From 1c7df74de5ac3ab71bb6efdd81fb1d4780f52941 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 12:50:52 +0300 Subject: [PATCH 01/18] ATA: get rid of x86_ata We'll be using our own implementation. --- Cargo.lock | 13 -- ableos/Cargo.toml | 1 - x86_ata/Cargo.toml | 25 --- x86_ata/src/lib.rs | 380 --------------------------------------------- 4 files changed, 419 deletions(-) delete mode 100644 x86_ata/Cargo.toml delete mode 100644 x86_ata/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d6861c6a..a19f7b10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,6 @@ dependencies = [ "wasmi", "watson", "x86_64", - "x86_ata", "y-compositor-protocol", ] @@ -879,18 +878,6 @@ dependencies = [ "volatile 0.4.5", ] -[[package]] -name = "x86_ata" -version = "0.1.0" -dependencies = [ - "bit_field", - "lazy_static", - "log", - "serde", - "spin 0.9.4", - "x86_64", -] - [[package]] name = "y-compositor-protocol" version = "0.1.1" diff --git a/ableos/Cargo.toml b/ableos/Cargo.toml index a50c735c..deca9cfa 100644 --- a/ableos/Cargo.toml +++ b/ableos/Cargo.toml @@ -148,7 +148,6 @@ git = "https://git.ablecorp.us:443/able/externc-libm.git" riscv = "*" [target.'cfg(target_arch = "x86_64")'.dependencies] -x86_ata = { path = "../x86_ata" } bootloader = { version = "0.9.8", features = ["map_physical_memory"] } cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" } pic8259 = "0.10.1" diff --git a/x86_ata/Cargo.toml b/x86_ata/Cargo.toml deleted file mode 100644 index 342b7d35..00000000 --- a/x86_ata/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "x86_ata" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -log = "*" -[dependencies.bit_field] -version = "0.10.0" - -[dependencies.lazy_static] -features = ["spin_no_std"] -version = "1.4.0" - -[dependencies.serde] -default-features = false -version = "1.0.126" - -[dependencies.spin] -version = "0.9.0" - -[dependencies.x86_64] -version = "0.14.3" diff --git a/x86_ata/src/lib.rs b/x86_ata/src/lib.rs deleted file mode 100644 index b2e760f4..00000000 --- a/x86_ata/src/lib.rs +++ /dev/null @@ -1,380 +0,0 @@ -#![no_std] - -/// Implementation Courtesy of MOROS. -/// Currently Only Supports ATA-PIO, with 24-bit LBA Addressing. -extern crate alloc; - -use alloc::string::String; -use alloc::vec::Vec; -use bit_field::BitField; -use core::hint::spin_loop; -use lazy_static::lazy_static; -use log::trace; -use spin::Mutex; -use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly}; - -pub type BlockIndex = u32; - -pub const ATA_BLOCK_SIZE: usize = 512; - -fn sleep_ticks(ticks: usize) { - for _ in 0..=ticks { - x86_64::instructions::hlt(); - } -} - -#[repr(u16)] -enum Command { - Read = 0x20, - Write = 0x30, - Identify = 0xEC, -} - -#[allow(dead_code)] -#[repr(usize)] -enum Status { - ERR = 0, - IDX = 1, - CORR = 2, - DRQ = 3, - SRV = 4, - DF = 5, - RDY = 6, - BSY = 7, -} - -#[allow(dead_code)] -#[derive(Debug, Clone)] -pub struct Bus { - id: u8, - irq: u8, - - data_register: Port, - error_register: PortReadOnly, - features_register: PortWriteOnly, - sector_count_register: Port, - lba0_register: Port, - lba1_register: Port, - lba2_register: Port, - drive_register: Port, - status_register: PortReadOnly, - command_register: PortWriteOnly, - - alternate_status_register: PortReadOnly, - control_register: PortWriteOnly, - drive_blockess_register: PortReadOnly, -} - -impl Bus { - pub fn new(id: u8, io_base: u16, ctrl_base: u16, irq: u8) -> Self { - Self { - id, - irq, - - data_register: Port::new(io_base), - error_register: PortReadOnly::new(io_base + 1), - features_register: PortWriteOnly::new(io_base + 1), - sector_count_register: Port::new(io_base + 2), - lba0_register: Port::new(io_base + 3), - lba1_register: Port::new(io_base + 4), - lba2_register: Port::new(io_base + 5), - drive_register: Port::new(io_base + 6), - status_register: PortReadOnly::new(io_base + 7), - command_register: PortWriteOnly::new(io_base + 7), - - alternate_status_register: PortReadOnly::new(ctrl_base), - control_register: PortWriteOnly::new(ctrl_base), - drive_blockess_register: PortReadOnly::new(ctrl_base + 1), - } - } - - fn reset(&mut self) { - unsafe { - self.control_register.write(4); // Set SRST bit - sleep_ticks(2); - self.control_register.write(0); // Then clear it - sleep_ticks(2); - } - } - - fn wait(&mut self) { - for _ in 0..4 { - // Wait about 4 x 100 ns - unsafe { - self.alternate_status_register.read(); - } - } - } - - fn write_command(&mut self, cmd: Command) { - unsafe { - self.command_register.write(cmd as u8); - } - } - - fn status(&mut self) -> u8 { - unsafe { self.status_register.read() } - } - - fn lba1(&mut self) -> u8 { - unsafe { self.lba1_register.read() } - } - - fn lba2(&mut self) -> u8 { - unsafe { self.lba2_register.read() } - } - - fn read_data(&mut self) -> u16 { - unsafe { self.data_register.read() } - } - - fn write_data(&mut self, data: u16) { - unsafe { self.data_register.write(data) } - } - - fn busy_loop(&mut self) { - self.wait(); - let start = 0; - while self.is_busy() { - if 0 - start > 1 { - // Hanged - return self.reset(); - } - - spin_loop(); - } - } - - fn is_busy(&mut self) -> bool { - self.status().get_bit(Status::BSY as usize) - } - - fn is_error(&mut self) -> bool { - self.status().get_bit(Status::ERR as usize) - } - - fn is_ready(&mut self) -> bool { - self.status().get_bit(Status::RDY as usize) - } - - fn select_drive(&mut self, drive: u8) { - // Drive #0 (primary) = 0xA0 - // Drive #1 (secondary) = 0xB0 - let drive_id = 0xA0 | (drive << 4); - unsafe { - self.drive_register.write(drive_id); - } - } - - fn setup(&mut self, drive: u8, block: u32) { - let drive_id = 0xE0 | (drive << 4); - unsafe { - self.drive_register - .write(drive_id | ((block.get_bits(24..28) as u8) & 0x0F)); - self.sector_count_register.write(1); - self.lba0_register.write(block.get_bits(0..8) as u8); - self.lba1_register.write(block.get_bits(8..16) as u8); - self.lba2_register.write(block.get_bits(16..24) as u8); - } - } - - pub fn identify_drive(&mut self, drive: u8) -> Option<[u16; 256]> { - self.reset(); - self.wait(); - self.select_drive(drive); - unsafe { - self.sector_count_register.write(0); - self.lba0_register.write(0); - self.lba1_register.write(0); - self.lba2_register.write(0); - } - - self.write_command(Command::Identify); - - if self.status() == 0 { - return None; - } - - self.busy_loop(); - - if self.lba1() != 0 || self.lba2() != 0 { - return None; - } - - for i in 0.. { - if i == 256 { - self.reset(); - return None; - } - if self.is_error() { - return None; - } - if self.is_ready() { - break; - } - } - - let mut res = [0; 256]; - for i in 0..256 { - res[i] = self.read_data(); - } - Some(res) - } - - /// Read A single, 512-byte long slice from a given block - /// panics if buf isn't EXACTLY 512 Bytes long; - /// Example: - /// ```rust - /// // Read A Single block from a disk - /// pub fn read_single() { - /// use x86_ata::{init, ATA_BLOCK_SIZE, read}; - /// // 1. Initialise ATA Subsystem. (Perform Once, on boot) - /// init().expect("Failed To Start ATA..."); - /// // 2. Create a temporary buffer of size 512. - /// let mut buffer: [u8;ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE]; - /// // 3. Pass the buffer over to the Subsystem, to be filled. - /// read(0, 0, 0, &mut buffer); - /// } - - pub fn read(&mut self, drive: u8, block: BlockIndex, buf: &mut [u8]) { - assert!(buf.len() == 512); - trace!("Reading Block 0x{:8X}", block); - // trace!("{:?}", self); - - self.setup(drive, block); - self.write_command(Command::Read); - self.busy_loop(); - for i in (0..256).step_by(2) { - let data = self.read_data(); - - //log!("Read[{:08X}][{:02X}]: 0x{:04X}\n", block, i, data); - buf[i] = data.get_bits(0..8) as u8; - buf[i + 1] = data.get_bits(8..16) as u8; - } - } - - /// Write A single, 512-byte long slice to a given block - /// panics if buf isn't EXACTLY 512 Bytes long; - /// Example: - /// ```rust - /// // Read A Single block from a disk - /// pub fn write_single() { - /// use x86_ata::{init, ATA_BLOCK_SIZE, write}; - /// // 1. Initialise ATA Subsystem. (Perform Once, on boot) - /// init().expect("Failed To Start ATA..."); - /// // 2. Create a temporary buffer of size 512. - /// let buffer: [u8;ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE]; - /// // 3. Pass the buffer over to the Subsystem, to be filled. - /// write(0, 0, 0, &buffer); - /// } - - pub fn write(&mut self, drive: u8, block: BlockIndex, buf: &[u8]) { - assert!(buf.len() == 512); - self.setup(drive, block); - self.write_command(Command::Write); - self.busy_loop(); - for i in 0..256 { - let mut data = 0_u16; - data.set_bits(0..8, buf[i * 2] as u16); - data.set_bits(8..16, buf[i * 2 + 1] as u16); - - //log!("Data: 0x{:04X} | {}{} \n", data, buf[i * 2] as char, buf[i * 2 + 1] as char); - - self.write_data(data); - } - self.busy_loop(); - } -} - -lazy_static! { - pub static ref BUSES: Mutex> = Mutex::new(Vec::new()); -} - -fn disk_size(sectors: u32) -> (u32, String) { - let bytes = sectors * 512; - if bytes >> 20 < 1000 { - (bytes >> 20, String::from("MB")) - } else { - (bytes >> 30, String::from("GB")) - } -} - -pub fn list() -> Vec<(u8, u8, String, String, u32, String, u32)> { - let mut buses = BUSES.lock(); - let mut res = Vec::new(); - for bus in 0..2 { - for drive in 0..2 { - if let Some(buf) = buses[bus as usize].identify_drive(drive) { - let mut serial = String::new(); - for i in 10..20 { - for &b in &buf[i].to_be_bytes() { - serial.push(b as char); - } - } - serial = serial.trim().into(); - let mut model = String::new(); - for i in 27..47 { - for &b in &buf[i].to_be_bytes() { - model.push(b as char); - } - } - model = model.trim().into(); - let sectors = (buf[61] as u32) << 16 | (buf[60] as u32); - let (size, unit) = disk_size(sectors); - res.push((bus, drive, model, serial, size, unit, sectors)); - } - } - } - res -} - -/// Identify a specific drive on a bus, format: (bus, drive, model, serial. size, unit, sectors) -pub fn indentify_drive(bus: u8, drive: u8) -> Option<(u8, u8, String, String, u32, String, u32)> { - let mut buses = BUSES.lock(); - if let Some(buf) = buses[bus as usize].identify_drive(drive) { - let mut serial = String::new(); - for i in 10..20 { - for &b in &buf[i].to_be_bytes() { - serial.push(b as char); - } - } - serial = serial.trim().into(); - let mut model = String::new(); - for i in 27..47 { - for &b in &buf[i].to_be_bytes() { - model.push(b as char); - } - } - model = model.trim().into(); - let sectors = (buf[61] as u32) << 16 | (buf[60] as u32); - let (size, unit) = disk_size(sectors); - Some((bus, drive, model, serial, size, unit, sectors)) - } else { - None - } -} - -pub fn read(bus: u8, drive: u8, block: BlockIndex, buf: &mut [u8]) { - let mut buses = BUSES.lock(); - trace!("Reading Block 0x{:08X}\n", block); - buses[bus as usize].read(drive, block, buf); -} - -pub fn write(bus: u8, drive: u8, block: BlockIndex, buf: &[u8]) { - let mut buses = BUSES.lock(); - //log!("Writing Block 0x{:08X}\n", block); - buses[bus as usize].write(drive, block, buf); -} - -pub fn drive_is_present(bus: usize) -> bool { - unsafe { BUSES.lock()[bus].status_register.read() != 0xFF } -} - -pub fn init() -> Result<(), ()> { - { - let mut buses = BUSES.lock(); - buses.push(Bus::new(0, 0x1F0, 0x3F6, 14)); - buses.push(Bus::new(1, 0x170, 0x376, 15)); - } - Ok(()) -} From 6265560ccf21504e73e2113579bf08b6984b698e Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 13:02:57 +0300 Subject: [PATCH 02/18] ATA: configure qemu to boot from an IDE drive --- ableos/Cargo.toml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ableos/Cargo.toml b/ableos/Cargo.toml index deca9cfa..f8b2669a 100644 --- a/ableos/Cargo.toml +++ b/ableos/Cargo.toml @@ -8,6 +8,18 @@ version = "0.1.1" panic = "abort" [package.metadata.bootimage] +run-command = [ + "qemu-system-x86_64", + + "-device", + "piix4-ide,id=ide", + + "-drive", + "file={},format=raw,if=none,id=disk", + + "-device", + "ide-hd,drive=disk,bus=ide.0" +] run-args = [ # "--nodefaults", "-cpu", @@ -38,14 +50,8 @@ run-args = [ # "-machine", "pcspk-audiodev=0", - - "-hdb", - "../userland/root_fs/ext2.img", - - # "-qmp", # "unix:../qmp-sock,server,nowait", - ] test-args = [ From bc1a0a721fd6fc979410dd981c30ec834e8bac85 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 13:36:39 +0300 Subject: [PATCH 03/18] PCI: revision id, programming interface byte and device ID --- ableos/src/devices/pci/mod.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index 1afb0c27..5b7c1c45 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -32,6 +32,8 @@ pub struct PciDeviceInfo { pub bus: u8, pub device_id: DeviceID, pub full_class: PciFullClass, + pub prog_if: u8, + pub rev_id: u8, pub header_type: u8, pub bars: [u32; 6], pub supported_fns: [bool; 8], @@ -51,13 +53,16 @@ impl PciDeviceInfo { impl Display for PciDeviceInfo { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { let vendor_name = &self.device_id.vendor; + let device_id = &self.device_id.id; writeln!( f, - "Device {} | Bus {:X} | Vendor: {}", - self.device, self.bus, vendor_name + "Device: {} | Bus: 0x{:X} | Vendor: {} | Device ID: 0x{:X}", + self.device, self.bus, vendor_name, device_id, )?; writeln!(f, "{}", self.full_class)?; - writeln!(f, " Header type: {:X}", self.header_type)?; + writeln!(f, " Revision ID: {}", self.rev_id)?; + writeln!(f, " Prog IF: 0b{:b}", self.prog_if)?; + writeln!(f, " Header type: 0x{:X}", self.header_type)?; write!(f, " Supported functions: 0")?; for (i, b) in self.supported_fns.iter().enumerate().skip(1) { if *b { @@ -110,9 +115,11 @@ fn check_device(bus: u8, device: u8) -> Option { return None; } - let class = unsafe { pci_config_read(bus, device, 0, 0x8) }; - let class = (class >> 16) & 0x0000FFFF; - let pci_class = PciFullClass::from_u16(class as u16); + let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) }; + let rev_id = (reg2 & 0x000000FF) as u8; + let prog_if = ((reg2 >> 8) & 0x000000FF) as u8; + let class = ((reg2 >> 16) & 0x0000FFFF) as u16; + let pci_class = PciFullClass::from_u16(class); let header_type = get_header_type(bus, device, function); let mut supported_fns = [true, false, false, false, false, false, false, false]; @@ -148,6 +155,8 @@ fn check_device(bus: u8, device: u8) -> Option { }, // vendor_id, full_class: pci_class, + prog_if, + rev_id, header_type, bars, supported_fns, From 8c1f80b7e693663d16d20f9a1caad2cc8513da22 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 14:09:01 +0300 Subject: [PATCH 04/18] PCI: add INTEL_PIIX4_IDE device --- ableos/src/devices/pci/devices.rs | 10 +++++++++- ableos/src/devices/pci/support.rs | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ableos/src/devices/pci/devices.rs b/ableos/src/devices/pci/devices.rs index a10f97f4..7f4a7a54 100644 --- a/ableos/src/devices/pci/devices.rs +++ b/ableos/src/devices/pci/devices.rs @@ -5,16 +5,24 @@ */ use super::vendors::Vendor::{self, *}; + #[derive(PartialEq, Clone, Eq, Debug)] pub struct DeviceID { pub vendor: Vendor, pub id: u16, } + impl DeviceID { pub const fn new(vendor: Vendor, id: u16) -> Self { Self { vendor, id } } } -pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMware, 0x0405); +// FIXME: Unknown class pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); + +// MassStorage_IDE (0x0101) +pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(Intel, 0x7111); + +// Display_VGA (0x0300) +pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMware, 0x0405); diff --git a/ableos/src/devices/pci/support.rs b/ableos/src/devices/pci/support.rs index 793074f9..f9c0df6b 100644 --- a/ableos/src/devices/pci/support.rs +++ b/ableos/src/devices/pci/support.rs @@ -8,8 +8,14 @@ use super::devices::*; pub fn check_pci_support(device_id: DeviceID) -> bool { match device_id { - VMWARE_SVGA2 => true, + // FIXME: Unknown class S3INC_TRIO64V2 => true, + + // MassStorage_IDE (0x0101) + INTEL_PIIX4_IDE => true, + + // Display_VGA (0x0300) + VMWARE_SVGA2 => true, _ => false, } } From 272cf525affa2fd391709d7e10b5e9e44811439a Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 20:07:43 +0300 Subject: [PATCH 05/18] Devices: Add block devices --- ableos/src/devices/character_devs/dev_null.rs | 2 +- ableos/src/devices/character_devs/dev_unicode.rs | 2 +- ableos/src/devices/character_devs/dev_zero.rs | 2 +- ableos/src/devices/character_devs/mod.rs | 2 +- ableos/src/devices/dev_vterm.rs | 2 +- ableos/src/devices/mod.rs | 3 ++- ableos/src/driver_traits/serial.rs | 2 +- ableos/src/stdio.rs | 6 ++++-- kernel/src/device_interface/block.rs | 6 ++++++ kernel/src/device_interface/block/mod.rs | 1 - kernel/src/device_interface/mod.rs | 7 +++++-- 11 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 kernel/src/device_interface/block.rs delete mode 100644 kernel/src/device_interface/block/mod.rs diff --git a/ableos/src/devices/character_devs/dev_null.rs b/ableos/src/devices/character_devs/dev_null.rs index eef0d3bb..7688875f 100644 --- a/ableos/src/devices/character_devs/dev_null.rs +++ b/ableos/src/devices/character_devs/dev_null.rs @@ -1,4 +1,4 @@ -use kernel::device_interface::character::CharacterDevice; +use kernel::device_interface::CharacterDevice; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DevNull; diff --git a/ableos/src/devices/character_devs/dev_unicode.rs b/ableos/src/devices/character_devs/dev_unicode.rs index 839c1b79..995e0375 100644 --- a/ableos/src/devices/character_devs/dev_unicode.rs +++ b/ableos/src/devices/character_devs/dev_unicode.rs @@ -1,4 +1,4 @@ -use kernel::device_interface::character::CharacterDevice; +use kernel::device_interface::CharacterDevice; #[derive(Debug)] pub struct DevUnicode { diff --git a/ableos/src/devices/character_devs/dev_zero.rs b/ableos/src/devices/character_devs/dev_zero.rs index ad26d1d8..07508b51 100644 --- a/ableos/src/devices/character_devs/dev_zero.rs +++ b/ableos/src/devices/character_devs/dev_zero.rs @@ -1,4 +1,4 @@ -use kernel::device_interface::character::CharacterDevice; +use kernel::device_interface::CharacterDevice; #[derive(Debug)] pub struct DevZero; diff --git a/ableos/src/devices/character_devs/mod.rs b/ableos/src/devices/character_devs/mod.rs index 9a2f2948..f63a0640 100644 --- a/ableos/src/devices/character_devs/mod.rs +++ b/ableos/src/devices/character_devs/mod.rs @@ -2,4 +2,4 @@ pub mod dev_null; pub mod dev_unicode; pub mod dev_zero; -pub use kernel::device_interface::character::CharacterDevice; +pub use kernel::device_interface::CharacterDevice; diff --git a/ableos/src/devices/dev_vterm.rs b/ableos/src/devices/dev_vterm.rs index 8ea16546..e807cb46 100644 --- a/ableos/src/devices/dev_vterm.rs +++ b/ableos/src/devices/dev_vterm.rs @@ -3,7 +3,7 @@ use core::ops::Not; use core::sync::atomic::AtomicU32; use core::sync::atomic::Ordering; -use kernel::device_interface::character::CharacterDevice; +use kernel::device_interface::CharacterDevice; use crate::pixel_format::Rgba64; diff --git a/ableos/src/devices/mod.rs b/ableos/src/devices/mod.rs index 2e618d07..52758fbf 100644 --- a/ableos/src/devices/mod.rs +++ b/ableos/src/devices/mod.rs @@ -10,7 +10,7 @@ pub use self::Device::*; use crate::devices::dev_vterm::VTerm; use character_devs::{dev_null::DevNull, dev_unicode::DevUnicode, dev_zero::DevZero}; use hashbrown::HashMap; -use kernel::device_interface::character::CharacterDevice; +use kernel::device_interface::{BlockDevice, CharacterDevice}; use spin::Lazy; pub static DEVICE_TABLE: Lazy> = @@ -19,6 +19,7 @@ pub static DEVICE_TABLE: Lazy> = // FIXME: This is a hack to hold a device. // #[derive(Debug)] pub enum Device { + Block(Box), Character(Box), Vterm(Box), } diff --git a/ableos/src/driver_traits/serial.rs b/ableos/src/driver_traits/serial.rs index 8e7aa15f..118f32f0 100644 --- a/ableos/src/driver_traits/serial.rs +++ b/ableos/src/driver_traits/serial.rs @@ -1,4 +1,4 @@ -use kernel::device_interface::character::CharacterDevice; +use kernel::device_interface::CharacterDevice; pub struct Serial { pub base: usize, diff --git a/ableos/src/stdio.rs b/ableos/src/stdio.rs index b69b2eaf..c5b127d3 100644 --- a/ableos/src/stdio.rs +++ b/ableos/src/stdio.rs @@ -1,7 +1,7 @@ use { - crate::devices::Device::{Character, Vterm}, + crate::devices::Device::{Block, Character, Vterm}, core::fmt::{Arguments, Error, Write}, - kernel::device_interface::character::CharacterDevice, + kernel::device_interface::CharacterDevice, }; #[derive(Debug, Clone)] @@ -35,6 +35,7 @@ impl StdIo { } Ok(()) } + Block(_) => todo!(), } } @@ -54,6 +55,7 @@ impl StdIo { vterm.read_char().map(|c| buf.push(c)); println!("{}", buf); } + Block(_) => todo!(), } } } diff --git a/kernel/src/device_interface/block.rs b/kernel/src/device_interface/block.rs new file mode 100644 index 00000000..9a24cc37 --- /dev/null +++ b/kernel/src/device_interface/block.rs @@ -0,0 +1,6 @@ +//! Block device interface + +/// Block device interface +pub trait BlockDevice { + // TODO +} diff --git a/kernel/src/device_interface/block/mod.rs b/kernel/src/device_interface/block/mod.rs deleted file mode 100644 index 9d0f028e..00000000 --- a/kernel/src/device_interface/block/mod.rs +++ /dev/null @@ -1 +0,0 @@ -//! diff --git a/kernel/src/device_interface/mod.rs b/kernel/src/device_interface/mod.rs index 7fe7faaf..5306d1b4 100644 --- a/kernel/src/device_interface/mod.rs +++ b/kernel/src/device_interface/mod.rs @@ -1,4 +1,7 @@ //! Platform Agnostic Device -pub mod block; -pub mod character; +mod block; +mod character; + +pub use block::BlockDevice; +pub use character::CharacterDevice; From daea5b01836d848f3dd804b05a6263740dece052 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 21:39:02 +0300 Subject: [PATCH 06/18] PCI: add PIIX3_IDE to supported devices PIIX4_IDE and PIIX3_IDE are similar enough that we can have one driver for both. --- ableos/src/devices/pci/devices.rs | 1 + ableos/src/devices/pci/support.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/ableos/src/devices/pci/devices.rs b/ableos/src/devices/pci/devices.rs index 7f4a7a54..9af2c944 100644 --- a/ableos/src/devices/pci/devices.rs +++ b/ableos/src/devices/pci/devices.rs @@ -22,6 +22,7 @@ impl DeviceID { pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); // MassStorage_IDE (0x0101) +pub const INTEL_PIIX3_IDE: DeviceID = DeviceID::new(Intel, 0x7010); pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(Intel, 0x7111); // Display_VGA (0x0300) diff --git a/ableos/src/devices/pci/support.rs b/ableos/src/devices/pci/support.rs index f9c0df6b..7cbb651e 100644 --- a/ableos/src/devices/pci/support.rs +++ b/ableos/src/devices/pci/support.rs @@ -12,6 +12,7 @@ pub fn check_pci_support(device_id: DeviceID) -> bool { S3INC_TRIO64V2 => true, // MassStorage_IDE (0x0101) + INTEL_PIIX3_IDE => true, INTEL_PIIX4_IDE => true, // Display_VGA (0x0300) From 641d1542191c5584f25bcf45dc104913fb3ac527 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 8 Aug 2022 22:55:28 +0300 Subject: [PATCH 07/18] allocate DMA frame --- ableos/src/arch/x86_64/mod.rs | 2 +- ableos/src/devices/pci/mod.rs | 3 ++ ableos/src/devices/pci/piix.rs | 80 ++++++++++++++++++++++++++++++++++ ableos/src/kmain.rs | 14 +++++- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 ableos/src/devices/pci/piix.rs diff --git a/ableos/src/arch/x86_64/mod.rs b/ableos/src/arch/x86_64/mod.rs index ce008fa9..d2680fa0 100644 --- a/ableos/src/arch/x86_64/mod.rs +++ b/ableos/src/arch/x86_64/mod.rs @@ -34,7 +34,7 @@ pub fn start(boot_info: &'static BootInfo) -> ! { allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); - crate::kmain::kernel_main(); + crate::kmain::kernel_main(mapper, frame_allocator); } #[allow(unused)] diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index 5b7c1c45..c97b349e 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -19,6 +19,9 @@ pub use enums::*; pub mod port; use port::*; +// MassStorage_IDE (0x0101) +pub mod piix; + use self::devices::DeviceID; // PciDeviceInfo /////////////////////////////////////////////////////////////// diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix.rs new file mode 100644 index 00000000..416aa329 --- /dev/null +++ b/ableos/src/devices/pci/piix.rs @@ -0,0 +1,80 @@ +// FIXME: platform agnostic paging stuff +use x86_64::structures::paging::{PhysFrame, FrameAllocator, Size4KiB, mapper::MapToError, Mapper, Page}; +use x86_64::VirtAddr; + +use super::{PciDeviceInfo, check_device}; + +const PRDT_START: u64 = 0x_ffff_ffff_0000_0000; + +pub struct Piix { + device_info: PciDeviceInfo, + prdt_frame: Option, +} + +impl Piix { + pub fn new(bus: u8, device: u8) -> Option { + let device_info = check_device(bus, device)?; + trace!("device_info: {device_info}"); + + Some(Self { + device_info, + prdt_frame: None, + }) + } + + pub fn allocate_dma_frame( + &mut self, + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, + ) -> Result<(), MapToError> { + use x86_64::structures::paging::PageTableFlags as Flags; + + let prdt_frame = frame_allocator.allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + let flags = Flags::NO_CACHE | Flags::PRESENT | Flags::WRITABLE; + + unsafe { + mapper.map_to( + Page::containing_address(VirtAddr::new(PRDT_START)), + prdt_frame, + flags, + frame_allocator, + )?.flush() + } + + trace!("{prdt_frame:#?}"); + self.prdt_frame = Some(prdt_frame); + Ok(()) + } + + pub fn read(&self) { + // bus master interface base address + let bmiba = self.device_info.bars[4] as *mut BusMasterInterface; + // bmiba.bmidtpp = prdt; + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +struct BusMasterInterface { + /// Bus Master IDE Command (primary) + pub bmicp: u8, + /// Reserved + pub _0: u8, + /// Bus Master IDE Status (primary) + pub bmisp: u8, + /// Reserved + pub _1: u8, + /// Bus Master IDE Descriptor Table Pointer (primary) + pub bmidtpp: u32, + /// Bus Master IDE Command (secondary) + pub bmics: u8, + /// Reserved + pub _2: u8, + /// Bus Master IDE Status (secondary) + pub bmiss: u8, + /// Reserved + pub _3: u8, + /// Bus Master IDE Descriptor Table Pointer (secondary) + pub bmidtps: u32, +} diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index 0115208a..eea56b20 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -9,6 +9,7 @@ use core::sync::atomic::AtomicU64; use crate::arch::{drivers::sysinfo::master, init, sloop}; +use crate::devices::pci::piix::Piix; use crate::relib::network::socket::{SimpleSock, Socket}; use crate::{ boot_conf::KernelConfig, scratchpad, systeminfo::RELEASE_TYPE, TERM, @@ -17,12 +18,17 @@ use crate::{filesystem, hardware}; use kernel::KERNEL_VERSION; use spin::Lazy; +// FIXME: platform agnostic paging stuff +use x86_64::structures::paging::{Mapper, FrameAllocator, Size4KiB}; + // TODO: Change this structure to allow for multiple cores loaded pub static KERNEL_CONF: Lazy = Lazy::new(KernelConfig::new); /// The main entry point of the kernel -#[no_mangle] -pub fn kernel_main() -> ! { +pub fn kernel_main( + mut mapper: impl Mapper, + mut frame_allocator: impl FrameAllocator, +) -> ! { init::init(); // /* @@ -45,6 +51,10 @@ pub fn kernel_main() -> ! { filesystem::init().unwrap(); + // FIXME: unhardcode this and do device discovery + let mut piix = Piix::new(0, 3).unwrap(); + piix.allocate_dma_frame(&mut mapper, &mut frame_allocator).unwrap(); + /* // println!("abc"); From b65a3be19dc801aa9e775b1eef45f79f6c329644 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Tue, 9 Aug 2022 11:11:15 +0300 Subject: [PATCH 08/18] allocate 16 frames for DMA --- ableos/src/arch/x86_64/memory.rs | 8 ++++- ableos/src/devices/pci/piix.rs | 59 +++++++++++++++++++++++++++++--- ableos/src/kmain.rs | 5 +-- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/ableos/src/arch/x86_64/memory.rs b/ableos/src/arch/x86_64/memory.rs index 338daae0..35e4fbe2 100644 --- a/ableos/src/arch/x86_64/memory.rs +++ b/ableos/src/arch/x86_64/memory.rs @@ -1,7 +1,7 @@ use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; use x86_64::{ structures::paging::{ - FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, + FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, FrameDeallocator, }, PhysAddr, VirtAddr, }; @@ -109,3 +109,9 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { frame } } + +impl FrameDeallocator for BootInfoFrameAllocator { + unsafe fn deallocate_frame(&mut self, _frame: PhysFrame) { + // TODO + } +} diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix.rs index 416aa329..5793530d 100644 --- a/ableos/src/devices/pci/piix.rs +++ b/ableos/src/devices/pci/piix.rs @@ -1,14 +1,19 @@ +use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; // FIXME: platform agnostic paging stuff -use x86_64::structures::paging::{PhysFrame, FrameAllocator, Size4KiB, mapper::MapToError, Mapper, Page}; +use x86_64::structures::paging::{PhysFrame, Size4KiB, mapper::MapToError, Mapper, Page}; use x86_64::VirtAddr; +use crate::arch::memory::BootInfoFrameAllocator; + use super::{PciDeviceInfo, check_device}; const PRDT_START: u64 = 0x_ffff_ffff_0000_0000; +const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000; pub struct Piix { device_info: PciDeviceInfo, prdt_frame: Option, + buffer_frames: Option>, } impl Piix { @@ -19,18 +24,41 @@ impl Piix { Some(Self { device_info, prdt_frame: None, + buffer_frames: None, }) } pub fn allocate_dma_frame( &mut self, mapper: &mut impl Mapper, - frame_allocator: &mut impl FrameAllocator, + frame_allocator: &mut BootInfoFrameAllocator, ) -> Result<(), MapToError> { use x86_64::structures::paging::PageTableFlags as Flags; let prdt_frame = frame_allocator.allocate_frame() .ok_or(MapToError::FrameAllocationFailed)?; + let buffer_frames = { + let mut frame = frame_allocator.allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + while !frame.start_address().is_aligned(0x10000u64) { + unsafe { + frame_allocator.deallocate_frame(frame); + } + + frame = frame_allocator.allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + } + + let mut frames = Vec::with_capacity(16); + frames.push(frame); + for _ in 0..15 { + let frame = frame_allocator.allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?;; + frames.push(frame); + } + + frames + }; let flags = Flags::NO_CACHE | Flags::PRESENT | Flags::WRITABLE; unsafe { @@ -39,11 +67,22 @@ impl Piix { prdt_frame, flags, frame_allocator, - )?.flush() + )?.flush(); + + for (i, frame) in buffer_frames.iter().enumerate() { + mapper.map_to( + Page::containing_address(VirtAddr::new(BUFFER_START + i as u64 * 0x1000)), + *frame, + flags, + frame_allocator, + )?.flush() + } } - trace!("{prdt_frame:#?}"); + trace!("prdt_frame: {prdt_frame:?}"); + trace!("buffer_frames: {buffer_frames:?}"); self.prdt_frame = Some(prdt_frame); + self.buffer_frames = Some(buffer_frames); Ok(()) } @@ -78,3 +117,15 @@ struct BusMasterInterface { /// Bus Master IDE Descriptor Table Pointer (secondary) pub bmidtps: u32, } + +#[repr(C, packed)] +struct PhysRegionDescriptor { + /// Pointer to the data buffer + pub data_buffer: u32, + /// Byte count, 64K maximum per PRD transfer + pub byte_count: u16, + /// Reserved byte + pub _0: u8, + /// MSB marks end of transfer + pub eot: u8, +} diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index eea56b20..ef24c9c9 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -8,6 +8,7 @@ use core::sync::atomic::AtomicU64; +use crate::arch::memory::BootInfoFrameAllocator; use crate::arch::{drivers::sysinfo::master, init, sloop}; use crate::devices::pci::piix::Piix; use crate::relib::network::socket::{SimpleSock, Socket}; @@ -19,7 +20,7 @@ use kernel::KERNEL_VERSION; use spin::Lazy; // FIXME: platform agnostic paging stuff -use x86_64::structures::paging::{Mapper, FrameAllocator, Size4KiB}; +use x86_64::structures::paging::{Mapper, Size4KiB}; // TODO: Change this structure to allow for multiple cores loaded pub static KERNEL_CONF: Lazy = Lazy::new(KernelConfig::new); @@ -27,7 +28,7 @@ pub static KERNEL_CONF: Lazy = Lazy::new(KernelConfig::new); /// The main entry point of the kernel pub fn kernel_main( mut mapper: impl Mapper, - mut frame_allocator: impl FrameAllocator, + mut frame_allocator: BootInfoFrameAllocator, ) -> ! { init::init(); From 8b105cb8a7fd66bf669b152c72f31a934b8b6bbf Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Tue, 9 Aug 2022 14:53:25 +0300 Subject: [PATCH 09/18] progress, i guess --- ableos/src/arch/x86_64/memory.rs | 3 +- ableos/src/devices/pci/piix.rs | 160 +++++++++++++++++++++---------- ableos/src/kmain.rs | 8 +- ableos/src/scratchpad.rs | 12 +-- 4 files changed, 118 insertions(+), 65 deletions(-) diff --git a/ableos/src/arch/x86_64/memory.rs b/ableos/src/arch/x86_64/memory.rs index 35e4fbe2..df43bb38 100644 --- a/ableos/src/arch/x86_64/memory.rs +++ b/ableos/src/arch/x86_64/memory.rs @@ -1,7 +1,8 @@ use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; use x86_64::{ structures::paging::{ - FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, FrameDeallocator, + FrameAllocator, FrameDeallocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, + Size4KiB, }, PhysAddr, VirtAddr, }; diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix.rs index 5793530d..1bf32e7b 100644 --- a/ableos/src/devices/pci/piix.rs +++ b/ableos/src/devices/pci/piix.rs @@ -1,30 +1,53 @@ +/* + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ + +use core::num::TryFromIntError; + use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; // FIXME: platform agnostic paging stuff -use x86_64::structures::paging::{PhysFrame, Size4KiB, mapper::MapToError, Mapper, Page}; +use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB}; use x86_64::VirtAddr; use crate::arch::memory::BootInfoFrameAllocator; -use super::{PciDeviceInfo, check_device}; +use super::port::Port; +use super::{check_device, PciDeviceInfo}; const PRDT_START: u64 = 0x_ffff_ffff_0000_0000; const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000; +/// Bus Master IDE Command +const BMIC_OFFSET: u16 = 0; +/// Bus Master IDE Status +const BMIS_OFFSET: u16 = 2; +/// Bus Master IDE Descriptor Table Pointer +const BMIDTP_OFFSET: u16 = 4; + +/// Bus Master IDE Secondary Offset +const BMI_SECONDARY: u16 = 8; + pub struct Piix { device_info: PciDeviceInfo, prdt_frame: Option, buffer_frames: Option>, + bmiba: u16, } impl Piix { + // FIXME: make this return a Result pub fn new(bus: u8, device: u8) -> Option { let device_info = check_device(bus, device)?; trace!("device_info: {device_info}"); + let bmiba = device_info.bars[4] & 0xFFFFFFFC; Some(Self { device_info, prdt_frame: None, buffer_frames: None, + bmiba: bmiba.try_into().ok()?, }) } @@ -35,25 +58,29 @@ impl Piix { ) -> Result<(), MapToError> { use x86_64::structures::paging::PageTableFlags as Flags; - let prdt_frame = frame_allocator.allocate_frame() + let prdt_frame = frame_allocator + .allocate_frame() .ok_or(MapToError::FrameAllocationFailed)?; let buffer_frames = { - let mut frame = frame_allocator.allocate_frame() + let mut frame = frame_allocator + .allocate_frame() .ok_or(MapToError::FrameAllocationFailed)?; while !frame.start_address().is_aligned(0x10000u64) { unsafe { frame_allocator.deallocate_frame(frame); } - frame = frame_allocator.allocate_frame() + frame = frame_allocator + .allocate_frame() .ok_or(MapToError::FrameAllocationFailed)?; } let mut frames = Vec::with_capacity(16); frames.push(frame); for _ in 0..15 { - let frame = frame_allocator.allocate_frame() - .ok_or(MapToError::FrameAllocationFailed)?;; + let frame = frame_allocator + .allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; frames.push(frame); } @@ -62,67 +89,98 @@ impl Piix { let flags = Flags::NO_CACHE | Flags::PRESENT | Flags::WRITABLE; unsafe { - mapper.map_to( - Page::containing_address(VirtAddr::new(PRDT_START)), - prdt_frame, - flags, - frame_allocator, - )?.flush(); - - for (i, frame) in buffer_frames.iter().enumerate() { - mapper.map_to( - Page::containing_address(VirtAddr::new(BUFFER_START + i as u64 * 0x1000)), - *frame, + mapper + .map_to( + Page::containing_address(VirtAddr::new(PRDT_START)), + prdt_frame, flags, frame_allocator, - )?.flush() + )? + .flush(); + + for (i, frame) in buffer_frames.iter().enumerate() { + mapper + .map_to( + Page::containing_address(VirtAddr::new(BUFFER_START + i as u64 * 0x1000)), + *frame, + flags, + frame_allocator, + )? + .flush() } } - trace!("prdt_frame: {prdt_frame:?}"); - trace!("buffer_frames: {buffer_frames:?}"); self.prdt_frame = Some(prdt_frame); self.buffer_frames = Some(buffer_frames); Ok(()) } - pub fn read(&self) { - // bus master interface base address - let bmiba = self.device_info.bars[4] as *mut BusMasterInterface; - // bmiba.bmidtpp = prdt; - } -} + pub fn read(&self) -> Result<(), TryFromIntError> { + // prepare PRD table + let prd = PRDT_START as *mut PhysRegionDescriptor; + unsafe { + (*prd).data_buffer = self.buffer_frames.as_ref().unwrap()[0] + .start_address() + .as_u64() + .try_into()?; + // we want to read 512 bytes + (*prd).byte_count = 512; + // this is the end of table + (*prd).eot = 1 << 7; + } -#[derive(Copy, Clone, Debug)] -#[repr(C, packed)] -struct BusMasterInterface { - /// Bus Master IDE Command (primary) - pub bmicp: u8, - /// Reserved - pub _0: u8, - /// Bus Master IDE Status (primary) - pub bmisp: u8, - /// Reserved - pub _1: u8, - /// Bus Master IDE Descriptor Table Pointer (primary) - pub bmidtpp: u32, - /// Bus Master IDE Command (secondary) - pub bmics: u8, - /// Reserved - pub _2: u8, - /// Bus Master IDE Status (secondary) - pub bmiss: u8, - /// Reserved - pub _3: u8, - /// Bus Master IDE Descriptor Table Pointer (secondary) - pub bmidtps: u32, + unsafe { + self.stop(false); + self.set_read(false); + self.clear_status(false); + // (*bmiba).bmidtpp = self.prdt_frame.unwrap().start_address().as_u64().try_into()?; + } + + Ok(()) + } + + unsafe fn stop(&self, secondary: bool) { + let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIC_OFFSET; + let mut bmic = Port::::new(addr).read(); + // stop ongoing transfer + bmic &= !1; + // write the new bmic + Port::::new(addr).write(bmic); + } + + unsafe fn set_read(&self, secondary: bool) { + let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIC_OFFSET; + let mut bmic = Port::::new(addr).read(); + // mark bit 3 as 0 (read) + bmic &= !(1 << 3); + // write the new bmic + Port::::new(addr).write(bmic); + } + + unsafe fn set_write(&self, secondary: bool) { + let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIC_OFFSET; + let mut bmic = Port::::new(addr).read(); + // mark bit 3 as 1 (write) + bmic |= 1 << 3; + // write the new bmic + Port::::new(addr).write(bmic); + } + + unsafe fn clear_status(&self, secondary: bool) { + let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIS_OFFSET; + let mut bmis = Port::::new(addr).read(); + // write 1 to bits 1 (DMA error) and 2 (int status) which clears them + bmis |= 1 << 1 | 1 << 2; + // write the new bmis + Port::::new(addr).write(bmis); + } } #[repr(C, packed)] struct PhysRegionDescriptor { /// Pointer to the data buffer pub data_buffer: u32, - /// Byte count, 64K maximum per PRD transfer + /// Byte count, 64K maximum per PRD transfer. 0 means 64K pub byte_count: u16, /// Reserved byte pub _0: u8, diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index ef24c9c9..0a2ac2e8 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -12,9 +12,7 @@ use crate::arch::memory::BootInfoFrameAllocator; use crate::arch::{drivers::sysinfo::master, init, sloop}; use crate::devices::pci::piix::Piix; use crate::relib::network::socket::{SimpleSock, Socket}; -use crate::{ - boot_conf::KernelConfig, scratchpad, systeminfo::RELEASE_TYPE, TERM, -}; +use crate::{boot_conf::KernelConfig, scratchpad, systeminfo::RELEASE_TYPE, TERM}; use crate::{filesystem, hardware}; use kernel::KERNEL_VERSION; use spin::Lazy; @@ -54,7 +52,9 @@ pub fn kernel_main( // FIXME: unhardcode this and do device discovery let mut piix = Piix::new(0, 3).unwrap(); - piix.allocate_dma_frame(&mut mapper, &mut frame_allocator).unwrap(); + piix.allocate_dma_frame(&mut mapper, &mut frame_allocator) + .unwrap(); + piix.read().unwrap(); /* diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 2ce80e70..045289f5 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -12,11 +12,7 @@ use crate::filesystem::vfs::VFS; use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE}; use crate::time::fetch_time; use crate::{ - arch::shutdown, - rhai_shell::KEYBUFF, - vterm::VTerm, - KERNEL_STATE, - wasm_jumploader::run_program, + arch::shutdown, rhai_shell::KEYBUFF, vterm::VTerm, wasm_jumploader::run_program, KERNEL_STATE, }; use acpi::{AcpiTables, PlatformInfo}; @@ -236,7 +232,7 @@ pub fn command_parser(user: String, command: String) { "echo" => match conf_args.1.arguments.get("p") { Some(path) => echo_file(path.to_string()), None => println!("No path provided"), - } + }, "test" => {} "quit" => shutdown(), "tree" => filesystem::tree("/").unwrap(), @@ -308,9 +304,7 @@ pub fn echo_file(path: String) { let mut current_path = String::from("/"); current_path.push_str(&path); let mut vfs = VFS.lock(); - let handle = vfs - .resolve(¤t_path) - .unwrap(); + let handle = vfs.resolve(¤t_path).unwrap(); let file = vfs.fs_node(handle).unwrap(); if file.is_dir() { From e9d58c67ad4f5e71cd972a1caecb3ecc76a2f87e Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Wed, 10 Aug 2022 14:00:56 +0300 Subject: [PATCH 10/18] ATA device detection --- ableos/src/devices/pci/mod.rs | 16 +++ ableos/src/devices/pci/piix.rs | 237 +++++++++++++++++++++++++++++---- 2 files changed, 229 insertions(+), 24 deletions(-) diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index c97b349e..08b6e2ff 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -35,6 +35,8 @@ pub struct PciDeviceInfo { pub bus: u8, pub device_id: DeviceID, pub full_class: PciFullClass, + pub command: u16, + pub status: u16, pub prog_if: u8, pub rev_id: u8, pub header_type: u8, @@ -52,6 +54,10 @@ impl PciDeviceInfo { pub fn subclass(&self) -> PciClass { PciClass::from_u8((self.full_class.as_u16() & 0xFF) as u8) } + + pub unsafe fn config_read(&self, func: u8, offset: u8) -> u32 { + pci_config_read(self.bus, self.device, func, offset) + } } impl Display for PciDeviceInfo { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { @@ -63,6 +69,11 @@ impl Display for PciDeviceInfo { self.device, self.bus, vendor_name, device_id, )?; writeln!(f, "{}", self.full_class)?; + writeln!( + f, + " Command: {:b} | Status: {:b}", + self.command, self.status + )?; writeln!(f, " Revision ID: {}", self.rev_id)?; writeln!(f, " Prog IF: 0b{:b}", self.prog_if)?; writeln!(f, " Header type: 0x{:X}", self.header_type)?; @@ -118,7 +129,10 @@ fn check_device(bus: u8, device: u8) -> Option { return None; } + let reg1 = unsafe { pci_config_read(bus, device, 0, 0x4) }; let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) }; + let command = (reg1 & 0x0000FFFF) as u16; + let status = ((reg1 >> 16) & 0x0000FFFF) as u16; let rev_id = (reg2 & 0x000000FF) as u8; let prog_if = ((reg2 >> 8) & 0x000000FF) as u8; let class = ((reg2 >> 16) & 0x0000FFFF) as u16; @@ -158,6 +172,8 @@ fn check_device(bus: u8, device: u8) -> Option { }, // vendor_id, full_class: pci_class, + command, + status, prog_if, rev_id, header_type, diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix.rs index 1bf32e7b..606c58d6 100644 --- a/ableos/src/devices/pci/piix.rs +++ b/ableos/src/devices/pci/piix.rs @@ -13,8 +13,7 @@ use x86_64::VirtAddr; use crate::arch::memory::BootInfoFrameAllocator; -use super::port::Port; -use super::{check_device, PciDeviceInfo}; +use super::{check_device, port::Port}; const PRDT_START: u64 = 0x_ffff_ffff_0000_0000; const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000; @@ -29,8 +28,32 @@ const BMIDTP_OFFSET: u16 = 4; /// Bus Master IDE Secondary Offset const BMI_SECONDARY: u16 = 8; +/// Primary command block offset +const PRIMARY_COMMAND: u16 = 0x01F0; + +/// Secondary command block offset +const SECONDARY_COMMAND: u16 = 0x0170; + +/// Drive/Head register offset +const DRIVE_HEAD_OFFSET: u16 = 6; + +/// Command/status register offset +const COMMAND_STATUS_OFFSET: u16 = 7; + +/// Secondary control block offset +const SECONDARY_CONTROL: u16 = 0x0374; + +/// Primary control block offset +const PRIMARY_CONTROL: u16 = 0x03F4; + +/// Alternative status offset +const ALT_STATUS_OFFSET: u16 = 2; + +/// ATA identification command +const CMD_IDENTIFY: u8 = 0xEC; + pub struct Piix { - device_info: PciDeviceInfo, + ide_devices: Vec, prdt_frame: Option, buffer_frames: Option>, bmiba: u16, @@ -41,10 +64,55 @@ impl Piix { pub fn new(bus: u8, device: u8) -> Option { let device_info = check_device(bus, device)?; trace!("device_info: {device_info}"); + let idetim = unsafe { device_info.config_read(0, 0x40) }; + trace!("idetim: {idetim:b}"); + // FIXME: enable the right bits in idetim (and sidetim) to use fast timings + + let mut ide_devices = Vec::with_capacity(4); + for ch in 0..2 { + let channel = if ch == 0 { + Channel::Primary + } else { + Channel::Secondary + }; + 'drive: for dr in 0..2 { + let drive = if dr == 0 { Drive::Master } else { Drive::Slave }; + + unsafe { + select_drive(drive, channel); + let status = ata_send_command(CMD_IDENTIFY, channel); + if status == 0 { + continue; // If status = 0, no device + } + + loop { + let status = { + let addr = if channel.secondary() { + SECONDARY_COMMAND + } else { + PRIMARY_COMMAND + } + COMMAND_STATUS_OFFSET; + Port::::new(addr).read() + }; + + if status & 1 == 1 { + // if error (bit 0), device is not ATA + // FIXME: ATAPI devices + continue 'drive; + } + if !((status >> 7) & 1 == 1) && (status >> 3) & 1 == 1 { + // BSY cleared, DRQ set, everything is right + break; + } + } + } + } + } + let bmiba = device_info.bars[4] & 0xFFFFFFFC; Some(Self { - device_info, + ide_devices, prdt_frame: None, buffer_frames: None, bmiba: bmiba.try_into().ok()?, @@ -130,49 +198,170 @@ impl Piix { } unsafe { - self.stop(false); - self.set_read(false); - self.clear_status(false); - // (*bmiba).bmidtpp = self.prdt_frame.unwrap().start_address().as_u64().try_into()?; + self.load_prdt(Channel::Primary); + self.stop(Channel::Primary); + self.set_read(Channel::Primary); + self.clear_status(Channel::Primary); + select_drive(Drive::Master, Channel::Primary); } Ok(()) } - unsafe fn stop(&self, secondary: bool) { - let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIC_OFFSET; - let mut bmic = Port::::new(addr).read(); + unsafe fn load_prdt(&self, channel: Channel) { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIDTP_OFFSET; + Port::::new(addr).write( + self.prdt_frame + .unwrap() + .start_address() + .as_u64() + .try_into() + .unwrap(), + ); + } + + unsafe fn stop(&self, channel: Channel) { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIC_OFFSET; + let port: Port = Port::new(addr); + let mut bmic = port.read(); // stop ongoing transfer bmic &= !1; // write the new bmic - Port::::new(addr).write(bmic); + port.write(bmic); } - unsafe fn set_read(&self, secondary: bool) { - let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIC_OFFSET; - let mut bmic = Port::::new(addr).read(); + unsafe fn set_read(&self, channel: Channel) { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIC_OFFSET; + let port: Port = Port::new(addr); + let mut bmic = port.read(); // mark bit 3 as 0 (read) bmic &= !(1 << 3); // write the new bmic - Port::::new(addr).write(bmic); + port.write(bmic); } - unsafe fn set_write(&self, secondary: bool) { - let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIC_OFFSET; - let mut bmic = Port::::new(addr).read(); + unsafe fn set_write(&self, channel: Channel) { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIC_OFFSET; + let port: Port = Port::new(addr); + let mut bmic = port.read(); // mark bit 3 as 1 (write) bmic |= 1 << 3; // write the new bmic - Port::::new(addr).write(bmic); + port.write(bmic); } - unsafe fn clear_status(&self, secondary: bool) { - let addr = if secondary { BMI_SECONDARY } else { 0 } + self.bmiba + BMIS_OFFSET; - let mut bmis = Port::::new(addr).read(); + unsafe fn clear_status(&self, channel: Channel) { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIS_OFFSET; + let port: Port = Port::new(addr); + let mut bmis = port.read(); // write 1 to bits 1 (DMA error) and 2 (int status) which clears them bmis |= 1 << 1 | 1 << 2; // write the new bmis - Port::::new(addr).write(bmis); + port.write(bmis); + } +} + +unsafe fn select_drive(drive: Drive, channel: Channel) { + let addr = if channel.secondary() { + SECONDARY_COMMAND + } else { + PRIMARY_COMMAND + } + DRIVE_HEAD_OFFSET; + let port: Port = Port::new(addr); + let mut drive_command = port.read(); + if drive.slave() { + // mark bit 4 + drive_command |= 1 << 4; + } else { + // clear bit 4 + drive_command &= !(1 << 4); + } + // write the new drive/head register + port.write(drive_command); + ata_delay(channel); +} + +/// Send ATA command and read status afterwards +unsafe fn ata_send_command(command: u8, channel: Channel) -> u8 { + let addr = if channel.secondary() { + SECONDARY_COMMAND + } else { + PRIMARY_COMMAND + } + COMMAND_STATUS_OFFSET; + let port: Port = Port::new(addr); + port.write(command); + ata_delay(channel); + port.read() +} + +/// Read the alternate status register 14 times to create a ~420ns delay +unsafe fn ata_delay(channel: Channel) { + let addr = if channel.secondary() { + SECONDARY_CONTROL + } else { + PRIMARY_CONTROL + } + ALT_STATUS_OFFSET; + let port: Port = Port::new(addr); + for _ in 0..14 { + port.read(); + } +} + +struct IdeDevice { + pub channel: Channel, + pub drive: Drive, + pub signature: u16, + pub capabilities: u16, + pub command_sets: u32, + pub size: u64, +} + +#[derive(Copy, Clone, Debug)] +enum Channel { + Primary, + Secondary, +} + +impl Channel { + fn secondary(&self) -> bool { + matches!(self, Self::Secondary) + } +} + +#[derive(Copy, Clone, Debug)] +enum Drive { + Master, + Slave, +} + +impl Drive { + fn slave(&self) -> bool { + matches!(self, Self::Slave) } } From 54140d153f30ef97f6539dc536b00d28828de175 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Fri, 12 Aug 2022 12:19:08 +0300 Subject: [PATCH 11/18] IDE device discovery --- ableos/src/devices/pci/piix.rs | 67 ++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix.rs index 606c58d6..693fbcc8 100644 --- a/ableos/src/devices/pci/piix.rs +++ b/ableos/src/devices/pci/piix.rs @@ -6,6 +6,7 @@ use core::num::TryFromIntError; +use x86_64::instructions::interrupts; use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; // FIXME: platform agnostic paging stuff use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB}; @@ -34,6 +35,9 @@ const PRIMARY_COMMAND: u16 = 0x01F0; /// Secondary command block offset const SECONDARY_COMMAND: u16 = 0x0170; +/// Data register offset +const DATA_OFFSET: u16 = 0; + /// Drive/Head register offset const DRIVE_HEAD_OFFSET: u16 = 6; @@ -80,6 +84,7 @@ impl Piix { unsafe { select_drive(drive, channel); + // FIXME: clear sector count and lba0, lba1, lba2 registers let status = ata_send_command(CMD_IDENTIFY, channel); if status == 0 { continue; // If status = 0, no device @@ -105,6 +110,49 @@ impl Piix { break; } } + + // Read identification space of device + let addr = if channel.secondary() { + SECONDARY_COMMAND + } else { + PRIMARY_COMMAND + } + DATA_OFFSET; + let mut buffer = [0_u8; 512]; + read_dword_buffer(addr, buffer.as_mut_ptr() as *mut _, 128); + // for (i, byte) in buffer.iter().enumerate() { + // if byte.is_ascii() { + // trace!("byte {i}: {byte:b}, ascii: {}", *byte as char); + // } else { + // trace!("byte {i}: {byte:b}"); + // } + // } + + if buffer[99] & 1 != 1 { + // FIXME: PIO mode support + error!("IDE drive {channel:?}/{drive:?} does not support DMA"); + continue; + } + + if (buffer[167] >> 2) & 1 != 1 { + // FIXME: 24-bit LBA and CHS support + error!("IDE drive {channel:?}/{drive:?} does not support 48-bit LBA"); + } + + let size = buffer[200] as u64 + | (buffer[201] as u64) << 8 + | (buffer[202] as u64) << 16 + | (buffer[203] as u64) << 24 + | (buffer[204] as u64) << 32 + | (buffer[205] as u64) << 40 + | (buffer[206] as u64) << 48 + | (buffer[207] as u64) << 54; + trace!("IDE drive {channel:?}/{drive:?} has {size} sectors"); + + ide_devices.push(IdeDevice { + channel, + drive, + size, + }); } } } @@ -332,13 +380,24 @@ unsafe fn ata_delay(channel: Channel) { } } +unsafe fn read_dword_buffer(port: u16, buffer: *mut u32, mut count: u32) { + // FIXME: this assumes x86-64 + interrupts::without_interrupts(|| { + asm!(" + cld + repne + insd", + in("di") buffer, + in("dx") port, + inout("cx") count, + ) + }); +} + struct IdeDevice { pub channel: Channel, pub drive: Drive, - pub signature: u16, - pub capabilities: u16, - pub command_sets: u32, - pub size: u64, + pub size: u64, // in sectors } #[derive(Copy, Clone, Debug)] From 428a8e8b7312d0a7c856d64e223f7d911c6704e5 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Fri, 12 Aug 2022 16:40:23 +0300 Subject: [PATCH 12/18] PCI: a lot of refactoration --- ableos/src/arch/x86_64/interrupts.rs | 8 +- ableos/src/arch/x86_64/mod.rs | 8 +- ableos/src/devices/mod.rs | 1 - ableos/src/devices/pci/{enums.rs => class.rs} | 54 ++-- ableos/src/devices/pci/device.rs | 181 +++++++++++++ ableos/src/devices/pci/devices.rs | 29 --- ableos/src/devices/pci/mod.rs | 244 ++---------------- ableos/src/devices/pci/piix.rs | 22 +- ableos/src/devices/pci/port.rs | 72 ------ ableos/src/devices/pci/support.rs | 22 -- ableos/src/devices/pci/vendors.rs | 168 ++++++++++-- ableos/src/devices/pci_inner.rs | 56 ---- ableos/src/kmain.rs | 10 +- ableos/src/panic.rs | 8 +- ableos/src/scratchpad.rs | 4 - ableos/src/tests/mod.rs | 8 +- ableos/src/tests/old_tests.rs | 8 +- ableos/src/virtio/mod.rs | 2 +- repbuild/src/main.rs | 10 +- 19 files changed, 401 insertions(+), 514 deletions(-) rename ableos/src/devices/pci/{enums.rs => class.rs} (90%) create mode 100644 ableos/src/devices/pci/device.rs delete mode 100644 ableos/src/devices/pci/devices.rs delete mode 100644 ableos/src/devices/pci/port.rs delete mode 100644 ableos/src/devices/pci/support.rs delete mode 100644 ableos/src/devices/pci_inner.rs diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index 7ae3d3ec..a59384af 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -1,8 +1,8 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ use core::panic::PanicInfo; diff --git a/ableos/src/arch/x86_64/mod.rs b/ableos/src/arch/x86_64/mod.rs index d2680fa0..cabb6bbe 100644 --- a/ableos/src/arch/x86_64/mod.rs +++ b/ableos/src/arch/x86_64/mod.rs @@ -1,8 +1,8 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ pub mod drivers; pub mod gdt; diff --git a/ableos/src/devices/mod.rs b/ableos/src/devices/mod.rs index 52758fbf..ea102d6a 100644 --- a/ableos/src/devices/mod.rs +++ b/ableos/src/devices/mod.rs @@ -3,7 +3,6 @@ mod dev_vterm; pub mod id; pub mod pci; -pub mod pci_inner; pub use self::Device::*; diff --git a/ableos/src/devices/pci/enums.rs b/ableos/src/devices/pci/class.rs similarity index 90% rename from ableos/src/devices/pci/enums.rs rename to ableos/src/devices/pci/class.rs index 1c1fe671..5cbddbf9 100644 --- a/ableos/src/devices/pci/enums.rs +++ b/ableos/src/devices/pci/class.rs @@ -1,16 +1,16 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ use core::fmt::Display; -/// The major class specification for a PCI device. -#[allow(dead_code)] -#[derive(Debug, Clone, Copy, PartialEq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[allow(non_camel_case_types, dead_code)] +#[derive(Debug, Clone, Copy, PartialEq)] #[repr(C)] +/// Class specification for a PCI device pub enum PciClass { Unclassified = 0x00, MassStorage = 0x01, @@ -19,37 +19,28 @@ pub enum PciClass { Multimedia = 0x04, Memory = 0x05, Bridge = 0x06, - Other = 0xFF, -} -impl PciClass { - /// Convert a u8 into the corresponding PciClass - pub fn from_u8(n: u8) -> PciClass { - match n { - 0x00 => PciClass::Unclassified, - 0x01 => PciClass::MassStorage, - 0x02 => PciClass::Network, - 0x03 => PciClass::Display, - 0x04 => PciClass::Multimedia, - 0x05 => PciClass::Memory, - 0x06 => PciClass::Bridge, - _ => PciClass::Other, - } - } - /// Convert a PciClass to its u8 representation - pub fn as_u8(&self) -> u8 { - *self as u8 - } + Unknown = 0xFF, } + impl From for PciClass { /// Convert a u8 into the corresponding PciClass fn from(n: u8) -> Self { - Self::from_u8(n) + use PciClass::*; + match n { + 0x00 => Unclassified, + 0x01 => MassStorage, + 0x02 => Network, + 0x03 => Display, + 0x04 => Multimedia, + 0x05 => Memory, + 0x06 => Bridge, + _ => Unknown, + } } } #[allow(non_camel_case_types, dead_code)] #[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] /// Full class specification (type and subtype) for a PCI device. /// @@ -110,6 +101,7 @@ pub enum PciFullClass { Unknown = 0xFFFF, } + impl PciFullClass { // listen, i know this sucks, but i didn't want to include // `num`, `num-traits` and `num-derive` as dependencies for @@ -173,11 +165,13 @@ impl PciFullClass { _ => PciFullClass::Unknown, } } + /// Convert a PciFullClass to its u16 representation pub fn as_u16(&self) -> u16 { *self as u16 } } + impl From for PciFullClass { /// Convert a u16 into the corresponding PciFullClass fn from(n: u16) -> Self { diff --git a/ableos/src/devices/pci/device.rs b/ableos/src/devices/pci/device.rs new file mode 100644 index 00000000..1b4371c3 --- /dev/null +++ b/ableos/src/devices/pci/device.rs @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2022, able + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ + +use core::fmt; + +use x86_64::instructions::port::Port; + +use super::{vendors::Vendor::{self, *}, PciFullClass, PciClass}; + +// FIXME: Unknown class +pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); + +// MassStorage_IDE (0x0101) +pub const INTEL_PIIX3_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7010); +pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7111); + +// Display_VGA (0x0300) +pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMWareInc, 0x0405); + +#[derive(Clone, Debug)] +/// A struct containing info about a PCI device. +pub struct PciDeviceInfo { + pub header_type: u8, + pub device: u8, + pub bus: u8, + pub device_id: DeviceID, + pub full_class: PciFullClass, + pub rev_id: u8, +} + +impl PciDeviceInfo { + /// Get the class of the PCI device as a PciClass + pub fn class(&self) -> PciClass { + (((self.full_class.as_u16() >> 8) & 0xFF) as u8).into() + } + + /// Get the bar, 0-indexed + pub fn bar(&self, bar: u8) -> u32 { + assert!(bar < 6); + unsafe { + self.io_read(0, 0x10 + bar * 4) + } + } + + /// Get the interrupt pin + pub fn interrupt_pin(&self) -> u8 { + let last_row = unsafe { self.io_read(0, 0x3C) }; + ((last_row >> 8) & 0xFF) as u8 + } + + /// Read from IO space + pub unsafe fn io_read(&self, func: u8, offset: u8) -> u32 { + pci_io_read(self.bus, self.device, func, offset) + } +} + +impl fmt::Display for PciDeviceInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + let vendor_name = &self.device_id.vendor; + let device_id = &self.device_id.id; + writeln!( + f, + "Device: {} | Bus: 0x{:X} | Vendor: {} | Device ID: 0x{:X}", + self.device, self.bus, vendor_name, device_id, + )?; + writeln!(f, "{}", self.full_class)?; + writeln!(f, " Header type: 0x{:X}", self.header_type)?; + writeln!(f, " Revision ID: {}", self.rev_id)?; + // write!(f, " Supported functions: 0")?; + // for (i, b) in self.supported_fns.iter().enumerate().skip(1) { + // if *b { + // write!(f, ", {}", i)?; + // } + // } + // writeln!(f)?; + // write!(f, " BARs: [ ")?; + // for i in self.bars.iter() { + // if *i == 0 { + // write!(f, "0x0 ")?; + // } else { + // write!(f, "{:#010X} ", i)?; + // } + // } + // writeln!(f, "]")?; + // writeln!( + // f, + // " Interrupt line / pin: {} / {}", + // self.interrupt_line, self.interrupt_pin + // )?; + Ok(()) + } +} + +#[derive(PartialEq, Clone, Eq, Debug)] +pub struct DeviceID { + pub vendor: Vendor, + pub id: u16, +} + +impl DeviceID { + pub const fn new(vendor: Vendor, id: u16) -> Self { + Self { vendor, id } + } +} + +pub fn check_pci_support(device_id: DeviceID) -> bool { + match device_id { + // FIXME: Unknown class + S3INC_TRIO64V2 => true, + + // MassStorage_IDE (0x0101) + INTEL_PIIX3_IDE => true, + INTEL_PIIX4_IDE => true, + + // Display_VGA (0x0300) + VMWARE_SVGA2 => true, + _ => false, + } +} + +pub fn check_device(bus: u8, device: u8) -> Option { + assert!(device < 32); + let (device_id, vendor_id) = get_ids(bus, device, 0); + if vendor_id == 0xFFFF { + // Device doesn't exist + return None; + } + + let reg2 = unsafe { pci_io_read(bus, device, 0, 0x8) }; + let class = ((reg2 >> 16) & 0x0000FFFF) as u16; + let pci_class = PciFullClass::from_u16(class); + let header_type = get_header_type(bus, device, 0); + + Some(PciDeviceInfo { + header_type, + device, + bus, + device_id: DeviceID { + vendor: vendor_id.into(), + id: device_id, + }, + full_class: pci_class, + rev_id: (reg2 & 0x000000FF) as u8, + }) +} + +unsafe fn pci_io_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 { + let bus = bus as u32; + let device = device as u32; + let func = func as u32; + let offset = offset as u32; + // construct address param + let address = + ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32; + + // write address + Port::::new(0xCF8).write(address); + + // read data + Port::::new(0xCFC).read() +} + +fn get_header_type(bus: u8, device: u8, function: u8) -> u8 { + assert!(device < 32); + assert!(function < 8); + let res = unsafe { pci_io_read(bus, device, function, 0x0C) }; + ((res >> 16) & 0xFF) as u8 +} + +fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) { + assert!(device < 32); + assert!(function < 8); + let res = unsafe { pci_io_read(bus, device, function, 0) }; + let dev_id = ((res >> 16) & 0xFFFF) as u16; + let vnd_id = (res & 0xFFFF) as u16; + (dev_id, vnd_id) +} diff --git a/ableos/src/devices/pci/devices.rs b/ableos/src/devices/pci/devices.rs deleted file mode 100644 index 9af2c944..00000000 --- a/ableos/src/devices/pci/devices.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ - -use super::vendors::Vendor::{self, *}; - -#[derive(PartialEq, Clone, Eq, Debug)] -pub struct DeviceID { - pub vendor: Vendor, - pub id: u16, -} - -impl DeviceID { - pub const fn new(vendor: Vendor, id: u16) -> Self { - Self { vendor, id } - } -} - -// FIXME: Unknown class -pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); - -// MassStorage_IDE (0x0101) -pub const INTEL_PIIX3_IDE: DeviceID = DeviceID::new(Intel, 0x7010); -pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(Intel, 0x7111); - -// Display_VGA (0x0300) -pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMware, 0x0405); diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index 08b6e2ff..3338c2a3 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -1,240 +1,28 @@ -// The MIT License (MIT) -// Copyright (c) 2021 trashbyte -// See LICENSE.txt for full license +/* + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ -extern crate alloc; -use alloc::{format, string::String, vec::Vec}; -use core::fmt::{Display, Error, Formatter}; - -#[cfg(feature = "serde")] -#[macro_use] -extern crate serde; - -pub mod devices; -mod enums; -pub mod support; +pub mod class; +pub mod device; pub mod vendors; -pub use enums::*; - -pub mod port; -use port::*; // MassStorage_IDE (0x0101) pub mod piix; -use self::devices::DeviceID; +pub use class::*; +pub use device::*; -// PciDeviceInfo /////////////////////////////////////////////////////////////// - -#[allow(dead_code)] -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -/// A struct containing info about a PCI device. -pub struct PciDeviceInfo { - pub device: u8, - pub bus: u8, - pub device_id: DeviceID, - pub full_class: PciFullClass, - pub command: u16, - pub status: u16, - pub prog_if: u8, - pub rev_id: u8, - pub header_type: u8, - pub bars: [u32; 6], - pub supported_fns: [bool; 8], - pub interrupt_line: u8, - pub interrupt_pin: u8, -} -impl PciDeviceInfo { - /// Get the class of the PCI device as a PciClass - pub fn class(&self) -> PciClass { - PciClass::from_u8(((self.full_class.as_u16() >> 8) & 0xFF) as u8) - } - /// Get the full class of the PCI device as a PciFullClass - pub fn subclass(&self) -> PciClass { - PciClass::from_u8((self.full_class.as_u16() & 0xFF) as u8) - } - - pub unsafe fn config_read(&self, func: u8, offset: u8) -> u32 { - pci_config_read(self.bus, self.device, func, offset) - } -} -impl Display for PciDeviceInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { - let vendor_name = &self.device_id.vendor; - let device_id = &self.device_id.id; - writeln!( - f, - "Device: {} | Bus: 0x{:X} | Vendor: {} | Device ID: 0x{:X}", - self.device, self.bus, vendor_name, device_id, - )?; - writeln!(f, "{}", self.full_class)?; - writeln!( - f, - " Command: {:b} | Status: {:b}", - self.command, self.status - )?; - writeln!(f, " Revision ID: {}", self.rev_id)?; - writeln!(f, " Prog IF: 0b{:b}", self.prog_if)?; - writeln!(f, " Header type: 0x{:X}", self.header_type)?; - write!(f, " Supported functions: 0")?; - for (i, b) in self.supported_fns.iter().enumerate().skip(1) { - if *b { - write!(f, ", {}", i)?; - } - } - writeln!(f)?; - write!(f, " BARs: [ ")?; - for i in self.bars.iter() { - if *i == 0 { - write!(f, "0x0 ")?; - } else { - write!(f, "{:#010X} ", i)?; - } - } - writeln!(f, "]")?; - writeln!( - f, - " Interrupt line / pin: {} / {}", - self.interrupt_line, self.interrupt_pin - )?; - Ok(()) - } -} - -// Public functions //////////////////////////////////////////////////////////// - -/// Brute force scans for devices 0-31 on buses 0-255. -pub fn brute_force_scan() -> Vec { - let mut infos = Vec::new(); - for bus in 0u8..=255 { - for device in 0u8..32 { - if let Some(info) = check_device(bus, device) { - infos.push(info); - } - } - } - infos -} - -// Internal functions ////////////////////////////////////////////////////////// - -fn check_device(bus: u8, device: u8) -> Option { - assert!(device < 32); - let function = 0u8; - - let (device_id, vendor_id) = get_ids(bus, device, function); - if vendor_id == 0xFFFF { - // Device doesn't exist - return None; - } - - let reg1 = unsafe { pci_config_read(bus, device, 0, 0x4) }; - let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) }; - let command = (reg1 & 0x0000FFFF) as u16; - let status = ((reg1 >> 16) & 0x0000FFFF) as u16; - let rev_id = (reg2 & 0x000000FF) as u8; - let prog_if = ((reg2 >> 8) & 0x000000FF) as u8; - let class = ((reg2 >> 16) & 0x0000FFFF) as u16; - let pci_class = PciFullClass::from_u16(class); - let header_type = get_header_type(bus, device, function); - - let mut supported_fns = [true, false, false, false, false, false, false, false]; - if (header_type & 0x80) != 0 { - // It is a multi-function device, so check remaining functions - for function in 0u8..8 { - if get_ids(bus, device, function).1 != 0xFFFF { - if check_function(bus, device, function) { - supported_fns[function as usize] = true; +/// Enumerate PCI devices and run initialisation routines on ones we support +pub fn init() { + for bus in 0..=255 { + for device in 0..32 { + if let Some(device_info) = device::check_device(bus, device) { + if !device::check_pci_support(device_info.device_id) { + trace!("PCI device {} on bus {} unsupported", device_info.device, device_info.bus) } } } } - - let mut bars = [0, 0, 0, 0, 0, 0]; - unsafe { - bars[0] = pci_config_read(bus, device, 0, 0x10); - bars[1] = pci_config_read(bus, device, 0, 0x14); - bars[2] = pci_config_read(bus, device, 0, 0x18); - bars[3] = pci_config_read(bus, device, 0, 0x1C); - bars[4] = pci_config_read(bus, device, 0, 0x20); - bars[5] = pci_config_read(bus, device, 0, 0x24); - } - - let last_row = unsafe { pci_config_read(bus, device, 0, 0x3C) }; - - Some(PciDeviceInfo { - device, - bus, - device_id: DeviceID { - vendor: vendor_id.into(), - id: device_id, - }, - // vendor_id, - full_class: pci_class, - command, - status, - prog_if, - rev_id, - header_type, - bars, - supported_fns, - interrupt_line: (last_row & 0xFF) as u8, - interrupt_pin: ((last_row >> 8) & 0xFF) as u8, - }) -} - -unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 { - let bus = bus as u32; - let device = device as u32; - let func = func as u32; - let offset = offset as u32; - // construct address param - let address = - ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32; - - // write address - Port::::new(0xCF8).write(address); - - // read data - Port::::new(0xCFC).read() -} - -#[allow(dead_code)] -unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) { - let bus = bus as u32; - let device = device as u32; - let func = func as u32; - let offset = offset as u32; - // construct address param - let address = - ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32; - - // write address - Port::::new(0xCF8).write(address); - - // write data - Port::::new(0xCFC).write(value); -} - -fn get_header_type(bus: u8, device: u8, function: u8) -> u8 { - assert!(device < 32); - assert!(function < 8); - let res = unsafe { pci_config_read(bus, device, function, 0x0C) }; - ((res >> 16) & 0xFF) as u8 -} - -fn check_function(bus: u8, device: u8, function: u8) -> bool { - assert!(device < 32); - assert!(function < 8); - get_ids(bus, device, function).1 != 0xFFFF -} - -fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) { - assert!(device < 32); - assert!(function < 8); - let res = unsafe { pci_config_read(bus, device, function, 0) }; - let dev_id = ((res >> 16) & 0xFFFF) as u16; - let vnd_id = (res & 0xFFFF) as u16; - (dev_id, vnd_id) } diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix.rs index 693fbcc8..d1bda613 100644 --- a/ableos/src/devices/pci/piix.rs +++ b/ableos/src/devices/pci/piix.rs @@ -7,14 +7,14 @@ use core::num::TryFromIntError; use x86_64::instructions::interrupts; +use x86_64::instructions::port::Port; use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; // FIXME: platform agnostic paging stuff use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB}; use x86_64::VirtAddr; use crate::arch::memory::BootInfoFrameAllocator; - -use super::{check_device, port::Port}; +use crate::devices::pci::check_device; const PRDT_START: u64 = 0x_ffff_ffff_0000_0000; const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000; @@ -68,7 +68,7 @@ impl Piix { pub fn new(bus: u8, device: u8) -> Option { let device_info = check_device(bus, device)?; trace!("device_info: {device_info}"); - let idetim = unsafe { device_info.config_read(0, 0x40) }; + let idetim = unsafe { device_info.io_read(0, 0x40) }; trace!("idetim: {idetim:b}"); // FIXME: enable the right bits in idetim (and sidetim) to use fast timings @@ -157,7 +157,7 @@ impl Piix { } } - let bmiba = device_info.bars[4] & 0xFFFFFFFC; + let bmiba = device_info.bar(4) & 0xFFFFFFFC; Some(Self { ide_devices, @@ -280,7 +280,7 @@ impl Piix { 0 } + self.bmiba + BMIC_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); let mut bmic = port.read(); // stop ongoing transfer bmic &= !1; @@ -295,7 +295,7 @@ impl Piix { 0 } + self.bmiba + BMIC_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); let mut bmic = port.read(); // mark bit 3 as 0 (read) bmic &= !(1 << 3); @@ -310,7 +310,7 @@ impl Piix { 0 } + self.bmiba + BMIC_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); let mut bmic = port.read(); // mark bit 3 as 1 (write) bmic |= 1 << 3; @@ -325,7 +325,7 @@ impl Piix { 0 } + self.bmiba + BMIS_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); let mut bmis = port.read(); // write 1 to bits 1 (DMA error) and 2 (int status) which clears them bmis |= 1 << 1 | 1 << 2; @@ -340,7 +340,7 @@ unsafe fn select_drive(drive: Drive, channel: Channel) { } else { PRIMARY_COMMAND } + DRIVE_HEAD_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); let mut drive_command = port.read(); if drive.slave() { // mark bit 4 @@ -361,7 +361,7 @@ unsafe fn ata_send_command(command: u8, channel: Channel) -> u8 { } else { PRIMARY_COMMAND } + COMMAND_STATUS_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); port.write(command); ata_delay(channel); port.read() @@ -374,7 +374,7 @@ unsafe fn ata_delay(channel: Channel) { } else { PRIMARY_CONTROL } + ALT_STATUS_OFFSET; - let port: Port = Port::new(addr); + let mut port: Port = Port::new(addr); for _ in 0..14 { port.read(); } diff --git a/ableos/src/devices/pci/port.rs b/ableos/src/devices/pci/port.rs deleted file mode 100644 index e22b1075..00000000 --- a/ableos/src/devices/pci/port.rs +++ /dev/null @@ -1,72 +0,0 @@ -use core::marker::PhantomData; - -/// Trait for limiting [Port] to only being able to read/write u8/16/32. -pub(crate) trait PortRW { - /// Read a value (self) from the port - unsafe fn read_port(port: u16) -> Self; - /// Write a value (self) to the port - unsafe fn write_port(port: u16, value: Self); -} - -// PortRW Implementations ////////////////////////////////////////////////////////////////////////// - -impl PortRW for u8 { - unsafe fn read_port(port: u16) -> Self { - let value: u8; - asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags)); - value - } - - unsafe fn write_port(port: u16, value: Self) { - asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags)); - } -} - -impl PortRW for u16 { - unsafe fn read_port(port: u16) -> Self { - let value: u16; - asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags)); - value - } - - unsafe fn write_port(port: u16, value: Self) { - asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags)); - } -} - -impl PortRW for u32 { - unsafe fn read_port(port: u16) -> Self { - let value: u32; - asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags)); - value - } - - unsafe fn write_port(port: u16, value: Self) { - asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags)); - } -} - -/// A simple wrapper around the asm instructions needed to read/write I/O ports. -pub(crate) struct Port { - addr: u16, - _phantom: PhantomData, -} -impl Port { - /// Create a new `Port` with the given address and data size - pub(crate) fn new(addr: u16) -> Self { - Self { - addr, - _phantom: PhantomData, - } - } - - /// Read a value from the port - pub(crate) unsafe fn read(&self) -> T { - T::read_port(self.addr) - } - - /// Write a value to the port - pub(crate) unsafe fn write(&self, value: T) { - T::write_port(self.addr, value); - } -} diff --git a/ableos/src/devices/pci/support.rs b/ableos/src/devices/pci/support.rs deleted file mode 100644 index 7cbb651e..00000000 --- a/ableos/src/devices/pci/support.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ - -use super::devices::*; - -pub fn check_pci_support(device_id: DeviceID) -> bool { - match device_id { - // FIXME: Unknown class - S3INC_TRIO64V2 => true, - - // MassStorage_IDE (0x0101) - INTEL_PIIX3_IDE => true, - INTEL_PIIX4_IDE => true, - - // Display_VGA (0x0300) - VMWARE_SVGA2 => true, - _ => false, - } -} diff --git a/ableos/src/devices/pci/vendors.rs b/ableos/src/devices/pci/vendors.rs index 04454c53..0a4c9732 100644 --- a/ableos/src/devices/pci/vendors.rs +++ b/ableos/src/devices/pci/vendors.rs @@ -1,20 +1,57 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ use core::fmt::Display; #[derive(PartialEq, Debug, Clone, Eq)] #[repr(u16)] pub enum Vendor { + ThreeDfxInteractiveInc = 0x121a, + ThreeDLabs = 0x3d3d, + AllianceSemiconductorCorp = 0x1142, + ARKLogicInc = 0xedd8, + ATITechnologiesInc = 0x1002, + AvanceLogicIncALI = 0x1005, + ChipsandTechnologies = 0x102c, + CirrusLogic = 0x1013, + Compaq = 0x0e11, + CyrixCorp = 0x1078, + DiamondMultimediaSystems = 0x1092, + DigitalEquipmentCorp = 0x1011, + Iit = 0x1061, + IntegratedMicroSolutionsInc = 0x10e0, + IntelCorp = 0x8086, + IntergraphicsSystems = 0x10ea, + MacronixInc = 0x10d9, + MatroxGraphicsInc = 0x102b, + MiroComputersProductsAG = 0x1031, + NationalSemiconductorCorp = 0x100b, + NeoMagicCorp = 0x10c8, + Number9ComputerCompany = 0x105d, + NVidiaCorporation = 0x10de, + NVidiaSgsthomson = 0x12d2, + OakTechnologyInc = 0x104e, Qemu = 0x1234, - VMware = 0x15AD, - VirtIO = 0x1AF4, - Ati = 1002, - Intel = 0x8086, + QuantumDesignsHKLtd = 0x1098, + Real3D = 0x003d, + Rendition = 0x1163, S3Inc = 0x5333, + SierraSemiconductor = 0x10a8, + SiliconIntegratedSystemsSiS = 0x1039, + SiliconMotionInc = 0x126f, + STBSystemsInc = 0x10b4, + TexasInstruments = 0x104c, + ToshibaAmericaInfoSystems = 0x1179, + TridentMicrosystems = 0x1023, + TsengLabsInc = 0x100c, + TundraSemiconductorCorp = 0x10e3, + VIATechnologiesInc = 0x1106, + VirtIO = 0x1AF4, + VMWareInc = 0x15ad, + Weitek = 0x100e, Unknown(u16), } @@ -22,9 +59,49 @@ impl From for Vendor { fn from(vendor_id: u16) -> Self { use Vendor::*; match vendor_id { - 0x15AD => VMware, - 0x8086 => Intel, - 1002 => Ati, + 0x121a => ThreeDfxInteractiveInc, + 0x3d3d => ThreeDLabs, + 0x1142 => AllianceSemiconductorCorp, + 0xedd8 => ARKLogicInc, + 0x1002 => ATITechnologiesInc, + 0x1005 => AvanceLogicIncALI, + 0x102c => ChipsandTechnologies, + 0x1013 => CirrusLogic, + 0x0e11 => Compaq, + 0x1078 => CyrixCorp, + 0x1092 => DiamondMultimediaSystems, + 0x1011 => DigitalEquipmentCorp, + 0x1061 => Iit, + 0x10e0 => IntegratedMicroSolutionsInc, + 0x8086 => IntelCorp, + 0x10ea => IntergraphicsSystems, + 0x10d9 => MacronixInc, + 0x102b => MatroxGraphicsInc, + 0x1031 => MiroComputersProductsAG, + 0x100b => NationalSemiconductorCorp, + 0x10c8 => NeoMagicCorp, + 0x105d => Number9ComputerCompany, + 0x10de => NVidiaCorporation, + 0x12d2 => NVidiaSgsthomson, + 0x104e => OakTechnologyInc, + 0x1234 => Qemu, + 0x1098 => QuantumDesignsHKLtd, + 0x003d => Real3D, + 0x1163 => Rendition, + 0x5333 => S3Inc, + 0x10a8 => SierraSemiconductor, + 0x1039 => SiliconIntegratedSystemsSiS, + 0x126f => SiliconMotionInc, + 0x10b4 => STBSystemsInc, + 0x104c => TexasInstruments, + 0x1179 => ToshibaAmericaInfoSystems, + 0x1023 => TridentMicrosystems, + 0x100c => TsengLabsInc, + 0x10e3 => TundraSemiconductorCorp, + 0x1106 => VIATechnologiesInc, + 0x1AF4 => VirtIO, + 0x15ad => VMWareInc, + 0x100e => Weitek, id => Unknown(id), } } @@ -34,12 +111,49 @@ impl Into for Vendor { fn into(self) -> u16 { use Vendor::*; match self { - VMware => 0x15AD, - Ati => 1002, + ThreeDfxInteractiveInc => 0x121a, + ThreeDLabs => 0x3d3d, + AllianceSemiconductorCorp => 0x1142, + ARKLogicInc => 0xedd8, + ATITechnologiesInc => 0x1002, + AvanceLogicIncALI => 0x1005, + ChipsandTechnologies => 0x102c, + CirrusLogic => 0x1013, + Compaq => 0x0e11, + CyrixCorp => 0x1078, + DiamondMultimediaSystems => 0x1092, + DigitalEquipmentCorp => 0x1011, + Iit => 0x1061, + IntegratedMicroSolutionsInc => 0x10e0, + IntelCorp => 0x8086, + IntergraphicsSystems => 0x10ea, + MacronixInc => 0x10d9, + MatroxGraphicsInc => 0x102b, + MiroComputersProductsAG => 0x1031, + NationalSemiconductorCorp => 0x100b, + NeoMagicCorp => 0x10c8, + Number9ComputerCompany => 0x105d, + NVidiaCorporation => 0x10de, + NVidiaSgsthomson => 0x12d2, + OakTechnologyInc => 0x104e, Qemu => 0x1234, - VirtIO => 0x1AF4, - Intel => 0x8086, + QuantumDesignsHKLtd => 0x1098, + Real3D => 0x003d, + Rendition => 0x1163, S3Inc => 0x5333, + SierraSemiconductor => 0x10a8, + SiliconIntegratedSystemsSiS => 0x1039, + SiliconMotionInc => 0x126f, + STBSystemsInc => 0x10b4, + TexasInstruments => 0x104c, + ToshibaAmericaInfoSystems => 0x1179, + TridentMicrosystems => 0x1023, + TsengLabsInc => 0x100c, + TundraSemiconductorCorp => 0x10e3, + VIATechnologiesInc => 0x1106, + VirtIO => 0x1AF4, + VMWareInc => 0x15ad, + Weitek => 0x100e, Unknown(id) => id, } } @@ -49,20 +163,18 @@ impl Display for Vendor { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { use Vendor::*; - let mut ret: String = match self { - Qemu => "\0PINK\0QEMU (0x1234)".into(), - VirtIO => "\0PINK\0VirtIO (0x1AF4)".into(), - VMware => "\0PINK\0VMWARE (0x15AD)".into(), - S3Inc => "\0YELLOW\0S3 Incorporated (0x5333)".into(), - Intel => "\0BLUE\0Intel Corp. (0x8086)".into(), - Ati => "\0RED\0ATI (0x1002)".into(), + match self { + Qemu => write!(f, "{}", "\0PINK\0QEMU (0x1234)"), + VirtIO => write!(f, "{}", "\0PINK\0VirtIO (0x1AF4)"), + VMWareInc => write!(f, "{}", "\0PINK\0VMWARE (0x15AD)"), + S3Inc => write!(f, "{}", "\0YELLOW\0S3 Incorporated (0x5333)"), + IntelCorp => write!(f, "{}", "\0BLUE\0Intel Corp. (0x8086)"), + ATITechnologiesInc => write!(f, "{}", "\0RED\0ATI (0x1002)"), + Unknown(id) => write!(f, "\0RED\0Unknown ({:#6})", id), + other => write!(f, "{other:?}"), + }?; - Unknown(id) => format!("\0RED\0Unknown ({:#6})", id), - }; - - ret.push_str("\0RESET\0"); - - write!(f, "{}", ret)?; + write!(f, "\0RESET\0")?; Ok(()) } } diff --git a/ableos/src/devices/pci_inner.rs b/ableos/src/devices/pci_inner.rs deleted file mode 100644 index 83cff973..00000000 --- a/ableos/src/devices/pci_inner.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! map the DeviceClass via -//! -//! - -#[repr(C)] -pub enum Vendors { - ThreeDfxInteractiveInc = 0x121a, - ThreeDLabs = 0x3d3d, - AllianceSemiconductorCorp = 0x1142, - ARKLogicInc = 0xedd8, - ATITechnologiesInc = 0x1002, - AvanceLogicIncALI = 0x1005, - ChipsandTechnologies = 0x102c, - CirrusLogic = 0x1013, - Compaq = 0x0e11, - CyrixCorp = 0x1078, - DiamondMultimediaSystems = 0x1092, - DigitalEquipmentCorp = 0x1011, - Iit = 0x1061, - IntegratedMicroSolutionsInc = 0x10e0, - IntelCorp = 0x8086, - IntergraphicsSystems = 0x10ea, - MacronixInc = 0x10d9, - MatroxGraphicsInc = 0x102b, - MiroComputersProductsAG = 0x1031, - NationalSemiconductorCorp = 0x100b, - NeoMagicCorp = 0x10c8, - Number9ComputerCompany = 0x105d, - NVidiaCorporation = 0x10de, - NVidiaSgsthomson = 0x12d2, - OakTechnologyInc = 0x104e, - QuantumDesignsHKLtd = 0x1098, - Real3D = 0x003d, - Rendition = 0x1163, - S3Inc = 0x5333, - SierraSemiconductor = 0x10a8, - SiliconIntegratedSystemsSiS = 0x1039, - SiliconMotionInc = 0x126f, - STBSystemsInc = 0x10b4, - TexasInstruments = 0x104c, - ToshibaAmericaInfoSystems = 0x1179, - TridentMicrosystems = 0x1023, - TsengLabsInc = 0x100c, - TundraSemiconductorCorp = 0x10e3, - VIATechnologiesInc = 0x1106, - VMWareInc = 0x15ad, - Weitek = 0x100e, - Unknown = 0xffff, -} - -pub struct PciDevice { - pub vendor: Vendors, -} - -#[allow(dead_code)] -fn scan_pci_bus() {} diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index 0a2ac2e8..9a37c3f5 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -10,7 +10,7 @@ use core::sync::atomic::AtomicU64; use crate::arch::memory::BootInfoFrameAllocator; use crate::arch::{drivers::sysinfo::master, init, sloop}; -use crate::devices::pci::piix::Piix; +use crate::devices::pci; use crate::relib::network::socket::{SimpleSock, Socket}; use crate::{boot_conf::KernelConfig, scratchpad, systeminfo::RELEASE_TYPE, TERM}; use crate::{filesystem, hardware}; @@ -44,18 +44,14 @@ pub fn kernel_main( // term.draw_term(); // drop(term); + pci::init(); + x86_64::instructions::interrupts::without_interrupts(|| { hardware::init_mouse(); }); filesystem::init().unwrap(); - // FIXME: unhardcode this and do device discovery - let mut piix = Piix::new(0, 3).unwrap(); - piix.allocate_dma_frame(&mut mapper, &mut frame_allocator) - .unwrap(); - piix.read().unwrap(); - /* // println!("abc"); diff --git a/ableos/src/panic.rs b/ableos/src/panic.rs index 41b08378..609b2a60 100644 --- a/ableos/src/panic.rs +++ b/ableos/src/panic.rs @@ -1,8 +1,8 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ use core::panic::PanicInfo; use log::error; diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 045289f5..bfb77519 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -6,7 +6,6 @@ use crate::arch::drivers::sysinfo::master; use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2}; -use crate::devices::pci::brute_force_scan; use crate::filesystem; use crate::filesystem::vfs::VFS; use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE}; @@ -73,9 +72,6 @@ pub fn scratchpad() { // } // bruh(); - for x in brute_force_scan() { - println!("{}", x); - } disable(); let tick_time = fetch_time(); diff --git a/ableos/src/tests/mod.rs b/ableos/src/tests/mod.rs index d01f45f0..4429d367 100644 --- a/ableos/src/tests/mod.rs +++ b/ableos/src/tests/mod.rs @@ -1,8 +1,8 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ use core::panic::PanicInfo; diff --git a/ableos/src/tests/old_tests.rs b/ableos/src/tests/old_tests.rs index 08131570..c041774e 100644 --- a/ableos/src/tests/old_tests.rs +++ b/ableos/src/tests/old_tests.rs @@ -1,8 +1,8 @@ /* -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ use crate::{ kmain::KERNEL_CONF, diff --git a/ableos/src/virtio/mod.rs b/ableos/src/virtio/mod.rs index cb22fa19..802a7225 100644 --- a/ableos/src/virtio/mod.rs +++ b/ableos/src/virtio/mod.rs @@ -19,7 +19,7 @@ pub fn device_handler(device: PciDeviceInfo) { // Network => todo!(), Display => { trace!("Display found"); - println!("{}", device.interrupt_pin); + println!("{}", device.interrupt_pin()); } // Multimedia => todo!(), // Memory => todo!(), diff --git a/repbuild/src/main.rs b/repbuild/src/main.rs index e3662bcf..bc4d5714 100644 --- a/repbuild/src/main.rs +++ b/repbuild/src/main.rs @@ -1,9 +1,9 @@ /* -* Copyright (c) 2022, Umut İnan Erdoğan -* Copyright (c) 2022, able -* -* SPDX-License-Identifier: MPL-2.0 -*/ + * Copyright (c) 2022, Umut İnan Erdoğan + * Copyright (c) 2022, able + * + * SPDX-License-Identifier: MPL-2.0 + */ use std::{fs, process::Command}; From 445b5f5f5cc3f65e047f44a136adc9b0bee644e0 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Fri, 12 Aug 2022 16:48:22 +0300 Subject: [PATCH 13/18] PCI: device discovery --- ableos/src/devices/pci/device.rs | 26 ++++++-------------------- ableos/src/devices/pci/mod.rs | 29 ++++++++++++++++++++++++++--- ableos/src/devices/pci/vendors.rs | 2 +- ableos/src/kmain.rs | 2 +- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/ableos/src/devices/pci/device.rs b/ableos/src/devices/pci/device.rs index 1b4371c3..922a241b 100644 --- a/ableos/src/devices/pci/device.rs +++ b/ableos/src/devices/pci/device.rs @@ -9,7 +9,10 @@ use core::fmt; use x86_64::instructions::port::Port; -use super::{vendors::Vendor::{self, *}, PciFullClass, PciClass}; +use super::{ + vendors::Vendor::{self, *}, + PciClass, PciFullClass, +}; // FIXME: Unknown class pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); @@ -41,9 +44,7 @@ impl PciDeviceInfo { /// Get the bar, 0-indexed pub fn bar(&self, bar: u8) -> u32 { assert!(bar < 6); - unsafe { - self.io_read(0, 0x10 + bar * 4) - } + unsafe { self.io_read(0, 0x10 + bar * 4) } } /// Get the interrupt pin @@ -95,7 +96,7 @@ impl fmt::Display for PciDeviceInfo { } } -#[derive(PartialEq, Clone, Eq, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct DeviceID { pub vendor: Vendor, pub id: u16, @@ -107,21 +108,6 @@ impl DeviceID { } } -pub fn check_pci_support(device_id: DeviceID) -> bool { - match device_id { - // FIXME: Unknown class - S3INC_TRIO64V2 => true, - - // MassStorage_IDE (0x0101) - INTEL_PIIX3_IDE => true, - INTEL_PIIX4_IDE => true, - - // Display_VGA (0x0300) - VMWARE_SVGA2 => true, - _ => false, - } -} - pub fn check_device(bus: u8, device: u8) -> Option { assert!(device < 32); let (device_id, vendor_id) = get_ids(bus, device, 0); diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index 3338c2a3..f14a264b 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -13,14 +13,37 @@ pub mod piix; pub use class::*; pub use device::*; +use x86_64::structures::paging::{Mapper, Size4KiB}; + +use crate::arch::memory::BootInfoFrameAllocator; + +use self::piix::Piix; /// Enumerate PCI devices and run initialisation routines on ones we support -pub fn init() { +pub fn init(mapper: &mut impl Mapper, frame_allocator: &mut BootInfoFrameAllocator) { for bus in 0..=255 { for device in 0..32 { if let Some(device_info) = device::check_device(bus, device) { - if !device::check_pci_support(device_info.device_id) { - trace!("PCI device {} on bus {} unsupported", device_info.device, device_info.bus) + match device_info.device_id { + // FIXME: Unknown class + S3INC_TRIO64V2 => {} + + // MassStorage_IDE (0x0101) + INTEL_PIIX3_IDE | INTEL_PIIX4_IDE => { + let mut piix = Piix::new(bus, device).unwrap(); + piix.allocate_dma_frame(mapper, frame_allocator).unwrap(); + piix.read().unwrap(); + } + + // Display_VGA (0x0300) + VMWARE_SVGA2 => {} + _ => { + trace!( + "PCI device {} on bus {} unsupported", + device_info.device, + device_info.bus + ) + } } } } diff --git a/ableos/src/devices/pci/vendors.rs b/ableos/src/devices/pci/vendors.rs index 0a4c9732..486b32a4 100644 --- a/ableos/src/devices/pci/vendors.rs +++ b/ableos/src/devices/pci/vendors.rs @@ -6,7 +6,7 @@ use core::fmt::Display; -#[derive(PartialEq, Debug, Clone, Eq)] +#[derive(PartialEq, Debug, Copy, Clone, Eq)] #[repr(u16)] pub enum Vendor { ThreeDfxInteractiveInc = 0x121a, diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index 9a37c3f5..5bf23c6c 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -44,7 +44,7 @@ pub fn kernel_main( // term.draw_term(); // drop(term); - pci::init(); + pci::init(&mut mapper, &mut frame_allocator); x86_64::instructions::interrupts::without_interrupts(|| { hardware::init_mouse(); From 892b3e7250b3b3d5d9eb59a72049a815a7bbcbdf Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Tue, 16 Aug 2022 16:35:34 +0300 Subject: [PATCH 14/18] working IDE DMA implementation --- Cargo.lock | 7 + ableos/Cargo.toml | 2 +- ableos/src/arch/x86_64/interrupts.rs | 32 +++- ableos/src/devices/pci/device.rs | 52 ++++-- ableos/src/devices/pci/mod.rs | 26 ++- .../src/devices/pci/{piix.rs => piix_ide.rs} | 149 +++++++++++++++--- ableos/src/scratchpad.rs | 19 +++ 7 files changed, 245 insertions(+), 42 deletions(-) rename ableos/src/devices/pci/{piix.rs => piix_ide.rs} (76%) diff --git a/Cargo.lock b/Cargo.lock index a19f7b10..3a0df9f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,7 @@ dependencies = [ "rdrand", "riscv", "rkyv", + "seq-macro", "serde", "spin 0.9.4", "toml", @@ -648,6 +649,12 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "seq-macro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0772c5c30e1a0d91f6834f8e545c69281c099dfa9a3ac58d96a9fd629c8d4898" + [[package]] name = "serde" version = "1.0.141" diff --git a/ableos/Cargo.toml b/ableos/Cargo.toml index f8b2669a..5c0639f4 100644 --- a/ableos/Cargo.toml +++ b/ableos/Cargo.toml @@ -78,7 +78,7 @@ versioning = { git = "https://git.ablecorp.us/able/aos_userland" } pc-keyboard = "0.5" # mini-backtrace = "0.1" clparse = { git = "https://git.ablecorp.us/able/core_utils", default-features = false } - +seq-macro = "0.3" [dependencies.linked_list_allocator] version = "0.9.0" diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index a59384af..23700114 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -6,10 +6,16 @@ use core::panic::PanicInfo; -use crate::{arch::gdt, println, rhai_shell::KEYBUFF}; +use crate::{ + arch::gdt, + devices::pci::{PciDevice, PCI_DEVICES}, + println, + rhai_shell::KEYBUFF, +}; use cpuio::outb; use pic8259::ChainedPics; use qrcode::QrCode; +use seq_macro::seq; use spin::Lazy; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; @@ -30,6 +36,9 @@ pub enum InterruptIndex { /// Mouse offset Mouse = 44, + /// Disk offset + Disk = 46, + // SecondInterrupt = PIC_2_OFFSET, Cmos = 0x70, } @@ -47,9 +56,9 @@ static IDT: Lazy = Lazy::new(|| { reset_pit_for_cpu(); let mut idt = InterruptDescriptorTable::new(); - for int in 32..=255 { - idt[int].set_handler_fn(undefined_handler); - } + seq!(N in 32..=255 { + idt[N].set_handler_fn(undefined_handler_~N); + }); idt.breakpoint.set_handler_fn(breakpoint_handler); unsafe { @@ -68,12 +77,21 @@ static IDT: Lazy = Lazy::new(|| { idt }); -extern "x86-interrupt" fn undefined_handler(stack_frame: InterruptStackFrame) { - error!("{:?}", stack_frame); -} +seq!(N in 32..=255 { + extern "x86-interrupt" fn undefined_handler_~N(stack_frame: InterruptStackFrame) { + error!("INT {}: {:?}", N, stack_frame); + unsafe { + PICS.lock() + .notify_end_of_interrupt(N); + } + } +}); extern "x86-interrupt" fn software_int_handler(stack_frame: InterruptStackFrame) { trace!("EXCEPTION: SOFTWARE INT\n{:#?}", stack_frame); + unsafe { + PICS.lock().notify_end_of_interrupt(54); + } } extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { diff --git a/ableos/src/devices/pci/device.rs b/ableos/src/devices/pci/device.rs index 922a241b..217c6d31 100644 --- a/ableos/src/devices/pci/device.rs +++ b/ableos/src/devices/pci/device.rs @@ -7,6 +7,7 @@ use core::fmt; +use serde::de::value; use x86_64::instructions::port::Port; use super::{ @@ -24,7 +25,7 @@ pub const INTEL_PIIX4_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7111); // Display_VGA (0x0300) pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMWareInc, 0x0405); -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] /// A struct containing info about a PCI device. pub struct PciDeviceInfo { pub header_type: u8, @@ -44,18 +45,29 @@ impl PciDeviceInfo { /// Get the bar, 0-indexed pub fn bar(&self, bar: u8) -> u32 { assert!(bar < 6); - unsafe { self.io_read(0, 0x10 + bar * 4) } + unsafe { self.read(0, 0x10 + bar * 4) } } /// Get the interrupt pin pub fn interrupt_pin(&self) -> u8 { - let last_row = unsafe { self.io_read(0, 0x3C) }; + let last_row = unsafe { self.read(0, 0x3C) }; ((last_row >> 8) & 0xFF) as u8 } - /// Read from IO space - pub unsafe fn io_read(&self, func: u8, offset: u8) -> u32 { - pci_io_read(self.bus, self.device, func, offset) + /// Enable bus mastering. This allows the PCI device to do DMA + pub fn enable_bus_mastering(&self) { + let command = unsafe { self.read(0, 4) } | 1 << 2; + unsafe { self.write(0, 4, command) } + } + + /// Read from configuration space + pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { + pci_config_read(self.bus, self.device, func, offset) + } + + /// Write to IO space + pub unsafe fn write(&self, func: u8, offset: u8, value: u32) { + pci_config_write(self.bus, self.device, func, offset, value) } } @@ -116,7 +128,7 @@ pub fn check_device(bus: u8, device: u8) -> Option { return None; } - let reg2 = unsafe { pci_io_read(bus, device, 0, 0x8) }; + let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) }; let class = ((reg2 >> 16) & 0x0000FFFF) as u16; let pci_class = PciFullClass::from_u16(class); let header_type = get_header_type(bus, device, 0); @@ -134,7 +146,7 @@ pub fn check_device(bus: u8, device: u8) -> Option { }) } -unsafe fn pci_io_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 { +unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 { let bus = bus as u32; let device = device as u32; let func = func as u32; @@ -144,23 +156,39 @@ unsafe fn pci_io_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 { ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32; // write address - Port::::new(0xCF8).write(address); + Port::new(0xCF8).write(address); // read data - Port::::new(0xCFC).read() + Port::new(0xCFC).read() +} + +unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) { + let bus = bus as u32; + let device = device as u32; + let func = func as u32; + let offset = offset as u32; + // construct address param + let address = + ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc) | 0x80000000) as u32; + + // write address + Port::new(0xCF8).write(address); + + // write data + Port::new(0xCFC).write(value); } fn get_header_type(bus: u8, device: u8, function: u8) -> u8 { assert!(device < 32); assert!(function < 8); - let res = unsafe { pci_io_read(bus, device, function, 0x0C) }; + let res = unsafe { pci_config_read(bus, device, function, 0x0C) }; ((res >> 16) & 0xFF) as u8 } fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) { assert!(device < 32); assert!(function < 8); - let res = unsafe { pci_io_read(bus, device, function, 0) }; + let res = unsafe { pci_config_read(bus, device, function, 0) }; let dev_id = ((res >> 16) & 0xFFFF) as u16; let vnd_id = (res & 0xFFFF) as u16; (dev_id, vnd_id) diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index f14a264b..5e301cf7 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -9,30 +9,48 @@ pub mod device; pub mod vendors; // MassStorage_IDE (0x0101) -pub mod piix; +pub mod piix_ide; +use alloc::sync::Arc; pub use class::*; pub use device::*; +use lazy_static::lazy_static; +use spin::Mutex; use x86_64::structures::paging::{Mapper, Size4KiB}; use crate::arch::memory::BootInfoFrameAllocator; -use self::piix::Piix; +use self::piix_ide::PiixIde; + +lazy_static! { + pub static ref PCI_DEVICES: Mutex>>> = Default::default(); +} + +#[non_exhaustive] +pub enum PciDevice { + // MassStorage_IDE (0x0101) + PiixIde(PiixIde), + // Variant so that we aren't about irrefutable if-let patterns + // FIXME: remove as soon as we have other variants + _0, +} /// Enumerate PCI devices and run initialisation routines on ones we support pub fn init(mapper: &mut impl Mapper, frame_allocator: &mut BootInfoFrameAllocator) { for bus in 0..=255 { for device in 0..32 { if let Some(device_info) = device::check_device(bus, device) { + trace!("{device_info}"); match device_info.device_id { // FIXME: Unknown class S3INC_TRIO64V2 => {} // MassStorage_IDE (0x0101) INTEL_PIIX3_IDE | INTEL_PIIX4_IDE => { - let mut piix = Piix::new(bus, device).unwrap(); + let mut piix = PiixIde::new(bus, device).unwrap(); piix.allocate_dma_frame(mapper, frame_allocator).unwrap(); - piix.read().unwrap(); + let mut devices = PCI_DEVICES.lock(); + devices.push(Arc::new(Mutex::new(PciDevice::PiixIde(piix)))); } // Display_VGA (0x0300) diff --git a/ableos/src/devices/pci/piix.rs b/ableos/src/devices/pci/piix_ide.rs similarity index 76% rename from ableos/src/devices/pci/piix.rs rename to ableos/src/devices/pci/piix_ide.rs index d1bda613..cbe03c01 100644 --- a/ableos/src/devices/pci/piix.rs +++ b/ableos/src/devices/pci/piix_ide.rs @@ -4,10 +4,11 @@ * SPDX-License-Identifier: MPL-2.0 */ +use core::mem; use core::num::TryFromIntError; -use x86_64::instructions::interrupts; use x86_64::instructions::port::Port; +use x86_64::instructions::{hlt, interrupts}; use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; // FIXME: platform agnostic paging stuff use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB}; @@ -16,8 +17,11 @@ use x86_64::VirtAddr; use crate::arch::memory::BootInfoFrameAllocator; use crate::devices::pci::check_device; -const PRDT_START: u64 = 0x_ffff_ffff_0000_0000; -const BUFFER_START: u64 = 0x_ffff_ffff_0000_1000; +use super::PciDeviceInfo; + +// FIXME: un-hardcode these +const PRDT_START: u64 = 0xffff_ffff_0000_0000; +const BUFFER_START: u64 = 0xffff_ffff_0000_1000; /// Bus Master IDE Command const BMIC_OFFSET: u16 = 0; @@ -38,6 +42,18 @@ const SECONDARY_COMMAND: u16 = 0x0170; /// Data register offset const DATA_OFFSET: u16 = 0; +/// Sector count register offset +const SECCOUNT_OFFSET: u16 = 2; + +/// LBA0 register offset +const LBA0_OFFSET: u16 = 3; + +/// LBA1 register offset +const LBA1_OFFSET: u16 = 4; + +/// LBA2 register offset +const LBA2_OFFSET: u16 = 5; + /// Drive/Head register offset const DRIVE_HEAD_OFFSET: u16 = 6; @@ -56,19 +72,23 @@ const ALT_STATUS_OFFSET: u16 = 2; /// ATA identification command const CMD_IDENTIFY: u8 = 0xEC; -pub struct Piix { +/// ATA read using LBA48 DMA command +const CMD_READ_DMA_EXT: u8 = 0x25; + +pub struct PiixIde { + device_info: PciDeviceInfo, ide_devices: Vec, prdt_frame: Option, buffer_frames: Option>, bmiba: u16, } -impl Piix { +impl PiixIde { // FIXME: make this return a Result pub fn new(bus: u8, device: u8) -> Option { let device_info = check_device(bus, device)?; - trace!("device_info: {device_info}"); - let idetim = unsafe { device_info.io_read(0, 0x40) }; + device_info.enable_bus_mastering(); + let idetim = unsafe { device_info.read(0, 0x40) }; trace!("idetim: {idetim:b}"); // FIXME: enable the right bits in idetim (and sidetim) to use fast timings @@ -160,6 +180,7 @@ impl Piix { let bmiba = device_info.bar(4) & 0xFFFFFFFC; Some(Self { + device_info, ide_devices, prdt_frame: None, buffer_frames: None, @@ -177,6 +198,7 @@ impl Piix { let prdt_frame = frame_allocator .allocate_frame() .ok_or(MapToError::FrameAllocationFailed)?; + let buffer_frames = { let mut frame = frame_allocator .allocate_frame() @@ -231,7 +253,7 @@ impl Piix { Ok(()) } - pub fn read(&self) -> Result<(), TryFromIntError> { + pub fn read(&mut self) -> Result<(), TryFromIntError> { // prepare PRD table let prd = PRDT_START as *mut PhysRegionDescriptor; unsafe { @@ -243,19 +265,51 @@ impl Piix { (*prd).byte_count = 512; // this is the end of table (*prd).eot = 1 << 7; + // this byte is reserved, we should probably set it to 0 + (*prd)._0 = 0; } unsafe { self.load_prdt(Channel::Primary); self.stop(Channel::Primary); self.set_read(Channel::Primary); - self.clear_status(Channel::Primary); + self.clear_bmi_status(Channel::Primary); select_drive(Drive::Master, Channel::Primary); + set_lba(Channel::Primary, 0, 1); + ata_send_command(CMD_READ_DMA_EXT, Channel::Primary); + self.start(Channel::Primary); + + loop { + let status = self.bmi_status(Channel::Primary); + trace!("read status: 0b{status:b}"); + + // Bit 2 (INT) set? + if (status >> 2) & 1 == 1 { + break; + } + } + + // FIXME: error handling + + // Stop DMA + self.stop(Channel::Primary); + + // Clear the interrupt bit + self.clear_bmi_status(Channel::Primary); + + for i in 0..512 { + let addr = (BUFFER_START + i) as *mut u8; + trace!("byte {i}: {}", *addr); + } } Ok(()) } + pub fn device_info(&self) -> PciDeviceInfo { + self.device_info + } + unsafe fn load_prdt(&self, channel: Channel) { let addr = if channel.secondary() { BMI_SECONDARY @@ -273,6 +327,21 @@ impl Piix { ); } + unsafe fn start(&self, channel: Channel) { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIC_OFFSET; + let mut port: Port = Port::new(addr); + let mut bmic = port.read(); + // start transfer + bmic |= 1; + // write the new bmic + port.write(bmic); + } + unsafe fn stop(&self, channel: Channel) { let addr = if channel.secondary() { BMI_SECONDARY @@ -318,7 +387,18 @@ impl Piix { port.write(bmic); } - unsafe fn clear_status(&self, channel: Channel) { + unsafe fn bmi_status(&self, channel: Channel) -> u8 { + let addr = if channel.secondary() { + BMI_SECONDARY + } else { + 0 + } + self.bmiba + + BMIS_OFFSET; + let mut port = Port::new(addr); + port.read() + } + + unsafe fn clear_bmi_status(&self, channel: Channel) { let addr = if channel.secondary() { BMI_SECONDARY } else { @@ -341,14 +421,15 @@ unsafe fn select_drive(drive: Drive, channel: Channel) { PRIMARY_COMMAND } + DRIVE_HEAD_OFFSET; let mut port: Port = Port::new(addr); - let mut drive_command = port.read(); - if drive.slave() { - // mark bit 4 - drive_command |= 1 << 4; + // FIXME: CHS support + let drive_command = if drive.slave() { + // slave & LBA + 0b11110000 } else { - // clear bit 4 - drive_command &= !(1 << 4); - } + // master & LBA + 0b11100000 + }; + // write the new drive/head register port.write(drive_command); ata_delay(channel); @@ -361,7 +442,7 @@ unsafe fn ata_send_command(command: u8, channel: Channel) -> u8 { } else { PRIMARY_COMMAND } + COMMAND_STATUS_OFFSET; - let mut port: Port = Port::new(addr); + let mut port = Port::new(addr); port.write(command); ata_delay(channel); port.read() @@ -380,6 +461,37 @@ unsafe fn ata_delay(channel: Channel) { } } +/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors +unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16) { + // FIXME: CHS and LBA24 support + assert!(lba < 0xFFFFFFFFFFFF); + + let command_block = if channel.secondary() { + SECONDARY_COMMAND + } else { + PRIMARY_COMMAND + }; + let mut seccount = Port::new(command_block + SECCOUNT_OFFSET); + let mut lba0 = Port::new(command_block + LBA0_OFFSET); + let mut lba1 = Port::new(command_block + LBA1_OFFSET); + let mut lba2 = Port::new(command_block + LBA2_OFFSET); + + let lba_bytes = lba.to_le_bytes(); + let sector_count_bytes = sector_count.to_le_bytes(); + + // write the new LBA & sector count registers + // if LBA48 { + seccount.write(sector_count_bytes[1]); + lba0.write(lba_bytes[3]); + lba1.write(lba_bytes[4]); + lba2.write(lba_bytes[5]); + // } + seccount.write(sector_count_bytes[0]); + lba0.write(lba_bytes[0]); + lba1.write(lba_bytes[1]); + lba2.write(lba_bytes[2]); +} + unsafe fn read_dword_buffer(port: u16, buffer: *mut u32, mut count: u32) { // FIXME: this assumes x86-64 interrupts::without_interrupts(|| { @@ -398,6 +510,7 @@ struct IdeDevice { pub channel: Channel, pub drive: Drive, pub size: u64, // in sectors + // FIXME: model } #[derive(Copy, Clone, Debug)] diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index bfb77519..2b5e71a9 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -6,6 +6,7 @@ use crate::arch::drivers::sysinfo::master; use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2}; +use crate::devices::pci::{PciDevice, PCI_DEVICES}; use crate::filesystem; use crate::filesystem::vfs::VFS; use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE}; @@ -112,6 +113,24 @@ pub fn scratchpad() { BANNER_WIDTH ); + let piix_ide_device = { + let pci_devices = PCI_DEVICES.lock(); + pci_devices + .iter() + .find_map(|device_ref| { + let device = device_ref.lock(); + if let PciDevice::PiixIde(_) = &*device { + Some(device_ref.clone()) + } else { + None + } + }) + .unwrap() + }; + let mut piix_ide_device = piix_ide_device.lock(); + if let PciDevice::PiixIde(device) = &mut *piix_ide_device { + device.read().unwrap() + } real_shell(); } From 775ded8e23e49c85ddd7d6a25dd5b19a09ec6934 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Tue, 16 Aug 2022 17:09:22 +0300 Subject: [PATCH 15/18] IDE: Rename PiixIde to PciIde, use it for all IDE controllers If the controller is not a known PCI IDE controller, then we warn about the controller during PCI device discovery. :^) --- ableos/src/arch/x86_64/interrupts.rs | 1 - ableos/src/devices/pci/device.rs | 3 +- .../src/devices/pci/{piix_ide.rs => ide.rs} | 10 +++---- ableos/src/devices/pci/mod.rs | 30 ++++++++++--------- ableos/src/scratchpad.rs | 4 +-- 5 files changed, 23 insertions(+), 25 deletions(-) rename ableos/src/devices/pci/{piix_ide.rs => ide.rs} (98%) diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index 23700114..9daaaca8 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -8,7 +8,6 @@ use core::panic::PanicInfo; use crate::{ arch::gdt, - devices::pci::{PciDevice, PCI_DEVICES}, println, rhai_shell::KEYBUFF, }; diff --git a/ableos/src/devices/pci/device.rs b/ableos/src/devices/pci/device.rs index 217c6d31..e9469ef0 100644 --- a/ableos/src/devices/pci/device.rs +++ b/ableos/src/devices/pci/device.rs @@ -7,7 +7,6 @@ use core::fmt; -use serde::de::value; use x86_64::instructions::port::Port; use super::{ @@ -16,7 +15,7 @@ use super::{ }; // FIXME: Unknown class -pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); +pub const S3_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); // MassStorage_IDE (0x0101) pub const INTEL_PIIX3_IDE: DeviceID = DeviceID::new(IntelCorp, 0x7010); diff --git a/ableos/src/devices/pci/piix_ide.rs b/ableos/src/devices/pci/ide.rs similarity index 98% rename from ableos/src/devices/pci/piix_ide.rs rename to ableos/src/devices/pci/ide.rs index cbe03c01..ecac1cba 100644 --- a/ableos/src/devices/pci/piix_ide.rs +++ b/ableos/src/devices/pci/ide.rs @@ -4,13 +4,11 @@ * SPDX-License-Identifier: MPL-2.0 */ -use core::mem; use core::num::TryFromIntError; -use x86_64::instructions::port::Port; -use x86_64::instructions::{hlt, interrupts}; +// FIXME: platform agnostic-ify these +use x86_64::instructions::{port::Port, interrupts}; use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; -// FIXME: platform agnostic paging stuff use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB}; use x86_64::VirtAddr; @@ -75,7 +73,7 @@ const CMD_IDENTIFY: u8 = 0xEC; /// ATA read using LBA48 DMA command const CMD_READ_DMA_EXT: u8 = 0x25; -pub struct PiixIde { +pub struct PciIde { device_info: PciDeviceInfo, ide_devices: Vec, prdt_frame: Option, @@ -83,7 +81,7 @@ pub struct PiixIde { bmiba: u16, } -impl PiixIde { +impl PciIde { // FIXME: make this return a Result pub fn new(bus: u8, device: u8) -> Option { let device_info = check_device(bus, device)?; diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index 5e301cf7..12d18d08 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -9,7 +9,7 @@ pub mod device; pub mod vendors; // MassStorage_IDE (0x0101) -pub mod piix_ide; +pub mod ide; use alloc::sync::Arc; pub use class::*; @@ -20,7 +20,8 @@ use x86_64::structures::paging::{Mapper, Size4KiB}; use crate::arch::memory::BootInfoFrameAllocator; -use self::piix_ide::PiixIde; +// MassStorage_IDE (0x0101) +use self::ide::PciIde; lazy_static! { pub static ref PCI_DEVICES: Mutex>>> = Default::default(); @@ -28,8 +29,7 @@ lazy_static! { #[non_exhaustive] pub enum PciDevice { - // MassStorage_IDE (0x0101) - PiixIde(PiixIde), + Ide(PciIde), // Variant so that we aren't about irrefutable if-let patterns // FIXME: remove as soon as we have other variants _0, @@ -43,24 +43,26 @@ pub fn init(mapper: &mut impl Mapper, frame_allocator: &mut BootInfoFr trace!("{device_info}"); match device_info.device_id { // FIXME: Unknown class - S3INC_TRIO64V2 => {} + S3_TRIO64V2 => {} // MassStorage_IDE (0x0101) - INTEL_PIIX3_IDE | INTEL_PIIX4_IDE => { - let mut piix = PiixIde::new(bus, device).unwrap(); - piix.allocate_dma_frame(mapper, frame_allocator).unwrap(); + ide_controller if device_info.full_class == PciFullClass::MassStorage_IDE => { + if !matches!(ide_controller, INTEL_PIIX3_IDE | INTEL_PIIX4_IDE) { + // not one of our tested IDE controllers, but + // we shouldn't have any problems + warn!("Unsupported PCI IDE controller device {device} on bus {bus}") + } + + let mut ide = PciIde::new(bus, device).unwrap(); + ide.allocate_dma_frame(mapper, frame_allocator).unwrap(); let mut devices = PCI_DEVICES.lock(); - devices.push(Arc::new(Mutex::new(PciDevice::PiixIde(piix)))); + devices.push(Arc::new(Mutex::new(PciDevice::Ide(ide)))); } // Display_VGA (0x0300) VMWARE_SVGA2 => {} _ => { - trace!( - "PCI device {} on bus {} unsupported", - device_info.device, - device_info.bus - ) + trace!("Unknown PCI device {device} on bus {bus}") } } } diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 2b5e71a9..88886862 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -119,7 +119,7 @@ pub fn scratchpad() { .iter() .find_map(|device_ref| { let device = device_ref.lock(); - if let PciDevice::PiixIde(_) = &*device { + if let PciDevice::Ide(_) = &*device { Some(device_ref.clone()) } else { None @@ -128,7 +128,7 @@ pub fn scratchpad() { .unwrap() }; let mut piix_ide_device = piix_ide_device.lock(); - if let PciDevice::PiixIde(device) = &mut *piix_ide_device { + if let PciDevice::Ide(device) = &mut *piix_ide_device { device.read().unwrap() } real_shell(); From 21de06868555bbb5cf15726ed2bcdca0ddcdc379 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Wed, 17 Aug 2022 13:25:53 +0300 Subject: [PATCH 16/18] IDE: clean everything up --- ableos/src/arch/x86_64/interrupts.rs | 6 +- ableos/src/devices/pci/ide.rs | 86 ++++++++++++++++------------ ableos/src/scratchpad.rs | 14 +++-- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index 9daaaca8..803af1a3 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -6,11 +6,7 @@ use core::panic::PanicInfo; -use crate::{ - arch::gdt, - println, - rhai_shell::KEYBUFF, -}; +use crate::{arch::gdt, println, rhai_shell::KEYBUFF}; use cpuio::outb; use pic8259::ChainedPics; use qrcode::QrCode; diff --git a/ableos/src/devices/pci/ide.rs b/ableos/src/devices/pci/ide.rs index ecac1cba..63e59c2a 100644 --- a/ableos/src/devices/pci/ide.rs +++ b/ableos/src/devices/pci/ide.rs @@ -7,9 +7,9 @@ use core::num::TryFromIntError; // FIXME: platform agnostic-ify these -use x86_64::instructions::{port::Port, interrupts}; -use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; +use x86_64::instructions::{interrupts, port::Port}; use x86_64::structures::paging::{mapper::MapToError, Mapper, Page, PhysFrame, Size4KiB}; +use x86_64::structures::paging::{FrameAllocator, FrameDeallocator}; use x86_64::VirtAddr; use crate::arch::memory::BootInfoFrameAllocator; @@ -21,6 +21,9 @@ use super::PciDeviceInfo; const PRDT_START: u64 = 0xffff_ffff_0000_0000; const BUFFER_START: u64 = 0xffff_ffff_0000_1000; +/// ATA logical sector size, in bytes +const SECTOR_SIZE: u16 = 512; + /// Bus Master IDE Command const BMIC_OFFSET: u16 = 0; /// Bus Master IDE Status @@ -251,7 +254,17 @@ impl PciIde { Ok(()) } - pub fn read(&mut self) -> Result<(), TryFromIntError> { + pub fn read( + &mut self, + channel: Channel, + drive: Drive, + lba: u64, + sector_count: u16, + ) -> Result, TryFromIntError> { + // FIXME: make this an error + assert!(lba < 0xFFFFFFFFFFFF); + let byte_count = sector_count * SECTOR_SIZE; + // prepare PRD table let prd = PRDT_START as *mut PhysRegionDescriptor; unsafe { @@ -259,8 +272,7 @@ impl PciIde { .start_address() .as_u64() .try_into()?; - // we want to read 512 bytes - (*prd).byte_count = 512; + (*prd).byte_count = byte_count; // this is the end of table (*prd).eot = 1 << 7; // this byte is reserved, we should probably set it to 0 @@ -268,40 +280,42 @@ impl PciIde { } unsafe { - self.load_prdt(Channel::Primary); - self.stop(Channel::Primary); - self.set_read(Channel::Primary); - self.clear_bmi_status(Channel::Primary); - select_drive(Drive::Master, Channel::Primary); - set_lba(Channel::Primary, 0, 1); - ata_send_command(CMD_READ_DMA_EXT, Channel::Primary); - self.start(Channel::Primary); + self.load_prdt(channel); + self.stop(channel); + self.set_read(channel); + self.clear_bmi_status(channel); + select_drive(drive, channel); + set_lba(channel, lba, sector_count); + ata_send_command(CMD_READ_DMA_EXT, channel); + self.start(channel); + } - loop { - let status = self.bmi_status(Channel::Primary); - trace!("read status: 0b{status:b}"); + loop { + let status = unsafe { self.bmi_status(channel) }; - // Bit 2 (INT) set? - if (status >> 2) & 1 == 1 { - break; - } - } - - // FIXME: error handling - - // Stop DMA - self.stop(Channel::Primary); - - // Clear the interrupt bit - self.clear_bmi_status(Channel::Primary); - - for i in 0..512 { - let addr = (BUFFER_START + i) as *mut u8; - trace!("byte {i}: {}", *addr); + // Bit 2 (INT) set? + if (status >> 2) & 1 == 1 { + break; } } - Ok(()) + // FIXME: error handling + + unsafe { + // Stop DMA + self.stop(channel); + + // Clear the interrupt bit + self.clear_bmi_status(channel); + } + + let mut buffer = Vec::with_capacity(byte_count as usize); + for i in 0..512 { + let addr = (BUFFER_START + i) as *mut u8; + buffer.push(unsafe { *addr }); + } + + Ok(buffer) } pub fn device_info(&self) -> PciDeviceInfo { @@ -512,7 +526,7 @@ struct IdeDevice { } #[derive(Copy, Clone, Debug)] -enum Channel { +pub enum Channel { Primary, Secondary, } @@ -524,7 +538,7 @@ impl Channel { } #[derive(Copy, Clone, Debug)] -enum Drive { +pub enum Drive { Master, Slave, } diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 88886862..3d9f7394 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -6,6 +6,7 @@ use crate::arch::drivers::sysinfo::master; use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2}; +use crate::devices::pci::ide::{Channel, Drive}; use crate::devices::pci::{PciDevice, PCI_DEVICES}; use crate::filesystem; use crate::filesystem::vfs::VFS; @@ -113,7 +114,7 @@ pub fn scratchpad() { BANNER_WIDTH ); - let piix_ide_device = { + let pci_ide_device = { let pci_devices = PCI_DEVICES.lock(); pci_devices .iter() @@ -127,10 +128,15 @@ pub fn scratchpad() { }) .unwrap() }; - let mut piix_ide_device = piix_ide_device.lock(); - if let PciDevice::Ide(device) = &mut *piix_ide_device { - device.read().unwrap() + + { + let mut pci_ide_device = pci_ide_device.lock(); + if let PciDevice::Ide(device) = &mut *pci_ide_device { + let first_sector = device.read(Channel::Primary, Drive::Master, 0, 1).unwrap(); + trace!("IDE Primary/Master sector 0: {first_sector:?}"); + } } + real_shell(); } From 777888aae2a4bfcf051e0a84c2bf8b9a06990796 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Wed, 17 Aug 2022 15:10:00 +0300 Subject: [PATCH 17/18] IDE: Add LBA28 addressing support LBA28 is obsolete at this point, but we prefer to use it over LBA48 whenever we can because LBA28 is faster. --- ableos/src/devices/pci/ide.rs | 69 +++++++++++++++++++++++------------ ableos/src/scratchpad.rs | 3 +- qrcode-rust/src/bits.rs | 33 +++++------------ qrcode-rust/src/optimize.rs | 3 +- 4 files changed, 57 insertions(+), 51 deletions(-) diff --git a/ableos/src/devices/pci/ide.rs b/ableos/src/devices/pci/ide.rs index 63e59c2a..81576729 100644 --- a/ableos/src/devices/pci/ide.rs +++ b/ableos/src/devices/pci/ide.rs @@ -73,6 +73,9 @@ const ALT_STATUS_OFFSET: u16 = 2; /// ATA identification command const CMD_IDENTIFY: u8 = 0xEC; +/// ATA read using LBA28 DMA command +const CMD_READ_DMA: u8 = 0xC8; + /// ATA read using LBA48 DMA command const CMD_READ_DMA_EXT: u8 = 0x25; @@ -154,10 +157,8 @@ impl PciIde { continue; } - if (buffer[167] >> 2) & 1 != 1 { - // FIXME: 24-bit LBA and CHS support - error!("IDE drive {channel:?}/{drive:?} does not support 48-bit LBA"); - } + // FIXME: CHS support + let lba48 = (buffer[167] >> 2) & 1 == 1; let size = buffer[200] as u64 | (buffer[201] as u64) << 8 @@ -173,6 +174,7 @@ impl PciIde { channel, drive, size, + lba48_support: lba48, }); } } @@ -260,9 +262,19 @@ impl PciIde { drive: Drive, lba: u64, sector_count: u16, - ) -> Result, TryFromIntError> { + buffer: &mut Vec, + ) -> Result<(), TryFromIntError> { + let lba48_support = self + .ide_devices + .iter() + .find(|d| d.channel == channel && d.drive == drive) + .map(|d| d.lba48_support) + .unwrap(); // FIXME: make this an error + let lba48 = lba > 0xFFFFFFF && lba48_support; + // FIXME: make this an error - assert!(lba < 0xFFFFFFFFFFFF); + assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF)); + let byte_count = sector_count * SECTOR_SIZE; // prepare PRD table @@ -285,8 +297,14 @@ impl PciIde { self.set_read(channel); self.clear_bmi_status(channel); select_drive(drive, channel); - set_lba(channel, lba, sector_count); - ata_send_command(CMD_READ_DMA_EXT, channel); + set_lba(channel, lba, sector_count, lba48); + + if lba48 { + ata_send_command(CMD_READ_DMA_EXT, channel); + } else { + ata_send_command(CMD_READ_DMA, channel); + } + self.start(channel); } @@ -309,13 +327,12 @@ impl PciIde { self.clear_bmi_status(channel); } - let mut buffer = Vec::with_capacity(byte_count as usize); - for i in 0..512 { + for i in 0..byte_count as u64 { let addr = (BUFFER_START + i) as *mut u8; buffer.push(unsafe { *addr }); } - Ok(buffer) + Ok(()) } pub fn device_info(&self) -> PciDeviceInfo { @@ -474,30 +491,33 @@ unsafe fn ata_delay(channel: Channel) { } /// Set LBA and sector count registers. sector_count of 0 means 65536 sectors -unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16) { - // FIXME: CHS and LBA24 support - assert!(lba < 0xFFFFFFFFFFFF); - +unsafe fn set_lba(channel: Channel, lba: u64, sector_count: u16, lba48: bool) { let command_block = if channel.secondary() { SECONDARY_COMMAND } else { PRIMARY_COMMAND }; + let mut seccount = Port::new(command_block + SECCOUNT_OFFSET); let mut lba0 = Port::new(command_block + LBA0_OFFSET); let mut lba1 = Port::new(command_block + LBA1_OFFSET); let mut lba2 = Port::new(command_block + LBA2_OFFSET); + let mut head = Port::new(command_block + DRIVE_HEAD_OFFSET); + let head_value: u8 = head.read(); let lba_bytes = lba.to_le_bytes(); let sector_count_bytes = sector_count.to_le_bytes(); // write the new LBA & sector count registers - // if LBA48 { - seccount.write(sector_count_bytes[1]); - lba0.write(lba_bytes[3]); - lba1.write(lba_bytes[4]); - lba2.write(lba_bytes[5]); - // } + // FIXME: CHS support + if lba48 { + seccount.write(sector_count_bytes[1]); + lba0.write(lba_bytes[3]); + lba1.write(lba_bytes[4]); + lba2.write(lba_bytes[5]); + } else { + head.write(head_value | (lba_bytes[3] & 0x0F)); + } seccount.write(sector_count_bytes[0]); lba0.write(lba_bytes[0]); lba1.write(lba_bytes[1]); @@ -522,10 +542,11 @@ struct IdeDevice { pub channel: Channel, pub drive: Drive, pub size: u64, // in sectors - // FIXME: model + pub lba48_support: bool, + // FIXME: model } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Channel { Primary, Secondary, @@ -537,7 +558,7 @@ impl Channel { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Drive { Master, Slave, diff --git a/ableos/src/scratchpad.rs b/ableos/src/scratchpad.rs index 3d9f7394..dbe877a5 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -132,7 +132,8 @@ pub fn scratchpad() { { let mut pci_ide_device = pci_ide_device.lock(); if let PciDevice::Ide(device) = &mut *pci_ide_device { - let first_sector = device.read(Channel::Primary, Drive::Master, 0, 1).unwrap(); + let mut first_sector = Vec::with_capacity(512); + device.read(Channel::Primary, Drive::Master, 0, 1, &mut first_sector).unwrap(); trace!("IDE Primary/Master sector 0: {first_sector:?}"); } } diff --git a/qrcode-rust/src/bits.rs b/qrcode-rust/src/bits.rs index 1273626f..9cc951cc 100644 --- a/qrcode-rust/src/bits.rs +++ b/qrcode-rust/src/bits.rs @@ -135,14 +135,14 @@ fn test_push_number() { assert_eq!( bytes, vec![ - 0b0101_1010, // 90 + 0b0101_1010, // 90 0b1001_1010, // 154 - 0b1100_1011, // 203 - 0b0110_1101, // 109 - 0b01_1001_00, // 100 + 0b1100_1011, // 203 + 0b0110_1101, // 109 + 0b01_1001_00, // 100 0b0111_1001, // 121 - 0b0111_0001, // 113 - 0b1000_0000, // 128 + 0b0111_0001, // 113 + 0b1000_0000, // 128 ] ); } @@ -357,10 +357,7 @@ mod numeric_tests { fn test_iso_18004_2006_example_1() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_numeric_data(b"01234567"), Ok(())); - assert_eq!( - bits.into_bytes(), - vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000] - ); + assert_eq!(bits.into_bytes(), vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000]); } #[test] @@ -389,16 +386,7 @@ mod numeric_tests { assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); assert_eq!( bits.into_bytes(), - vec![ - 0b0010_0000, - 0b00000110, - 0b0010_1011, - 0b0011_0101, - 0b0011_0111, - 0b0000_1010, - 0b01110101, - 0b0010_1000, - ] + vec![0b0010_0000, 0b00000110, 0b0010_1011, 0b0011_0101, 0b0011_0111, 0b0000_1010, 0b01110101, 0b0010_1000,] ); } @@ -465,10 +453,7 @@ mod alphanumeric_tests { fn test_iso_18004_2006_example() { let mut bits = Bits::new(Version::Normal(1)); assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(())); - assert_eq!( - bits.into_bytes(), - vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000] - ); + assert_eq!(bits.into_bytes(), vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000]); } #[test] diff --git a/qrcode-rust/src/optimize.rs b/qrcode-rust/src/optimize.rs index 7a59c11e..1d3af2cf 100644 --- a/qrcode-rust/src/optimize.rs +++ b/qrcode-rust/src/optimize.rs @@ -1,7 +1,6 @@ //! Find the optimal data mode sequence to encode a piece of data. use crate::types::{Mode, Version}; - use core::slice::Iter; #[cfg(feature = "bench")] @@ -155,7 +154,7 @@ impl<'a> Iterator for Parser<'a> { #[cfg(test)] mod parse_tests { - use alloc::vec::{Vec}; + use alloc::vec::Vec; use crate::optimize::{Parser, Segment}; use crate::types::Mode; From d27b3bd93107d4eed0b864ecae358b459e5f7344 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Wed, 17 Aug 2022 17:19:27 +0300 Subject: [PATCH 18/18] IDE: Implement writing using Bus Mastering DMA --- ableos/src/devices/pci/ide.rs | 95 ++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/ableos/src/devices/pci/ide.rs b/ableos/src/devices/pci/ide.rs index 81576729..60a617e4 100644 --- a/ableos/src/devices/pci/ide.rs +++ b/ableos/src/devices/pci/ide.rs @@ -76,9 +76,15 @@ const CMD_IDENTIFY: u8 = 0xEC; /// ATA read using LBA28 DMA command const CMD_READ_DMA: u8 = 0xC8; +/// ATA write using LBA28 DMA command +const CMD_WRITE_DMA: u8 = 0xCA; + /// ATA read using LBA48 DMA command const CMD_READ_DMA_EXT: u8 = 0x25; +/// ATA write using LBA48 DMA command +const CMD_WRITE_DMA_EXT: u8 = 0x35; + pub struct PciIde { device_info: PciDeviceInfo, ide_devices: Vec, @@ -311,14 +317,14 @@ impl PciIde { loop { let status = unsafe { self.bmi_status(channel) }; + // FIXME: error handling + // Bit 2 (INT) set? if (status >> 2) & 1 == 1 { break; } } - // FIXME: error handling - unsafe { // Stop DMA self.stop(channel); @@ -335,6 +341,91 @@ impl PciIde { Ok(()) } + pub fn write( + &mut self, + channel: Channel, + drive: Drive, + lba: u64, + data: &[u8], + ) -> Result<(), TryFromIntError> { + // FIXME: make this an error + assert!(data.len() % SECTOR_SIZE as usize == 0); + + let lba48_support = self + .ide_devices + .iter() + .find(|d| d.channel == channel && d.drive == drive) + .map(|d| d.lba48_support) + .unwrap(); // FIXME: make this an error + let lba48 = lba > 0xFFFFFFF && lba48_support; + + // FIXME: make this an error + assert!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF)); + + let byte_count = data.len() as u16; + let sector_count = byte_count / SECTOR_SIZE; + + // prepare PRD table + let prd = PRDT_START as *mut PhysRegionDescriptor; + unsafe { + (*prd).data_buffer = self.buffer_frames.as_ref().unwrap()[0] + .start_address() + .as_u64() + .try_into()?; + (*prd).byte_count = byte_count; + // this is the end of table + (*prd).eot = 1 << 7; + // this byte is reserved, we should probably set it to 0 + (*prd)._0 = 0; + } + + // copy the data over to the DMA buffer + for i in 0..byte_count { + let addr = (BUFFER_START + i as u64) as *mut u8; + unsafe { + *addr = *data.get(i as usize).unwrap_or(&0); + } + } + + unsafe { + self.load_prdt(channel); + self.stop(channel); + self.set_write(channel); + self.clear_bmi_status(channel); + select_drive(drive, channel); + set_lba(channel, lba, sector_count, lba48); + + if lba48 { + ata_send_command(CMD_WRITE_DMA_EXT, channel); + } else { + ata_send_command(CMD_WRITE_DMA, channel); + } + + self.start(channel); + } + + loop { + let status = unsafe { self.bmi_status(channel) }; + + // FIXME: error handling + + // Bit 2 (INT) set? + if (status >> 2) & 1 == 1 { + break; + } + } + + unsafe { + // Stop DMA + self.stop(channel); + + // Clear the interrupt bit + self.clear_bmi_status(channel); + } + + Ok(()) + } + pub fn device_info(&self) -> PciDeviceInfo { self.device_info }