diff --git a/Cargo.lock b/Cargo.lock index d6861c6a..3a0df9f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,7 @@ dependencies = [ "rdrand", "riscv", "rkyv", + "seq-macro", "serde", "spin 0.9.4", "toml", @@ -65,7 +66,6 @@ dependencies = [ "wasmi", "watson", "x86_64", - "x86_ata", "y-compositor-protocol", ] @@ -649,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" @@ -879,18 +885,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..5c0639f4 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 = [ @@ -72,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" @@ -148,7 +154,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/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index 7ae3d3ec..803af1a3 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; @@ -10,6 +10,7 @@ use crate::{arch::gdt, 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 +31,9 @@ pub enum InterruptIndex { /// Mouse offset Mouse = 44, + /// Disk offset + Disk = 46, + // SecondInterrupt = PIC_2_OFFSET, Cmos = 0x70, } @@ -47,9 +51,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 +72,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/arch/x86_64/memory.rs b/ableos/src/arch/x86_64/memory.rs index 338daae0..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, + FrameAllocator, FrameDeallocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, + Size4KiB, }, PhysAddr, VirtAddr, }; @@ -109,3 +110,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/arch/x86_64/mod.rs b/ableos/src/arch/x86_64/mod.rs index ce008fa9..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; @@ -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/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..ea102d6a 100644 --- a/ableos/src/devices/mod.rs +++ b/ableos/src/devices/mod.rs @@ -3,14 +3,13 @@ mod dev_vterm; pub mod id; pub mod pci; -pub mod pci_inner; 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 +18,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/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..e9469ef0 --- /dev/null +++ b/ableos/src/devices/pci/device.rs @@ -0,0 +1,194 @@ +/* + * 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, *}, + PciClass, PciFullClass, +}; + +// FIXME: Unknown class +pub const S3_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(Copy, 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.read(0, 0x10 + bar * 4) } + } + + /// Get the interrupt pin + pub fn interrupt_pin(&self) -> u8 { + let last_row = unsafe { self.read(0, 0x3C) }; + ((last_row >> 8) & 0xFF) as u8 + } + + /// 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) + } +} + +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(Copy, Clone, Debug, PartialEq, Eq)] +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_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_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); + + 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_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() +} + +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 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/devices.rs b/ableos/src/devices/pci/devices.rs deleted file mode 100644 index a10f97f4..00000000 --- a/ableos/src/devices/pci/devices.rs +++ /dev/null @@ -1,20 +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 } - } -} - -pub const VMWARE_SVGA2: DeviceID = DeviceID::new(VMware, 0x0405); -pub const S3INC_TRIO64V2: DeviceID = DeviceID::new(S3Inc, 0x8900); diff --git a/ableos/src/devices/pci/ide.rs b/ableos/src/devices/pci/ide.rs new file mode 100644 index 00000000..60a617e4 --- /dev/null +++ b/ableos/src/devices/pci/ide.rs @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ + +use core::num::TryFromIntError; + +// FIXME: platform agnostic-ify these +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; +use crate::devices::pci::check_device; + +use super::PciDeviceInfo; + +// FIXME: un-hardcode these +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 +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; + +/// Primary command block offset +const PRIMARY_COMMAND: u16 = 0x01F0; + +/// Secondary command block offset +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; + +/// 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; + +/// 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, + prdt_frame: Option, + buffer_frames: Option>, + bmiba: u16, +} + +impl PciIde { + // FIXME: make this return a Result + pub fn new(bus: u8, device: u8) -> Option { + let device_info = check_device(bus, device)?; + 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 + + 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); + // 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 + } + + 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; + } + } + + // 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; + } + + // FIXME: CHS support + let lba48 = (buffer[167] >> 2) & 1 == 1; + + 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, + lba48_support: lba48, + }); + } + } + } + + let bmiba = device_info.bar(4) & 0xFFFFFFFC; + + Some(Self { + device_info, + ide_devices, + prdt_frame: None, + buffer_frames: None, + bmiba: bmiba.try_into().ok()?, + }) + } + + pub fn allocate_dma_frame( + &mut self, + mapper: &mut impl Mapper, + 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 { + 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, + flags, + frame_allocator, + )? + .flush() + } + } + + self.prdt_frame = Some(prdt_frame); + self.buffer_frames = Some(buffer_frames); + Ok(()) + } + + pub fn read( + &mut self, + channel: Channel, + drive: Drive, + lba: u64, + sector_count: u16, + 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!((lba48 && lba > 0xFFFFFFF) || (!lba48 && lba <= 0xFFFFFFF)); + + let byte_count = sector_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; + } + + unsafe { + 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, lba48); + + if lba48 { + ata_send_command(CMD_READ_DMA_EXT, channel); + } else { + ata_send_command(CMD_READ_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); + } + + for i in 0..byte_count as u64 { + let addr = (BUFFER_START + i) as *mut u8; + buffer.push(unsafe { *addr }); + } + + 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 + } + + 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 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 + } else { + 0 + } + self.bmiba + + BMIC_OFFSET; + let mut port: Port = Port::new(addr); + let mut bmic = port.read(); + // stop ongoing transfer + bmic &= !1; + // write the new bmic + port.write(bmic); + } + + unsafe fn set_read(&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(); + // mark bit 3 as 0 (read) + bmic &= !(1 << 3); + // write the new bmic + port.write(bmic); + } + + unsafe fn set_write(&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(); + // mark bit 3 as 1 (write) + bmic |= 1 << 3; + // write the new bmic + port.write(bmic); + } + + 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 { + 0 + } + self.bmiba + + BMIS_OFFSET; + 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; + // write the new 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 mut port: Port = Port::new(addr); + // FIXME: CHS support + let drive_command = if drive.slave() { + // slave & LBA + 0b11110000 + } else { + // master & LBA + 0b11100000 + }; + + // 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 mut 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 mut port: Port = Port::new(addr); + for _ in 0..14 { + port.read(); + } +} + +/// Set LBA and sector count registers. sector_count of 0 means 65536 sectors +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 + // 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]); + 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(|| { + asm!(" + cld + repne + insd", + in("di") buffer, + in("dx") port, + inout("cx") count, + ) + }); +} + +struct IdeDevice { + pub channel: Channel, + pub drive: Drive, + pub size: u64, // in sectors + pub lba48_support: bool, + // FIXME: model +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Channel { + Primary, + Secondary, +} + +impl Channel { + fn secondary(&self) -> bool { + matches!(self, Self::Secondary) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Drive { + Master, + Slave, +} + +impl Drive { + fn slave(&self) -> bool { + matches!(self, Self::Slave) + } +} + +#[repr(C, packed)] +struct PhysRegionDescriptor { + /// Pointer to the data buffer + pub data_buffer: u32, + /// Byte count, 64K maximum per PRD transfer. 0 means 64K + pub byte_count: u16, + /// Reserved byte + pub _0: u8, + /// MSB marks end of transfer + pub eot: u8, +} diff --git a/ableos/src/devices/pci/mod.rs b/ableos/src/devices/pci/mod.rs index 1afb0c27..12d18d08 100644 --- a/ableos/src/devices/pci/mod.rs +++ b/ableos/src/devices/pci/mod.rs @@ -1,212 +1,71 @@ -// 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 ide; -use self::devices::DeviceID; +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}; -// PciDeviceInfo /////////////////////////////////////////////////////////////// +use crate::arch::memory::BootInfoFrameAllocator; -#[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 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) - } -} -impl Display for PciDeviceInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { - let vendor_name = &self.device_id.vendor; - writeln!( - f, - "Device {} | Bus {:X} | Vendor: {}", - self.device, self.bus, vendor_name - )?; - writeln!(f, "{}", self.full_class)?; - writeln!(f, " Header type: {: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(()) - } +// MassStorage_IDE (0x0101) +use self::ide::PciIde; + +lazy_static! { + pub static ref PCI_DEVICES: Mutex>>> = Default::default(); } -// 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 +#[non_exhaustive] +pub enum PciDevice { + Ide(PciIde), + // Variant so that we aren't about irrefutable if-let patterns + // FIXME: remove as soon as we have other variants + _0, } -// Internal functions ////////////////////////////////////////////////////////// +/// 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 + S3_TRIO64V2 => {} -fn check_device(bus: u8, device: u8) -> Option { - assert!(device < 32); - let function = 0u8; + // MassStorage_IDE (0x0101) + 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 (device_id, vendor_id) = get_ids(bus, device, function); - if vendor_id == 0xFFFF { - // Device doesn't exist - return None; - } + 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::Ide(ide)))); + } - 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 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; + // Display_VGA (0x0300) + VMWARE_SVGA2 => {} + _ => { + trace!("Unknown PCI device {device} on bus {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, - 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/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 793074f9..00000000 --- a/ableos/src/devices/pci/support.rs +++ /dev/null @@ -1,15 +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 { - VMWARE_SVGA2 => true, - S3INC_TRIO64V2 => true, - _ => false, - } -} diff --git a/ableos/src/devices/pci/vendors.rs b/ableos/src/devices/pci/vendors.rs index 04454c53..486b32a4 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)] +#[derive(PartialEq, Debug, Copy, 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/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/kmain.rs b/ableos/src/kmain.rs index 0115208a..5bf23c6c 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -8,21 +8,26 @@ use core::sync::atomic::AtomicU64; +use crate::arch::memory::BootInfoFrameAllocator; use crate::arch::{drivers::sysinfo::master, init, sloop}; +use crate::devices::pci; 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; +// FIXME: platform agnostic paging stuff +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); /// The main entry point of the kernel -#[no_mangle] -pub fn kernel_main() -> ! { +pub fn kernel_main( + mut mapper: impl Mapper, + mut frame_allocator: BootInfoFrameAllocator, +) -> ! { init::init(); // /* @@ -39,6 +44,8 @@ pub fn kernel_main() -> ! { // term.draw_term(); // drop(term); + pci::init(&mut mapper, &mut frame_allocator); + x86_64::instructions::interrupts::without_interrupts(|| { hardware::init_mouse(); }); 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 2ce80e70..dbe877a5 100644 --- a/ableos/src/scratchpad.rs +++ b/ableos/src/scratchpad.rs @@ -6,17 +6,14 @@ 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::devices::pci::ide::{Channel, Drive}; +use crate::devices::pci::{PciDevice, PCI_DEVICES}; use crate::filesystem; 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}; @@ -77,9 +74,6 @@ pub fn scratchpad() { // } // bruh(); - for x in brute_force_scan() { - println!("{}", x); - } disable(); let tick_time = fetch_time(); @@ -120,6 +114,30 @@ pub fn scratchpad() { BANNER_WIDTH ); + let pci_ide_device = { + let pci_devices = PCI_DEVICES.lock(); + pci_devices + .iter() + .find_map(|device_ref| { + let device = device_ref.lock(); + if let PciDevice::Ide(_) = &*device { + Some(device_ref.clone()) + } else { + None + } + }) + .unwrap() + }; + + { + let mut pci_ide_device = pci_ide_device.lock(); + if let PciDevice::Ide(device) = &mut *pci_ide_device { + 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:?}"); + } + } + real_shell(); } @@ -236,7 +254,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 +326,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() { 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/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/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; 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; 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}; 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(()) -}