diff --git a/kernel/src/sys/kernel/cpu/x86_64/gdt.rs b/kernel/src/sys/kernel/cpu/x86_64/gdt.rs index 17fba1a..2a5c74d 100644 --- a/kernel/src/sys/kernel/cpu/x86_64/gdt.rs +++ b/kernel/src/sys/kernel/cpu/x86_64/gdt.rs @@ -46,8 +46,8 @@ lazy_static! { Selectors { code_selector, data_selector, - // user_code_selector, - // user_data_selector, + user_code_selector, + user_data_selector, tss_selector, } ) @@ -57,8 +57,8 @@ lazy_static! { struct Selectors { code_selector: SegmentSelector, data_selector: SegmentSelector, - // user_code_selector: SegmentSelector, - // user_data_selector: SegmentSelector, + user_code_selector: SegmentSelector, + user_data_selector: SegmentSelector, tss_selector: SegmentSelector, } @@ -72,8 +72,8 @@ pub fn init() { load_tss(GDT.1.tss_selector); // // Set up data segments - // DS::set_reg(GDT.1.data_selector); - // ES::set_reg(GDT.1.data_selector); + DS::set_reg(GDT.1.data_selector); + ES::set_reg(GDT.1.data_selector); SS::set_reg(GDT.1.data_selector); } } \ No newline at end of file diff --git a/kernel/src/sys/kernel/drivers/ahci/ahci.rs b/kernel/src/sys/kernel/drivers/ahci/ahci.rs new file mode 100644 index 0000000..df58f81 --- /dev/null +++ b/kernel/src/sys/kernel/drivers/ahci/ahci.rs @@ -0,0 +1,59 @@ +use x86_64::instructions::port::Port; + +use crate::println_log; + +use super::types::*; + +pub fn probe_port(abar: &HbaMem) { + let pi = abar.pi; + + for i in 0..32 { + if pi & 1 != 0 { + match check_type(&abar.ports[i]) { + PortSignature::Sata => { + println_log!("Found SATA port at {}", i); + }, + PortSignature::Semb => { + println_log!("Found SEMB port at {}", i); + }, + PortSignature::Pm => { + println_log!("Found PM port at {}", i); + }, + PortSignature::Satapi => { + println_log!("Found SATAPI port at {}", i); + }, + _ => { + println_log!("Unknown port type"); + } + } + } + } +} + +pub fn check_type(port: &HbaPort) -> PortSignature { + let ssts = port.ssts; + + let ipm: u8 = ((ssts >> 8) & 0x0F) as u8; + let det: u8 = (ssts & 0x01) as u8; + + if det != HBA_PORT_DET_PRESENT { + return PortSignature::Null; + } + + if ipm != HBA_PORT_IPM_ACTIVE { + return PortSignature::Null; + } + + return PortSignature::from(port.sig); +} + +pub fn start_cmd(port: &mut HbaPort) { + while port.cmd & HBA_PXCMD_CR != 0 {}; + + port.cmd |= HBA_PXCMD_FRE; + port.cmd |= HBA_PXCMD_ST; +} + +pub fn stop_cmd(port: &mut HbaPort) { + port.cmd &= !HBA_PXCMD_ST; +} \ No newline at end of file diff --git a/kernel/src/sys/kernel/drivers/ahci/mod.rs b/kernel/src/sys/kernel/drivers/ahci/mod.rs new file mode 100644 index 0000000..ae046d5 --- /dev/null +++ b/kernel/src/sys/kernel/drivers/ahci/mod.rs @@ -0,0 +1,3 @@ +pub mod ahci; + +mod types; \ No newline at end of file diff --git a/kernel/src/sys/kernel/drivers/ahci/types.rs b/kernel/src/sys/kernel/drivers/ahci/types.rs new file mode 100644 index 0000000..266da97 --- /dev/null +++ b/kernel/src/sys/kernel/drivers/ahci/types.rs @@ -0,0 +1,319 @@ + +#[repr(u32)] +pub enum DeviceSignature { + Ata = 0x00000101, + Atapi = 0xEB140101, + Semb = 0xC33C0101, + Pm = 0x96690101, + Invalid = 0x00000000, +} + +#[repr(u32)] +pub enum PortSignature { + Null = 0, + Sata = 1, + Semb = 2, + Pm = 3, + Satapi = 4, +} + +impl From for PortSignature { + fn from(value: u32) -> Self { + match value { + 0 => PortSignature::Null, + 1 => PortSignature::Sata, + 2 => PortSignature::Semb, + 3 => PortSignature::Pm, + 4 => PortSignature::Satapi, + _ => PortSignature::Null, + } + } +} + +// useful constants +pub const HBA_PORT_IPM_ACTIVE: u8 = 1; +pub const HBA_PORT_DET_PRESENT: u8 = 3; + +pub const HBA_PXCMD_ST: u32 = 0x0001; +pub const HBA_PXCMD_FRE: u32 = 0x0010; +pub const HBA_PXCMD_FR: u32 = 0x4000; +pub const HBA_PXCMD_CR: u32 = 0x8000; + + + +// Following code defines different kinds of FIS specified in Serial ATA Revision 3.0. +#[repr(u8)] +#[derive(Debug, Clone, Copy)] +pub enum FisType { + RegH2D = 0x27, // Register FIS - host to device + RegD2H = 0x34, // Register FIS - device to host + DmaAct = 0x39, // DMA activate FIS - device to host + DmaSetup = 0x41, // DMA setup FIS - bidirectional + Data = 0x46, // Data FIS - bidirectional + Bist = 0x58, // BIST activate FIS - bidirectional + PioSetup = 0x5F, // PIO setup FIS - device to host + DevBits = 0xA1, // Set device bits FIS - device to host +} + +// A host to device register FIS is used by the host to send command or control to a device. +// It contains IDE registers such as command, LBA, device, feature, count and control. +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct FisRegH2D { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_REG_H2D + pub pmport_c: u8, // Port multiplier [7:4], Reserved [3:1], Command[0] + pub command: u8, // Command register + pub featurel: u8, // Feature register, 7:0 + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + pub featureh: u8, // Feature register, 15:8 + + // DWORD 3 + pub countl: u8, // Count register, 7:0 + pub counth: u8, // Count register, 15:8 + pub icc: u8, // Isochronous command completion + pub control: u8, // Control register + + // DWORD 4 + pub rsv1: [u8; 4], // Reserved +} + +// A device to host register FIS is used by the device to notify the host +// that some ATA register has changed. +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct FisRegD2H { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_REG_D2H + pub pmport_i: u8, // Port multiplier [7:4], Reserved [3:2], Interrupt [1], Reserved [0] + pub status: u8, // Status register + pub error: u8, // Error register + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + pub rsv2: u8, // Reserved + + // DWORD 3 + pub countl: u8, // Count register, 7:0 + pub counth: u8, // Count register, 15:8 + pub rsv3: [u8; 2], // Reserved + + // DWORD 4 + pub rsv4: [u8; 4], // Reserved +} + +// This FIS is used by the host or device to send data payload. +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct FisData { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_DATA + pub pmport: u8, // Port multiplier [7:4], Reserved [3:0] + pub rsv1: [u8; 2], // Reserved + + // DWORD 1 ~ N + pub data: [u32; 1], // Payload +} + +// This FIS is used by the device to tell the host that it's about to send +// or ready to receive a PIO data payload. +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct FisPioSetup { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_PIO_SETUP + pub pmport_flags: u8, // Port multiplier [7:4], Reserved [3], Data transfer direction [2], Interrupt [1], Reserved [0] + pub status: u8, // Status register + pub error: u8, // Error register + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + pub rsv2: u8, // Reserved + + // DWORD 3 + pub countl: u8, // Count register, 7:0 + pub counth: u8, // Count register, 15:8 + pub rsv3: u8, // Reserved + pub e_status: u8, // New value of status register + + // DWORD 4 + pub tc: u16, // Transfer count + pub rsv4: [u8; 2], // Reserved +} + +// DMA Setup - Device to Host +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub struct FisDmaSetup { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_DMA_SETUP + pub pmport_flags: u8, // Port multiplier [7:4], Reserved [3], Data transfer direction [2], Interrupt [1], Auto-activate [0] + pub rsved: [u8; 2], // Reserved + + // DWORD 1&2 + pub dma_buffer_id: u64, // DMA Buffer Identifier + + // DWORD 3 + pub rsvd: u32, // More reserved + + // DWORD 4 + pub dma_buf_offset: u32, // Byte offset into buffer. First 2 bits must be 0 + + // DWORD 5 + pub transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0 + + // DWORD 6 + pub resvd: u32, // Reserved +} + +// HBA Memory Registers Structure +#[repr(C)] +#[derive(Debug)] +pub struct HbaMem { + // 0x00 - 0x2B, Generic Host Control + pub cap: u32, // 0x00, Host capability + pub ghc: u32, // 0x04, Global host control + pub is: u32, // 0x08, Interrupt status + pub pi: u32, // 0x0C, Port implemented + pub vs: u32, // 0x10, Version + pub ccc_ctl: u32, // 0x14, Command completion coalescing control + pub ccc_pts: u32, // 0x18, Command completion coalescing ports + pub em_loc: u32, // 0x1C, Enclosure management location + pub em_ctl: u32, // 0x20, Enclosure management control + pub cap2: u32, // 0x24, Host capabilities extended + pub bohc: u32, // 0x28, BIOS/OS handoff control and status + + // 0x2C - 0x9F, Reserved + pub rsv: [u8; 0xA0-0x2C], + + // 0xA0 - 0xFF, Vendor specific registers + pub vendor: [u8; 0x100-0xA0], + + // 0x100 - 0x10FF, Port control registers + pub ports: [HbaPort; 1], // 1 ~ 32 +} + +// HBA Port Structure +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct HbaPort { + pub clb: u32, // 0x00, command list base address, 1K-byte aligned + pub clbu: u32, // 0x04, command list base address upper 32 bits + pub fb: u32, // 0x08, FIS base address, 256-byte aligned + pub fbu: u32, // 0x0C, FIS base address upper 32 bits + pub is: u32, // 0x10, interrupt status + pub ie: u32, // 0x14, interrupt enable + pub cmd: u32, // 0x18, command and status + pub rsv0: u32, // 0x1C, Reserved + pub tfd: u32, // 0x20, task file data + pub sig: u32, // 0x24, signature + pub ssts: u32, // 0x28, SATA status (SCR0:SStatus) + pub sctl: u32, // 0x2C, SATA control (SCR2:SControl) + pub serr: u32, // 0x30, SATA error (SCR1:SError) + pub sact: u32, // 0x34, SATA active (SCR3:SActive) + pub ci: u32, // 0x38, command issue + pub sntf: u32, // 0x3C, SATA notification (SCR4:SNotification) + pub fbs: u32, // 0x40, FIS-based switch control + pub rsv1: [u32; 11], // 0x44 ~ 0x6F, Reserved + pub vendor: [u32; 4], // 0x70 ~ 0x7F, vendor specific +} + +// HBA FIS Structure +#[repr(C)] +#[derive(Debug)] +pub struct HbaFis { + // 0x00 + pub dsfis: FisDmaSetup, // DMA Setup FIS + pub pad0: [u8; 4], + + // 0x20 + pub psfis: FisPioSetup, // PIO Setup FIS + pub pad1: [u8; 12], + + // 0x40 + pub rfis: FisRegD2H, // Register – Device to Host FIS + pub pad2: [u8; 4], + + // 0x58 + pub sdbfis: [u8; 8], // Set Device Bit FIS + + // 0x60 + pub ufis: [u8; 64], + + // 0xA0 + pub rsv: [u8; 0x100-0xA0], +} + +// Command List Structure +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct HbaCmdHeader { + // DW0 + pub flags: u16, // Command FIS length and flags + pub prdtl: u16, // Physical region descriptor table length in entries + + // DW1 + pub prdbc: u32, // Physical region descriptor byte count transferred + + // DW2, 3 + pub ctba: u32, // Command table descriptor base address + pub ctbau: u32, // Command table descriptor base address upper 32 bits + + // DW4 - 7 + pub rsv1: [u32; 4], // Reserved +} + +// Command Table Structure +#[repr(C)] +#[derive(Debug)] +pub struct HbaCmdTbl { + // 0x00 + pub cfis: [u8; 64], // Command FIS + + // 0x40 + pub acmd: [u8; 16], // ATAPI command, 12 or 16 bytes + + // 0x50 + pub rsv: [u8; 48], // Reserved + + // 0x80 + pub prdt_entry: [HbaPrdtEntry; 1], // Physical region descriptor table entries, 0 ~ 65535 +} + +// Physical Region Descriptor Table Entry +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct HbaPrdtEntry { + pub dba: u32, // Data base address + pub dbau: u32, // Data base address upper 32 bits + pub rsv0: u32, // Reserved + + // DW3 + pub dbc_and_flags: u32, // Byte count and flags +} \ No newline at end of file diff --git a/kernel/src/sys/kernel/drivers/mod.rs b/kernel/src/sys/kernel/drivers/mod.rs index eccb8aa..b1ae8f5 100644 --- a/kernel/src/sys/kernel/drivers/mod.rs +++ b/kernel/src/sys/kernel/drivers/mod.rs @@ -1,2 +1,3 @@ pub mod framebuffer; -pub mod serial; \ No newline at end of file +pub mod serial; +pub mod ahci; \ No newline at end of file