summaryrefslogtreecommitdiffstats
path: root/rsnix/src
diff options
context:
space:
mode:
Diffstat (limited to 'rsnix/src')
-rw-r--r--rsnix/src/ahci.rs18
-rw-r--r--rsnix/src/fat.rs12
-rw-r--r--rsnix/src/memory.rs12
-rw-r--r--rsnix/src/pci.rs28
-rw-r--r--rsnix/src/sched.rs18
-rw-r--r--rsnix/src/strbuf.rs28
6 files changed, 76 insertions, 40 deletions
diff --git a/rsnix/src/ahci.rs b/rsnix/src/ahci.rs
index 72da07d..a77b341 100644
--- a/rsnix/src/ahci.rs
+++ b/rsnix/src/ahci.rs
@@ -510,22 +510,24 @@ fn active() -> Option<&'static Disk> {
510 disks().get(unsafe { ACTIVE }).and_then(|d| d.as_ref()) 510 disks().get(unsafe { ACTIVE }).and_then(|d| d.as_ref())
511} 511}
512 512
513/// DMA `count` sectors starting at `lba` into the selected disk's buffer. 513/// Bounds-checked DMA of `count` sectors starting at `lba` into/out of the
514pub fn read_sectors(lba: u64, count: u32) -> Result<(), ()> { 514/// selected disk's buffer (single code path for both directions).
515fn dma_sectors(lba: u64, count: u32, cmd: u8, write: bool) -> Result<(), ()> {
515 let d = active().ok_or(())?; 516 let d = active().ok_or(())?;
516 if lba + count as u64 > d.sectors { 517 if lba + count as u64 > d.sectors {
517 return Err(()); 518 return Err(());
518 } 519 }
519 issue(d, ATA_READ_DMA_EXT, lba, count, false) 520 issue(d, cmd, lba, count, write)
521}
522
523/// DMA `count` sectors starting at `lba` into the selected disk's buffer.
524pub fn read_sectors(lba: u64, count: u32) -> Result<(), ()> {
525 dma_sectors(lba, count, ATA_READ_DMA_EXT, false)
520} 526}
521 527
522/// DMA `count` sectors starting at `lba` out of the selected disk's buffer. 528/// DMA `count` sectors starting at `lba` out of the selected disk's buffer.
523pub fn write_sectors(lba: u64, count: u32) -> Result<(), ()> { 529pub fn write_sectors(lba: u64, count: u32) -> Result<(), ()> {
524 let d = active().ok_or(())?; 530 dma_sectors(lba, count, ATA_WRITE_DMA_EXT, true)
525 if lba + count as u64 > d.sectors {
526 return Err(());
527 }
528 issue(d, ATA_WRITE_DMA_EXT, lba, count, true)
529} 531}
530 532
531/// Pointer to the selected disk's 4 KiB DMA buffer. 533/// Pointer to the selected disk's 4 KiB DMA buffer.
diff --git a/rsnix/src/fat.rs b/rsnix/src/fat.rs
index bad01cd..eda81ed 100644
--- a/rsnix/src/fat.rs
+++ b/rsnix/src/fat.rs
@@ -167,8 +167,18 @@ fn write_sector(lba: u64, data: &[u8; SECTOR]) -> Result<(), ()> {
167 167
168// --- cluster math ---------------------------------------------------------- 168// --- cluster math ----------------------------------------------------------
169 169
170/// Current volume's metadata — only ever reached with a selected volume
171/// (the fs layer calls `select_vol` first), so a missing slot is a kernel
172/// invariant violation, not a recoverable error.
170fn v() -> &'static mut Volume { 173fn v() -> &'static mut Volume {
171 vols().get_mut(*active_vol()).unwrap() 174 let i = *active_vol();
175 match vols().get_mut(i) {
176 Some(v) => v,
177 None => {
178 crate::serial_println!("fat: internal error — no volume at slot {}", i);
179 crate::interrupts::halt();
180 }
181 }
172} 182}
173 183
174fn spc() -> usize { 184fn spc() -> usize {
diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs
index 7c3eda0..e03af8b 100644
--- a/rsnix/src/memory.rs
+++ b/rsnix/src/memory.rs
@@ -458,7 +458,9 @@ pub fn self_test() -> bool {
458 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1); 458 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
459 let align = 16usize << (seed as usize % 8); 459 let align = 16usize << (seed as usize % 8);
460 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1); 460 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
461 let layout = Layout::from_size_align(size, align).unwrap(); 461 let Ok(layout) = Layout::from_size_align(size, align) else {
462 return false; // impossible: size <= 2048, align <= 2048
463 };
462 let p = ALLOCATOR.alloc(layout); 464 let p = ALLOCATOR.alloc(layout);
463 if p.is_null() { 465 if p.is_null() {
464 break; // heap exhausted — stop 466 break; // heap exhausted — stop
@@ -493,7 +495,9 @@ pub fn self_test() -> bool {
493 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1); 495 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
494 let align = 16usize << (seed as usize % 8); 496 let align = 16usize << (seed as usize % 8);
495 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1); 497 seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
496 let layout = Layout::from_size_align(size, align).unwrap(); 498 let Ok(layout) = Layout::from_size_align(size, align) else {
499 return false; // impossible: size <= 2048, align <= 2048
500 };
497 let p = ALLOCATOR.alloc(layout); 501 let p = ALLOCATOR.alloc(layout);
498 if p.is_null() { 502 if p.is_null() {
499 return false; // failed to reuse freed space 503 return false; // failed to reuse freed space
@@ -510,7 +514,9 @@ pub fn self_test() -> bool {
510 if *ptr == 0 { 514 if *ptr == 0 {
511 continue; 515 continue;
512 } 516 }
513 let layout = Layout::from_size_align(*size, *align).unwrap(); 517 let Ok(layout) = Layout::from_size_align(*size, *align) else {
518 return false; // impossible: sizes/aligns came from the loop above
519 };
514 ALLOCATOR.dealloc(*ptr as *mut u8, layout); 520 ALLOCATOR.dealloc(*ptr as *mut u8, layout);
515 } 521 }
516 let stats = heap_stats(); 522 let stats = heap_stats();
diff --git a/rsnix/src/pci.rs b/rsnix/src/pci.rs
index 21d7536..b9c2265 100644
--- a/rsnix/src/pci.rs
+++ b/rsnix/src/pci.rs
@@ -46,25 +46,25 @@ fn inl(port: u16) -> u32 {
46 val 46 val
47} 47}
48 48
49/// Read a dword from a device's config space (`reg` must be dword-aligned). 49/// Encode the PCI config-space port address for (bus, dev, fn, reg);
50pub fn config_read(bus: u8, device: u8, func: u8, reg: u8) -> u32 { 50/// `reg` must be dword-aligned.
51 let addr = 0x8000_0000 51fn config_addr(bus: u8, device: u8, func: u8, reg: u8) -> u32 {
52 0x8000_0000
52 | ((bus as u32) << 16) 53 | ((bus as u32) << 16)
53 | ((device as u32) << 11) 54 | ((device as u32) << 11)
54 | ((func as u32) << 8) 55 | ((func as u32) << 8)
55 | ((reg as u32) & 0xFC); 56 | ((reg as u32) & 0xFC)
56 outl(CONFIG_ADDRESS, addr); 57}
58
59/// Read a dword from a device's config space (`reg` must be dword-aligned).
60pub fn config_read(bus: u8, device: u8, func: u8, reg: u8) -> u32 {
61 outl(CONFIG_ADDRESS, config_addr(bus, device, func, reg));
57 inl(CONFIG_DATA) 62 inl(CONFIG_DATA)
58} 63}
59 64
60/// Write a dword to a device's config space (`reg` must be dword-aligned). 65/// 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) { 66pub fn config_write(bus: u8, device: u8, func: u8, reg: u8, val: u32) {
62 let addr = 0x8000_0000 67 outl(CONFIG_ADDRESS, config_addr(bus, device, func, reg));
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) 68 outl(CONFIG_DATA, val)
69} 69}
70 70
@@ -83,7 +83,11 @@ pub fn bar64(bus: u8, device: u8, func: u8, bar_index: u8) -> Option<u64> {
83 0 83 0
84 }; 84 };
85 let base = ((hi as u64) << 32) | (lo as u64 & 0xFFFF_FFF0); 85 let base = ((hi as u64) << 32) | (lo as u64 & 0xFFFF_FFF0);
86 if base == 0 { None } else { Some(base) } 86 if base == 0 {
87 None
88 } else {
89 Some(base)
90 }
87} 91}
88 92
89/// Enumerate every device/function present on all buses. 93/// Enumerate every device/function present on all buses.
diff --git a/rsnix/src/sched.rs b/rsnix/src/sched.rs
index 4b10503..6ffa745 100644
--- a/rsnix/src/sched.rs
+++ b/rsnix/src/sched.rs
@@ -372,7 +372,7 @@ pub fn page_fault(cr2: u64, frame_ptr: usize) -> usize {
372 let rip = unsafe { (frame_ptr as *const IntFrame).read().rip }; 372 let rip = unsafe { (frame_ptr as *const IntFrame).read().rip };
373 let mut buf = [0u8; 96]; 373 let mut buf = [0u8; 96];
374 let n = { 374 let n = {
375 let mut f = FmtBuf { b: &mut buf, n: 0 }; 375 let mut f = crate::strbuf::FmtBuf::new(&mut buf);
376 let _ = fmt::write( 376 let _ = fmt::write(
377 &mut f, 377 &mut f,
378 core::format_args!( 378 core::format_args!(
@@ -386,7 +386,7 @@ pub fn page_fault(cr2: u64, frame_ptr: usize) -> usize {
386 rip 386 rip
387 ), 387 ),
388 ); 388 );
389 f.n 389 f.len()
390 }; 390 };
391 abort_current(core::str::from_utf8(&buf[..n]).unwrap_or("task fault")) 391 abort_current(core::str::from_utf8(&buf[..n]).unwrap_or("task fault"))
392} 392}
@@ -528,17 +528,3 @@ fn idle_main() {
528 } 528 }
529 } 529 }
530} 530}
531
532struct FmtBuf<'a> {
533 b: &'a mut [u8],
534 n: usize,
535}
536
537impl fmt::Write for FmtBuf<'_> {
538 fn write_str(&mut self, s: &str) -> fmt::Result {
539 let m = s.len().min(self.b.len() - self.n);
540 self.b[self.n..self.n + m].copy_from_slice(&s.as_bytes()[..m]);
541 self.n += m;
542 Ok(())
543 }
544}
diff --git a/rsnix/src/strbuf.rs b/rsnix/src/strbuf.rs
index 262720d..0e3ea56 100644
--- a/rsnix/src/strbuf.rs
+++ b/rsnix/src/strbuf.rs
@@ -69,3 +69,31 @@ impl<const N: usize> fmt::Debug for String<N> {
69 write!(f, "{:?}", self.as_str()) 69 write!(f, "{:?}", self.as_str())
70 } 70 }
71} 71}
72
73/// Small `fmt::Write` over a byte slice — no allocation, bounded.
74/// Shared by the panic handler (task-panic message) and the scheduler
75/// (page-fault abort message) so they don't each reinvent it.
76pub struct FmtBuf<'a> {
77 b: &'a mut [u8],
78 n: usize,
79}
80
81impl<'a> FmtBuf<'a> {
82 pub fn new(b: &'a mut [u8]) -> Self {
83 FmtBuf { b, n: 0 }
84 }
85
86 /// Bytes written so far (clamped at the buffer length).
87 pub fn len(&self) -> usize {
88 self.n
89 }
90}
91
92impl fmt::Write for FmtBuf<'_> {
93 fn write_str(&mut self, s: &str) -> fmt::Result {
94 let m = s.len().min(self.b.len() - self.n);
95 self.b[self.n..self.n + m].copy_from_slice(&s.as_bytes()[..m]);
96 self.n += m;
97 Ok(())
98 }
99}