1#![allow(dead_code)]
12
13#[cfg(feature = "alloc")]
14extern crate alloc;
15
16#[cfg(feature = "alloc")]
17use alloc::{string::String, vec::Vec};
18use core::sync::atomic::{AtomicBool, Ordering};
19
20use crate::error::KernelError;
21#[cfg(feature = "alloc")]
22use crate::fs::blockdev::BlockDevice;
23
24const PCI_CLASS_MASS_STORAGE: u8 = 0x01;
30
31const PCI_SUBCLASS_SATA: u8 = 0x06;
33
34const PCI_PROGIF_AHCI: u8 = 0x01;
36
37const HBA_REG_CAP: usize = 0x00;
43
44const HBA_REG_GHC: usize = 0x04;
46
47const HBA_REG_IS: usize = 0x08;
49
50const HBA_REG_PI: usize = 0x0C;
52
53const HBA_REG_VS: usize = 0x10;
55
56const HBA_REG_CCC_CTL: usize = 0x14;
58
59const HBA_REG_CCC_PORTS: usize = 0x18;
61
62const HBA_REG_EM_LOC: usize = 0x1C;
64
65const HBA_REG_EM_CTL: usize = 0x20;
67
68const HBA_REG_CAP2: usize = 0x24;
70
71const HBA_REG_BOHC: usize = 0x28;
73
74const GHC_HR: u32 = 1 << 0;
80
81const GHC_IE: u32 = 1 << 1;
83
84const GHC_AE: u32 = 1 << 31;
86
87const CAP_NP_MASK: u32 = 0x1F;
93
94const CAP_SNCQ: u32 = 1 << 30;
96
97const CAP_S64A: u32 = 1 << 31;
99
100const CAP_NCS_SHIFT: u32 = 8;
102const CAP_NCS_MASK: u32 = 0x1F;
103
104const PORT_BASE: usize = 0x100;
109const PORT_SIZE: usize = 0x80;
110
111const PORT_CLB: usize = 0x00;
113
114const PORT_CLBU: usize = 0x04;
116
117const PORT_FB: usize = 0x08;
119
120const PORT_FBU: usize = 0x0C;
122
123const PORT_IS: usize = 0x10;
125
126const PORT_IE: usize = 0x14;
128
129const PORT_CMD: usize = 0x18;
131
132const PORT_TFD: usize = 0x20;
134
135const PORT_SIG: usize = 0x24;
137
138const PORT_SSTS: usize = 0x28;
140
141const PORT_SCTL: usize = 0x2C;
143
144const PORT_SERR: usize = 0x30;
146
147const PORT_SACT: usize = 0x34;
149
150const PORT_CI: usize = 0x38;
152
153const PORT_CMD_ST: u32 = 1 << 0;
159
160const PORT_CMD_SUD: u32 = 1 << 1;
162
163const PORT_CMD_POD: u32 = 1 << 2;
165
166const PORT_CMD_FRE: u32 = 1 << 4;
168
169const PORT_CMD_FR: u32 = 1 << 14;
171
172const PORT_CMD_CR: u32 = 1 << 15;
174
175const TFD_BSY: u32 = 1 << 7;
181
182const TFD_DRQ: u32 = 1 << 3;
184
185const TFD_ERR: u32 = 1 << 0;
187
188const SSTS_DET_MASK: u32 = 0x0F;
194
195const SSTS_DET_PRESENT: u32 = 0x03;
197
198const SSTS_IPM_MASK: u32 = 0x0F00;
200
201const SSTS_IPM_ACTIVE: u32 = 0x0100;
203
204const SIG_SATA: u32 = 0x00000101;
210
211const SIG_SATAPI: u32 = 0xEB140101;
213
214const SIG_SEMB: u32 = 0xC33C0101;
216
217const SIG_PM: u32 = 0x96690101;
219
220const FIS_TYPE_REG_H2D: u8 = 0x27;
226
227const FIS_TYPE_REG_D2H: u8 = 0x34;
229
230const FIS_TYPE_DMA_ACT: u8 = 0x39;
232
233const FIS_TYPE_DMA_SETUP: u8 = 0x41;
235
236const FIS_TYPE_DATA: u8 = 0x46;
238
239const FIS_TYPE_BIST: u8 = 0x58;
241
242const FIS_TYPE_PIO_SETUP: u8 = 0x5F;
244
245const FIS_TYPE_DEV_BITS: u8 = 0xA1;
247
248const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
254
255const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35;
257
258const ATA_CMD_IDENTIFY: u8 = 0xEC;
260
261const ATA_CMD_READ_FPDMA_QUEUED: u8 = 0x60;
263
264const ATA_CMD_WRITE_FPDMA_QUEUED: u8 = 0x61;
266
267const ATA_CMD_FLUSH_CACHE_EXT: u8 = 0xEA;
269
270const SECTOR_SIZE: usize = 512;
276
277const MAX_PRDT_ENTRIES: usize = 65535;
279
280const MAX_SECTORS_PER_PRDT: u32 = 8192;
282
283const POLL_TIMEOUT: u32 = 1_000_000;
285
286#[repr(C, packed)]
292#[derive(Debug, Clone, Copy)]
293pub struct FisRegH2D {
294 pub fis_type: u8,
296 pub pm_and_c: u8,
298 pub command: u8,
300 pub feature_lo: u8,
302
303 pub lba0: u8,
305 pub lba1: u8,
307 pub lba2: u8,
309 pub device: u8,
311
312 pub lba3: u8,
314 pub lba4: u8,
316 pub lba5: u8,
318 pub feature_hi: u8,
320
321 pub count_lo: u8,
323 pub count_hi: u8,
325 pub icc: u8,
327 pub control: u8,
329
330 pub _reserved: [u8; 4],
332}
333
334impl Default for FisRegH2D {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340impl FisRegH2D {
341 pub fn new() -> Self {
343 Self {
344 fis_type: FIS_TYPE_REG_H2D,
345 pm_and_c: 0x80, command: 0,
347 feature_lo: 0,
348 lba0: 0,
349 lba1: 0,
350 lba2: 0,
351 device: 0,
352 lba3: 0,
353 lba4: 0,
354 lba5: 0,
355 feature_hi: 0,
356 count_lo: 0,
357 count_hi: 0,
358 icc: 0,
359 control: 0,
360 _reserved: [0; 4],
361 }
362 }
363
364 pub fn set_lba(&mut self, lba: u64) {
366 self.lba0 = (lba & 0xFF) as u8;
367 self.lba1 = ((lba >> 8) & 0xFF) as u8;
368 self.lba2 = ((lba >> 16) & 0xFF) as u8;
369 self.lba3 = ((lba >> 24) & 0xFF) as u8;
370 self.lba4 = ((lba >> 32) & 0xFF) as u8;
371 self.lba5 = ((lba >> 40) & 0xFF) as u8;
372 self.device = 1 << 6; }
374
375 pub fn set_count(&mut self, count: u16) {
377 self.count_lo = (count & 0xFF) as u8;
378 self.count_hi = ((count >> 8) & 0xFF) as u8;
379 }
380}
381
382#[repr(C, packed)]
384#[derive(Debug, Clone, Copy)]
385pub struct FisRegD2H {
386 pub fis_type: u8,
388 pub pm_and_i: u8,
390 pub status: u8,
392 pub error: u8,
394
395 pub lba0: u8,
397 pub lba1: u8,
399 pub lba2: u8,
401 pub device: u8,
403
404 pub lba3: u8,
406 pub lba4: u8,
408 pub lba5: u8,
410 pub _reserved0: u8,
412
413 pub count_lo: u8,
415 pub count_hi: u8,
417 pub _reserved1: [u8; 6],
419}
420
421#[repr(C, packed)]
423#[derive(Debug, Clone, Copy)]
424pub struct FisDmaSetup {
425 pub fis_type: u8,
427 pub flags: u8,
429 pub _reserved0: [u8; 2],
431
432 pub dma_buf_id_lo: u32,
434 pub dma_buf_id_hi: u32,
436
437 pub _reserved1: u32,
439 pub dma_buf_offset: u32,
441 pub transfer_count: u32,
443 pub _reserved2: u32,
445}
446
447#[repr(C, packed)]
449#[derive(Debug, Clone, Copy)]
450pub struct FisPioSetup {
451 pub fis_type: u8,
453 pub flags: u8,
455 pub status: u8,
457 pub error: u8,
459
460 pub lba0: u8,
462 pub lba1: u8,
464 pub lba2: u8,
466 pub device: u8,
468
469 pub lba3: u8,
471 pub lba4: u8,
473 pub lba5: u8,
475 pub _reserved0: u8,
477
478 pub count_lo: u8,
480 pub count_hi: u8,
482 pub _reserved1: u8,
484 pub e_status: u8,
486
487 pub transfer_count: u16,
489 pub _reserved2: [u8; 2],
491}
492
493#[repr(C, packed)]
495#[derive(Debug, Clone, Copy)]
496pub struct FisData {
497 pub fis_type: u8,
499 pub pm: u8,
501 pub _reserved: [u8; 2],
503 }
505
506#[repr(C, align(256))]
512#[derive(Debug, Clone, Copy)]
513pub struct ReceivedFis {
514 pub dma_setup: FisDmaSetup,
516 pub _pad0: [u8; 4],
518
519 pub pio_setup: FisPioSetup,
521 pub _pad1: [u8; 12],
523
524 pub d2h_reg: FisRegD2H,
526 pub _pad2: [u8; 4],
528
529 pub set_device_bits: [u8; 8],
531
532 pub unknown: [u8; 64],
534
535 pub _reserved: [u8; 96],
537}
538
539#[repr(C)]
545#[derive(Debug, Clone, Copy)]
546pub struct PrdtEntry {
547 pub data_base_lo: u32,
549 pub data_base_hi: u32,
551 pub _reserved: u32,
553 pub dbc_and_flags: u32,
556}
557
558impl PrdtEntry {
559 pub fn new(phys_addr: u64, byte_count: u32, interrupt: bool) -> Self {
565 let mut dbc = (byte_count - 1) & 0x003F_FFFF; if interrupt {
567 dbc |= 1 << 31;
568 }
569 Self {
570 data_base_lo: phys_addr as u32,
571 data_base_hi: (phys_addr >> 32) as u32,
572 _reserved: 0,
573 dbc_and_flags: dbc,
574 }
575 }
576}
577
578#[repr(C)]
582#[derive(Debug, Clone, Copy)]
583pub struct CommandHeader {
584 pub flags_and_prdtl: u32,
589 pub prdbc: u32,
591 pub ctba_lo: u32,
594 pub ctba_hi: u32,
596 pub _reserved: [u32; 4],
598}
599
600impl CommandHeader {
601 pub fn new(fis_len_dwords: u8, prdt_count: u16, write: bool, ctba_phys: u64) -> Self {
608 let mut flags = (fis_len_dwords as u32) & 0x1F;
609 if write {
610 flags |= 1 << 6; }
612 flags |= (prdt_count as u32) << 16;
613
614 Self {
615 flags_and_prdtl: flags,
616 prdbc: 0,
617 ctba_lo: ctba_phys as u32,
618 ctba_hi: (ctba_phys >> 32) as u32,
619 _reserved: [0; 4],
620 }
621 }
622}
623
624#[repr(C)]
629#[derive(Debug, Clone, Copy)]
630pub struct CommandTableHeader {
631 pub cfis: [u8; 64],
633 pub acmd: [u8; 16],
635 pub _reserved: [u8; 48],
637 }
639
640impl Default for CommandTableHeader {
641 fn default() -> Self {
642 Self::new()
643 }
644}
645
646impl CommandTableHeader {
647 pub fn new() -> Self {
649 Self {
650 cfis: [0; 64],
651 acmd: [0; 16],
652 _reserved: [0; 48],
653 }
654 }
655
656 pub fn set_h2d_fis(&mut self, fis: &FisRegH2D) {
658 let fis_bytes =
659 unsafe { core::slice::from_raw_parts(fis as *const FisRegH2D as *const u8, 20) };
660 self.cfis[..20].copy_from_slice(fis_bytes);
661 }
662}
663
664#[derive(Debug, Clone, Copy, PartialEq, Eq)]
670pub enum AhciDeviceType {
671 None,
673 Sata,
675 Satapi,
677 Semb,
679 PortMultiplier,
681 Unknown(u32),
683}
684
685impl AhciDeviceType {
686 pub fn from_signature(sig: u32) -> Self {
688 match sig {
689 SIG_SATA => Self::Sata,
690 SIG_SATAPI => Self::Satapi,
691 SIG_SEMB => Self::Semb,
692 SIG_PM => Self::PortMultiplier,
693 0xFFFFFFFF | 0x00000000 => Self::None,
694 other => Self::Unknown(other),
695 }
696 }
697}
698
699#[derive(Debug, Clone, Copy, PartialEq, Eq)]
705pub enum PortState {
706 Inactive,
708 Detected,
710 Ready,
712 Error,
714}
715
716#[derive(Debug, Clone, Copy)]
722pub struct AhciPort {
723 pub port_num: u8,
725 pub port_mmio_base: usize,
727 pub device_type: AhciDeviceType,
729 pub state: PortState,
731 pub num_cmd_slots: u8,
733 pub ncq_supported: bool,
735 pub total_sectors: u64,
737 pub sector_size: usize,
739}
740
741impl AhciPort {
742 pub fn new(port_num: u8, hba_mmio_base: usize, num_cmd_slots: u8, ncq_supported: bool) -> Self {
744 Self {
745 port_num,
746 port_mmio_base: hba_mmio_base + PORT_BASE + (port_num as usize) * PORT_SIZE,
747 device_type: AhciDeviceType::None,
748 state: PortState::Inactive,
749 num_cmd_slots,
750 ncq_supported,
751 total_sectors: 0,
752 sector_size: SECTOR_SIZE,
753 }
754 }
755
756 fn read_port_reg(&self, offset: usize) -> u32 {
758 unsafe { core::ptr::read_volatile((self.port_mmio_base + offset) as *const u32) }
762 }
763
764 fn write_port_reg(&self, offset: usize, value: u32) {
766 unsafe { core::ptr::write_volatile((self.port_mmio_base + offset) as *mut u32, value) }
769 }
770
771 pub fn detect_device(&mut self) {
773 let ssts = self.read_port_reg(PORT_SSTS);
774 let det = ssts & SSTS_DET_MASK;
775 let ipm = ssts & SSTS_IPM_MASK;
776
777 if det != SSTS_DET_PRESENT || ipm != SSTS_IPM_ACTIVE {
778 self.device_type = AhciDeviceType::None;
779 self.state = PortState::Inactive;
780 return;
781 }
782
783 let sig = self.read_port_reg(PORT_SIG);
784 self.device_type = AhciDeviceType::from_signature(sig);
785 self.state = PortState::Detected;
786 }
787
788 pub fn stop_cmd(&self) -> Result<(), KernelError> {
791 let mut cmd = self.read_port_reg(PORT_CMD);
792
793 cmd &= !PORT_CMD_ST;
795 self.write_port_reg(PORT_CMD, cmd);
796
797 let mut timeout = POLL_TIMEOUT;
799 while self.read_port_reg(PORT_CMD) & PORT_CMD_CR != 0 && timeout > 0 {
800 timeout -= 1;
801 core::hint::spin_loop();
802 }
803 if timeout == 0 {
804 return Err(KernelError::Timeout {
805 operation: "ahci_stop_cmd_cr",
806 duration_ms: 0,
807 });
808 }
809
810 cmd = self.read_port_reg(PORT_CMD);
812 cmd &= !PORT_CMD_FRE;
813 self.write_port_reg(PORT_CMD, cmd);
814
815 timeout = POLL_TIMEOUT;
817 while self.read_port_reg(PORT_CMD) & PORT_CMD_FR != 0 && timeout > 0 {
818 timeout -= 1;
819 core::hint::spin_loop();
820 }
821 if timeout == 0 {
822 return Err(KernelError::Timeout {
823 operation: "ahci_stop_cmd_fr",
824 duration_ms: 0,
825 });
826 }
827
828 Ok(())
829 }
830
831 pub fn start_cmd(&self) {
833 while self.read_port_reg(PORT_CMD) & PORT_CMD_CR != 0 {
835 core::hint::spin_loop();
836 }
837
838 let mut cmd = self.read_port_reg(PORT_CMD);
839 cmd |= PORT_CMD_FRE;
840 self.write_port_reg(PORT_CMD, cmd);
841
842 cmd = self.read_port_reg(PORT_CMD);
843 cmd |= PORT_CMD_ST;
844 self.write_port_reg(PORT_CMD, cmd);
845 }
846
847 pub fn clear_serr(&self) {
849 self.write_port_reg(PORT_SERR, 0xFFFF_FFFF);
850 }
851
852 pub fn clear_interrupt_status(&self) {
854 self.write_port_reg(PORT_IS, 0xFFFF_FFFF);
855 }
856
857 pub fn wait_ready(&self) -> Result<(), KernelError> {
859 let mut timeout = POLL_TIMEOUT;
860 while timeout > 0 {
861 let tfd = self.read_port_reg(PORT_TFD);
862 if tfd & (TFD_BSY | TFD_DRQ) == 0 {
863 return Ok(());
864 }
865 timeout -= 1;
866 core::hint::spin_loop();
867 }
868 Err(KernelError::Timeout {
869 operation: "ahci_port_ready",
870 duration_ms: 0,
871 })
872 }
873
874 pub fn find_free_slot(&self) -> Result<u8, KernelError> {
878 let ci = self.read_port_reg(PORT_CI);
879 let sact = self.read_port_reg(PORT_SACT);
880 let occupied = ci | sact;
881
882 for slot in 0..self.num_cmd_slots {
883 if occupied & (1 << slot) == 0 {
884 return Ok(slot);
885 }
886 }
887
888 Err(KernelError::ResourceExhausted {
889 resource: "ahci_command_slots",
890 })
891 }
892
893 pub fn issue_command_and_wait(&self, slot: u8) -> Result<(), KernelError> {
898 self.clear_serr();
900 self.clear_interrupt_status();
901
902 self.write_port_reg(PORT_CI, 1 << slot);
904
905 let mut timeout = POLL_TIMEOUT;
907 loop {
908 let ci = self.read_port_reg(PORT_CI);
909 if ci & (1 << slot) == 0 {
910 break;
912 }
913
914 let tfd = self.read_port_reg(PORT_TFD);
915 if tfd & TFD_ERR != 0 {
916 return Err(KernelError::HardwareError {
917 device: "ahci",
918 code: tfd,
919 });
920 }
921
922 timeout -= 1;
923 if timeout == 0 {
924 return Err(KernelError::Timeout {
925 operation: "ahci_command_completion",
926 duration_ms: 0,
927 });
928 }
929 core::hint::spin_loop();
930 }
931
932 let tfd = self.read_port_reg(PORT_TFD);
934 if tfd & TFD_ERR != 0 {
935 return Err(KernelError::HardwareError {
936 device: "ahci",
937 code: tfd,
938 });
939 }
940
941 Ok(())
942 }
943
944 pub fn build_read_dma_ext(
955 &self,
956 lba: u64,
957 sector_count: u16,
958 buffer_phys: u64,
959 ) -> (CommandHeader, CommandTableHeader, PrdtEntry) {
960 let mut fis = FisRegH2D::new();
961 fis.command = ATA_CMD_READ_DMA_EXT;
962 fis.set_lba(lba);
963 fis.set_count(sector_count);
964
965 let mut ct = CommandTableHeader::new();
966 ct.set_h2d_fis(&fis);
967
968 let byte_count = (sector_count as u32) * (self.sector_size as u32);
969 let prdt = PrdtEntry::new(buffer_phys, byte_count, true);
970
971 let cmd_hdr = CommandHeader::new(5, 1, false, 0);
974
975 (cmd_hdr, ct, prdt)
976 }
977
978 pub fn build_write_dma_ext(
984 &self,
985 lba: u64,
986 sector_count: u16,
987 buffer_phys: u64,
988 ) -> (CommandHeader, CommandTableHeader, PrdtEntry) {
989 let mut fis = FisRegH2D::new();
990 fis.command = ATA_CMD_WRITE_DMA_EXT;
991 fis.set_lba(lba);
992 fis.set_count(sector_count);
993
994 let mut ct = CommandTableHeader::new();
995 ct.set_h2d_fis(&fis);
996
997 let byte_count = (sector_count as u32) * (self.sector_size as u32);
998 let prdt = PrdtEntry::new(buffer_phys, byte_count, true);
999
1000 let cmd_hdr = CommandHeader::new(5, 1, true, 0);
1002
1003 (cmd_hdr, ct, prdt)
1004 }
1005}
1006
1007pub type NcqTag = u8;
1013
1014pub fn build_ncq_read_fis(lba: u64, sector_count: u16, tag: NcqTag) -> FisRegH2D {
1019 let mut fis = FisRegH2D::new();
1020 fis.command = ATA_CMD_READ_FPDMA_QUEUED;
1021 fis.set_lba(lba);
1022 fis.feature_lo = (sector_count & 0xFF) as u8;
1024 fis.feature_hi = ((sector_count >> 8) & 0xFF) as u8;
1025 fis.count_lo = (tag & 0x1F) << 3;
1027 fis.count_hi = 0;
1028 fis.device = 1 << 6; fis
1030}
1031
1032pub fn build_ncq_write_fis(lba: u64, sector_count: u16, tag: NcqTag) -> FisRegH2D {
1034 let mut fis = FisRegH2D::new();
1035 fis.command = ATA_CMD_WRITE_FPDMA_QUEUED;
1036 fis.set_lba(lba);
1037 fis.feature_lo = (sector_count & 0xFF) as u8;
1038 fis.feature_hi = ((sector_count >> 8) & 0xFF) as u8;
1039 fis.count_lo = (tag & 0x1F) << 3;
1040 fis.count_hi = 0;
1041 fis.device = 1 << 6; fis
1043}
1044
1045pub fn issue_ncq_command(_port: &AhciPort, _fis: &FisRegH2D) -> Result<NcqTag, KernelError> {
1054 Err(KernelError::NotImplemented {
1055 feature: "ahci_ncq_command_issue",
1056 })
1057}
1058
1059pub fn poll_ncq_completion(_port: &AhciPort) -> u32 {
1063 0
1065}
1066
1067#[cfg(feature = "alloc")]
1073pub struct AhciController {
1074 mmio_base: usize,
1076 capabilities: u32,
1078 num_ports: u8,
1080 num_cmd_slots: u8,
1082 ncq_supported: bool,
1084 supports_64bit: bool,
1086 version: u32,
1088 ports: Vec<AhciPort>,
1090}
1091
1092#[cfg(feature = "alloc")]
1093impl AhciController {
1094 pub fn new(mmio_base: usize) -> Result<Self, KernelError> {
1096 let mut ctrl = Self {
1097 mmio_base,
1098 capabilities: 0,
1099 num_ports: 0,
1100 num_cmd_slots: 0,
1101 ncq_supported: false,
1102 supports_64bit: false,
1103 version: 0,
1104 ports: Vec::new(),
1105 };
1106
1107 ctrl.initialize()?;
1108 Ok(ctrl)
1109 }
1110
1111 fn read_hba_reg(&self, offset: usize) -> u32 {
1113 unsafe { core::ptr::read_volatile((self.mmio_base + offset) as *const u32) }
1117 }
1118
1119 fn write_hba_reg(&self, offset: usize, value: u32) {
1121 unsafe { core::ptr::write_volatile((self.mmio_base + offset) as *mut u32, value) }
1124 }
1125
1126 fn initialize(&mut self) -> Result<(), KernelError> {
1128 crate::println!("[AHCI] Initializing controller at 0x{:x}", self.mmio_base);
1129
1130 self.version = self.read_hba_reg(HBA_REG_VS);
1132 let major = (self.version >> 16) & 0xFFFF;
1133 let minor = self.version & 0xFFFF;
1134 crate::println!("[AHCI] Version: {}.{}", major, minor);
1135
1136 self.capabilities = self.read_hba_reg(HBA_REG_CAP);
1138 self.num_ports = ((self.capabilities & CAP_NP_MASK) + 1) as u8;
1139 self.num_cmd_slots = (((self.capabilities >> CAP_NCS_SHIFT) & CAP_NCS_MASK) + 1) as u8;
1140 self.ncq_supported = self.capabilities & CAP_SNCQ != 0;
1141 self.supports_64bit = self.capabilities & CAP_S64A != 0;
1142
1143 crate::println!(
1144 "[AHCI] Ports: {}, Command Slots: {}, NCQ: {}, 64-bit: {}",
1145 self.num_ports,
1146 self.num_cmd_slots,
1147 self.ncq_supported,
1148 self.supports_64bit,
1149 );
1150
1151 let ghc = self.read_hba_reg(HBA_REG_GHC);
1153 if ghc & GHC_AE == 0 {
1154 self.write_hba_reg(HBA_REG_GHC, ghc | GHC_AE);
1155 crate::println!("[AHCI] Enabled AHCI mode");
1156 }
1157
1158 self.reset()?;
1160
1161 let ghc = self.read_hba_reg(HBA_REG_GHC);
1163 self.write_hba_reg(HBA_REG_GHC, ghc | GHC_AE);
1164
1165 let ghc = self.read_hba_reg(HBA_REG_GHC);
1167 self.write_hba_reg(HBA_REG_GHC, ghc | GHC_IE);
1168
1169 self.write_hba_reg(HBA_REG_IS, 0xFFFF_FFFF);
1171
1172 self.detect_ports();
1174
1175 crate::println!(
1176 "[AHCI] Controller initialized ({} active port(s))",
1177 self.ports
1178 .iter()
1179 .filter(|p| p.state != PortState::Inactive)
1180 .count()
1181 );
1182
1183 Ok(())
1184 }
1185
1186 fn reset(&self) -> Result<(), KernelError> {
1188 let ghc = self.read_hba_reg(HBA_REG_GHC);
1189 self.write_hba_reg(HBA_REG_GHC, ghc | GHC_HR);
1190
1191 let mut timeout = POLL_TIMEOUT;
1193 while self.read_hba_reg(HBA_REG_GHC) & GHC_HR != 0 && timeout > 0 {
1194 timeout -= 1;
1195 core::hint::spin_loop();
1196 }
1197
1198 if timeout == 0 {
1199 return Err(KernelError::Timeout {
1200 operation: "ahci_hba_reset",
1201 duration_ms: 0,
1202 });
1203 }
1204
1205 crate::println!("[AHCI] HBA reset complete");
1206 Ok(())
1207 }
1208
1209 fn detect_ports(&mut self) {
1211 let pi = self.read_hba_reg(HBA_REG_PI);
1212 crate::println!("[AHCI] Ports Implemented bitmask: 0x{:08x}", pi);
1213
1214 for port_num in 0..32u8 {
1215 if pi & (1 << port_num) == 0 {
1216 continue;
1217 }
1218
1219 let mut port = AhciPort::new(
1220 port_num,
1221 self.mmio_base,
1222 self.num_cmd_slots,
1223 self.ncq_supported,
1224 );
1225 port.detect_device();
1226
1227 match port.device_type {
1228 AhciDeviceType::Sata => {
1229 crate::println!("[AHCI] Port {}: SATA drive detected", port_num);
1230 }
1231 AhciDeviceType::Satapi => {
1232 crate::println!("[AHCI] Port {}: SATAPI device detected", port_num);
1233 }
1234 AhciDeviceType::Semb => {
1235 crate::println!("[AHCI] Port {}: SEMB detected", port_num);
1236 }
1237 AhciDeviceType::PortMultiplier => {
1238 crate::println!("[AHCI] Port {}: Port Multiplier detected", port_num);
1239 }
1240 AhciDeviceType::Unknown(sig) => {
1241 crate::println!(
1242 "[AHCI] Port {}: Unknown device (sig=0x{:08x})",
1243 port_num,
1244 sig
1245 );
1246 }
1247 AhciDeviceType::None => {}
1248 }
1249
1250 self.ports.push(port);
1251 }
1252 }
1253
1254 pub fn sata_ports(&self) -> Vec<&AhciPort> {
1256 self.ports
1257 .iter()
1258 .filter(|p| p.device_type == AhciDeviceType::Sata)
1259 .collect()
1260 }
1261
1262 pub fn port(&self, port_num: u8) -> Option<&AhciPort> {
1264 self.ports.iter().find(|p| p.port_num == port_num)
1265 }
1266
1267 pub fn port_mut(&mut self, port_num: u8) -> Option<&mut AhciPort> {
1269 self.ports.iter_mut().find(|p| p.port_num == port_num)
1270 }
1271
1272 pub fn port_count(&self) -> usize {
1274 self.ports.len()
1275 }
1276
1277 pub fn version(&self) -> (u16, u16) {
1279 ((self.version >> 16) as u16, self.version as u16)
1280 }
1281}
1282
1283#[cfg(feature = "alloc")]
1293pub struct AhciBlockDevice {
1294 port: AhciPort,
1296 name: String,
1298}
1299
1300#[cfg(feature = "alloc")]
1301impl AhciBlockDevice {
1302 pub fn new(port: AhciPort, name: String) -> Self {
1304 Self { port, name }
1305 }
1306
1307 pub fn port(&self) -> &AhciPort {
1309 &self.port
1310 }
1311}
1312
1313#[cfg(feature = "alloc")]
1314impl BlockDevice for AhciBlockDevice {
1315 fn name(&self) -> &str {
1316 &self.name
1317 }
1318
1319 fn block_size(&self) -> usize {
1320 self.port.sector_size
1321 }
1322
1323 fn block_count(&self) -> u64 {
1324 self.port.total_sectors
1325 }
1326
1327 fn read_blocks(&self, start_block: u64, buffer: &mut [u8]) -> Result<(), KernelError> {
1328 if buffer.is_empty() {
1329 return Ok(());
1330 }
1331
1332 if !buffer.len().is_multiple_of(self.port.sector_size) {
1333 return Err(KernelError::InvalidArgument {
1334 name: "buffer_length",
1335 value: "not_multiple_of_sector_size",
1336 });
1337 }
1338
1339 if self.port.total_sectors > 0 {
1340 let sector_count = (buffer.len() / self.port.sector_size) as u64;
1341 if start_block + sector_count > self.port.total_sectors {
1342 return Err(KernelError::InvalidArgument {
1343 name: "block_range",
1344 value: "out_of_bounds",
1345 });
1346 }
1347 }
1348
1349 Err(KernelError::NotImplemented {
1358 feature: "ahci_read_dma",
1359 })
1360 }
1361
1362 fn write_blocks(&mut self, start_block: u64, buffer: &[u8]) -> Result<(), KernelError> {
1363 if buffer.is_empty() {
1364 return Ok(());
1365 }
1366
1367 if !buffer.len().is_multiple_of(self.port.sector_size) {
1368 return Err(KernelError::InvalidArgument {
1369 name: "buffer_length",
1370 value: "not_multiple_of_sector_size",
1371 });
1372 }
1373
1374 if self.port.total_sectors > 0 {
1375 let sector_count = (buffer.len() / self.port.sector_size) as u64;
1376 if start_block + sector_count > self.port.total_sectors {
1377 return Err(KernelError::InvalidArgument {
1378 name: "block_range",
1379 value: "out_of_bounds",
1380 });
1381 }
1382 }
1383
1384 Err(KernelError::NotImplemented {
1386 feature: "ahci_write_dma",
1387 })
1388 }
1389
1390 fn flush(&mut self) -> Result<(), KernelError> {
1391 Ok(())
1393 }
1394}
1395
1396static AHCI_INITIALIZED: AtomicBool = AtomicBool::new(false);
1402
1403pub fn init() -> Result<(), KernelError> {
1408 if AHCI_INITIALIZED.swap(true, Ordering::SeqCst) {
1409 return Ok(());
1410 }
1411
1412 crate::println!("[AHCI] Scanning PCI bus for AHCI controllers...");
1413
1414 #[cfg(target_arch = "x86_64")]
1415 {
1416 let pci_bus = crate::drivers::pci::get_pci_bus().lock();
1417 let storage_devices =
1418 pci_bus.find_devices_by_class(crate::drivers::pci::class_codes::MASS_STORAGE);
1419
1420 let mut ahci_count = 0u32;
1421 for dev in &storage_devices {
1422 if dev.subclass == PCI_SUBCLASS_SATA && dev.prog_if == PCI_PROGIF_AHCI {
1423 ahci_count += 1;
1424 crate::println!(
1425 "[AHCI] Found AHCI controller: {:04x}:{:04x} at {}:{}.{}",
1426 dev.vendor_id,
1427 dev.device_id,
1428 dev.location.bus,
1429 dev.location.device,
1430 dev.location.function,
1431 );
1432
1433 if let Some(bar5) = dev.bars.get(5) {
1435 match bar5 {
1436 crate::drivers::pci::PciBar::Memory { address, size, .. } => {
1437 crate::println!(
1438 "[AHCI] BAR5 (ABAR): MMIO at {:#x}, size {:#x}",
1439 address,
1440 size
1441 );
1442
1443 #[cfg(target_os = "none")]
1444 {
1445 let virt_base = crate::mm::phys_to_virt_addr(*address) as usize;
1446 match AhciController::new(virt_base) {
1447 Ok(ctrl) => {
1448 let (maj, min) = ctrl.version();
1449 crate::println!(
1450 "[AHCI] Controller v{}.{} with {} port(s)",
1451 maj,
1452 min,
1453 ctrl.port_count()
1454 );
1455 }
1456 Err(e) => {
1457 crate::println!("[AHCI] Controller init failed: {:?}", e);
1458 }
1459 }
1460 }
1461 }
1462 crate::drivers::pci::PciBar::Io { address, size } => {
1463 crate::println!(
1464 "[AHCI] BAR5: I/O at {:#x}, size {:#x} (unexpected)",
1465 address,
1466 size
1467 );
1468 }
1469 crate::drivers::pci::PciBar::None => {
1470 crate::println!("[AHCI] BAR5: not configured");
1471 }
1472 }
1473 } else {
1474 crate::println!("[AHCI] No BAR5 found (need at least 6 BARs)");
1475 }
1476 }
1477 }
1478
1479 if ahci_count == 0 {
1480 crate::println!("[AHCI] No AHCI controllers found on PCI bus");
1481 } else {
1482 crate::println!("[AHCI] Found {} AHCI controller(s)", ahci_count);
1483 }
1484 }
1485
1486 #[cfg(not(target_arch = "x86_64"))]
1487 {
1488 crate::println!("[AHCI] AHCI PCI scanning not available on this architecture");
1489 }
1490
1491 Ok(())
1492}
1493
1494pub fn is_initialized() -> bool {
1496 AHCI_INITIALIZED.load(Ordering::Relaxed)
1497}
1498
1499#[cfg(test)]
1504mod tests {
1505 use super::*;
1506
1507 #[test]
1508 fn test_fis_reg_h2d_size() {
1509 assert_eq!(core::mem::size_of::<FisRegH2D>(), 20);
1510 }
1511
1512 #[test]
1513 fn test_fis_reg_d2h_size() {
1514 assert_eq!(core::mem::size_of::<FisRegD2H>(), 20);
1515 }
1516
1517 #[test]
1518 fn test_fis_dma_setup_size() {
1519 assert_eq!(core::mem::size_of::<FisDmaSetup>(), 28);
1520 }
1521
1522 #[test]
1523 fn test_fis_pio_setup_size() {
1524 assert_eq!(core::mem::size_of::<FisPioSetup>(), 20);
1525 }
1526
1527 #[test]
1528 fn test_prdt_entry_size() {
1529 assert_eq!(core::mem::size_of::<PrdtEntry>(), 16);
1530 }
1531
1532 #[test]
1533 fn test_command_header_size() {
1534 assert_eq!(core::mem::size_of::<CommandHeader>(), 32);
1535 }
1536
1537 #[test]
1538 fn test_command_table_header_size() {
1539 assert_eq!(core::mem::size_of::<CommandTableHeader>(), 128);
1540 }
1541
1542 #[test]
1543 fn test_received_fis_size() {
1544 assert_eq!(core::mem::size_of::<ReceivedFis>(), 256);
1545 }
1546
1547 #[test]
1548 fn test_device_type_from_signature() {
1549 assert_eq!(
1550 AhciDeviceType::from_signature(SIG_SATA),
1551 AhciDeviceType::Sata
1552 );
1553 assert_eq!(
1554 AhciDeviceType::from_signature(SIG_SATAPI),
1555 AhciDeviceType::Satapi
1556 );
1557 assert_eq!(
1558 AhciDeviceType::from_signature(SIG_SEMB),
1559 AhciDeviceType::Semb
1560 );
1561 assert_eq!(
1562 AhciDeviceType::from_signature(SIG_PM),
1563 AhciDeviceType::PortMultiplier
1564 );
1565 assert_eq!(
1566 AhciDeviceType::from_signature(0xFFFFFFFF),
1567 AhciDeviceType::None
1568 );
1569 assert_eq!(
1570 AhciDeviceType::from_signature(0x00000000),
1571 AhciDeviceType::None
1572 );
1573 assert_eq!(
1574 AhciDeviceType::from_signature(0xDEADBEEF),
1575 AhciDeviceType::Unknown(0xDEADBEEF)
1576 );
1577 }
1578
1579 #[test]
1580 fn test_fis_h2d_lba_encoding() {
1581 let mut fis = FisRegH2D::new();
1582 fis.set_lba(0x0000_1234_5678_9ABC);
1583
1584 assert_eq!(fis.lba0, 0xBC);
1585 assert_eq!(fis.lba1, 0x9A);
1586 assert_eq!(fis.lba2, 0x78);
1587 assert_eq!(fis.lba3, 0x56);
1588 assert_eq!(fis.lba4, 0x34);
1589 assert_eq!(fis.lba5, 0x12);
1590 assert_eq!(fis.device & (1 << 6), 1 << 6); }
1592
1593 #[test]
1594 fn test_fis_h2d_count_encoding() {
1595 let mut fis = FisRegH2D::new();
1596 fis.set_count(0xABCD);
1597
1598 assert_eq!(fis.count_lo, 0xCD);
1599 assert_eq!(fis.count_hi, 0xAB);
1600 }
1601
1602 #[test]
1603 fn test_prdt_entry_construction() {
1604 let prdt = PrdtEntry::new(0x1000_0000_DEAD_0000, 4096, true);
1605
1606 assert_eq!(prdt.data_base_lo, 0xDEAD_0000);
1607 assert_eq!(prdt.data_base_hi, 0x1000_0000);
1608 assert_eq!(prdt.dbc_and_flags, 0x8000_0FFF);
1610 }
1611
1612 #[test]
1613 fn test_prdt_entry_no_interrupt() {
1614 let prdt = PrdtEntry::new(0x0000_0000_0001_0000, 512, false);
1615
1616 assert_eq!(prdt.data_base_lo, 0x0001_0000);
1617 assert_eq!(prdt.data_base_hi, 0);
1618 assert_eq!(prdt.dbc_and_flags, 0x0000_01FF);
1620 }
1621
1622 #[test]
1623 fn test_command_header_construction() {
1624 let hdr = CommandHeader::new(5, 3, true, 0x0000_0001_0000_0080);
1625
1626 let expected_flags = 5 | (1 << 6) | (3 << 16);
1628 assert_eq!(hdr.flags_and_prdtl, expected_flags);
1629 assert_eq!(hdr.ctba_lo, 0x0000_0080);
1630 assert_eq!(hdr.ctba_hi, 0x0000_0001);
1631 assert_eq!(hdr.prdbc, 0);
1632 }
1633
1634 #[test]
1635 fn test_ncq_read_fis_tag_encoding() {
1636 let fis = build_ncq_read_fis(0, 8, 5);
1637
1638 assert_eq!(fis.command, ATA_CMD_READ_FPDMA_QUEUED);
1639 assert_eq!(fis.count_lo, 5 << 3);
1641 assert_eq!(fis.feature_lo, 8);
1643 assert_eq!(fis.feature_hi, 0);
1644 }
1645
1646 #[test]
1647 fn test_ncq_write_fis_tag_encoding() {
1648 let fis = build_ncq_write_fis(100, 256, 31);
1649
1650 assert_eq!(fis.command, ATA_CMD_WRITE_FPDMA_QUEUED);
1651 assert_eq!(fis.count_lo, 31 << 3);
1652 assert_eq!(fis.feature_lo, 0); assert_eq!(fis.feature_hi, 1); }
1655
1656 #[test]
1657 fn test_port_state_default() {
1658 let port = AhciPort::new(0, 0x1000_0000, 32, true);
1659
1660 assert_eq!(port.port_num, 0);
1661 assert_eq!(port.device_type, AhciDeviceType::None);
1662 assert_eq!(port.state, PortState::Inactive);
1663 assert_eq!(port.num_cmd_slots, 32);
1664 assert!(port.ncq_supported);
1665 assert_eq!(port.total_sectors, 0);
1666 assert_eq!(port.sector_size, SECTOR_SIZE);
1667 assert_eq!(port.port_mmio_base, 0x1000_0000 + PORT_BASE);
1669 }
1670
1671 #[test]
1672 fn test_port_mmio_base_calculation() {
1673 let port3 = AhciPort::new(3, 0x2000_0000, 16, false);
1674 assert_eq!(port3.port_mmio_base, 0x2000_0000 + 0x100 + 3 * 0x80);
1676 }
1677
1678 #[test]
1679 fn test_initialization_flag() {
1680 AHCI_INITIALIZED.store(false, Ordering::SeqCst);
1682 assert!(!is_initialized());
1683 }
1684
1685 #[cfg(feature = "alloc")]
1686 #[test]
1687 fn test_ahci_block_device_name() {
1688 let port = AhciPort::new(0, 0, 32, false);
1689 let dev = AhciBlockDevice::new(port, String::from("sda"));
1690 assert_eq!(dev.name(), "sda");
1691 assert_eq!(dev.block_size(), SECTOR_SIZE);
1692 assert_eq!(dev.block_count(), 0);
1693 }
1694}