summaryrefslogtreecommitdiffstats
path: root/rsnix/src/pci.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-07-31 19:53:53 +0200
committersalmonik <salmonik@tuta.io>2026-07-31 19:53:53 +0200
commitdc23d2f22cafeb6b97ba460789a834a6c586314d (patch)
tree987bec11922073923c4c42bda84c0f670884dbca /rsnix/src/pci.rs
parentvt: defer scrolls and batch framebuffer pushes (diff)
downloadrs-dos-dc23d2f22cafeb6b97ba460789a834a6c586314d.tar.gz
rs-dos-dc23d2f22cafeb6b97ba460789a834a6c586314d.zip
ahci: SATA driver + FAT32 persistent disk mounted at /disk
- ahci.rs: polling AHCI on PCI class 1/6/1, bus mastering + ABAR map, port 0 up, IDENTIFY + READ/WRITE DMA EXT through one 4KiB DMA buffer - fat.rs: BPB parse, whole-FAT RAM cache with write-back to both copies, LFN read/write, dirs, multi-cluster files, FSInfo free-count sync, space-padded dot entries ('..' = cluster 0 under root), fsck-clean - fs.rs: /disk mount node + 24-slot ephemeral node pool; ls/cat/hexdump/ echo/mkdir/touch/rm/edit all work on disk paths unchanged - QEMU: explicit bus assignment (disk=ide.0, ESP=ide.1); the implicit fat:rw:esp drive was stealing AHCI port 0 - Debugged against QEMU source: header DW0 is CFL in bits 4:0 / PRDTL in bits 31:16 (Linux libahci layout), FIS count at bytes 12-13, device at byte 7; QEMU rejects H2D FIS flags bits 6:4, so direction is the header W bit only - Verified: full shell round-trip on /disk, reboot persistence (poweroff then mdir/mtype and a fresh boot), fsck.fat clean
Diffstat (limited to 'rsnix/src/pci.rs')
-rw-r--r--rsnix/src/pci.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/rsnix/src/pci.rs b/rsnix/src/pci.rs
index 2d201f3..efdbc01 100644
--- a/rsnix/src/pci.rs
+++ b/rsnix/src/pci.rs
@@ -57,6 +57,39 @@ pub fn config_read(bus: u8, device: u8, func: u8, reg: u8) -> u32 {
57 inl(CONFIG_DATA) 57 inl(CONFIG_DATA)
58} 58}
59 59
60/// Write a dword to a device's config space (`reg` must be dword-aligned).
61pub fn config_write(bus: u8, device: u8, func: u8, reg: u8, val: u32) {
62 let addr = 0x8000_0000
63 | ((bus as u32) << 16)
64 | ((device as u32) << 11)
65 | ((func as u32) << 8)
66 | ((reg as u32) & 0xFC);
67 outl(CONFIG_ADDRESS, addr);
68 outl(CONFIG_DATA, val)
69}
70
71/// Read a memory BAR (index 0-5) as a 64-bit address, handling 32/64-bit
72/// BARs. Returns None for I/O BARs or invalid values.
73pub fn bar64(bus: u8, device: u8, func: u8, bar_index: u8) -> Option<u64> {
74 let reg_off = 0x10 + bar_index * 4;
75 let lo = config_read(bus, device, func, reg_off);
76 if lo & 1 == 1 {
77 return None; // I/O BAR
78 }
79 let kind = (lo >> 1) & 0x3;
80 let hi = if kind == 2 {
81 config_read(bus, device, func, reg_off + 4)
82 } else {
83 0
84 };
85 let base = ((hi as u64) << 32) | (lo as u64 & 0xFFFF_FFF0);
86 if base == 0 {
87 None
88 } else {
89 Some(base)
90 }
91}
92
60/// Enumerate every device/function present on all buses. 93/// Enumerate every device/function present on all buses.
61pub fn probe() -> alloc::vec::Vec<DeviceInfo> { 94pub fn probe() -> alloc::vec::Vec<DeviceInfo> {
62 let mut out = alloc::vec::Vec::new(); 95 let mut out = alloc::vec::Vec::new();