diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-31 19:53:53 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-31 19:53:53 +0200 |
| commit | dc23d2f22cafeb6b97ba460789a834a6c586314d (patch) | |
| tree | 987bec11922073923c4c42bda84c0f670884dbca /rsnix/src/pci.rs | |
| parent | vt: defer scrolls and batch framebuffer pushes (diff) | |
| download | rs-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.rs | 33 |
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). | ||
| 61 | pub 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. | ||
| 73 | pub 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. |
| 61 | pub fn probe() -> alloc::vec::Vec<DeviceInfo> { | 94 | pub fn probe() -> alloc::vec::Vec<DeviceInfo> { |
| 62 | let mut out = alloc::vec::Vec::new(); | 95 | let mut out = alloc::vec::Vec::new(); |
