summaryrefslogtreecommitdiffstats
path: root/rsnix/src/memory.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-01 22:28:34 +0200
committersalmonik <salmonik@tuta.io>2026-08-01 22:28:34 +0200
commitab7d87bcde31c1681ea09c30534dde840a58d6fa (patch)
tree42eed2c86663cf6ecfa3507ca46399e31b441c99 /rsnix/src/memory.rs
parentrsboot: track latest upstream HEAD (92367a8) instead of pinned ee1c85b (diff)
downloadrs-dos-ab7d87bcde31c1681ea09c30534dde840a58d6fa.tar.gz
rs-dos-ab7d87bcde31c1681ea09c30534dde840a58d6fa.zip
rsnix v0.5.2: fault diagnostics + real-hardware scroll-crash hardening
The real-hardware scroll crash (white bands + instant freeze, QEMU-clean) was invisible because the only trace was a single serial line on machines with no serial console. This makes every crash self-identifying and hardens the real-hardware failure surfaces: - Every CPU exception vector 0-31 now has an IDT entry (macro-generated stubs; 8/14 keep their IST stacks). A fault in the shell prints a white-on-red band to the framebuffer via gop::dump_lines (raw fb writes bypassing the vt, fully clamped) plus a parseable serial line: '!!! <kind> vec=N err=… rip=… cr2=… rsp=… rflags=… task=N "name"', then halts — instead of converging to a cryptic double fault. Background-task faults abort the task as before. - Boot log now reports the authoritative post-SetMode geometry: 'gop: fb base=… size=… pitch=… WxH bpp=… bgr=…', so the next real machine's report identifies whether pitch*height exceeds the mapping. - Framebuffer writes (clear, push_rect, shift_up_n bulk push, cursor overlay) are clamped to the firmware's framebuffer_size: a pitch- padded mode degrades to a truncated view instead of faulting past the mapping. - The GOP framebuffer region is excluded from the page allocator (and subtracted from the heap's conventional-region pick) even when the firmware lists it as ConventionalMemory — kernel allocations can never overwrite the display again. The GOP protocol is located and peeked before the memory map is captured so the exclusion is known at heap-init time. - Shell gains a hidden 'fault' command (deliberate unmapped write) and 'make test-fault' verifies the dump: vec=14, cr2=0x400000000000, task=0, halt — no triple fault. All other suites re-pass. - CONTEXT.md: fault-dump format documented for real-hardware reports.
Diffstat (limited to 'rsnix/src/memory.rs')
-rw-r--r--rsnix/src/memory.rs35
1 files changed, 33 insertions, 2 deletions
diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs
index e03af8b..a947c53 100644
--- a/rsnix/src/memory.rs
+++ b/rsnix/src/memory.rs
@@ -354,14 +354,29 @@ pub unsafe fn refresh_and_exit(bs: &BootServices, image_handle: Handle) -> Resul
354 354
355fn init_heap() { 355fn init_heap() {
356 unsafe { 356 unsafe {
357 // Region the firmware maps for the GOP framebuffer, if known —
358 // exclude it even when the memory map lists it as conventional
359 // (some real firmware does exactly that, which would let heap
360 // allocations overwrite the display).
361 let fb = crate::gop::framebuffer_region();
357 let mut best_start = 0usize; 362 let mut best_start = 0usize;
358 let mut best_size = 0usize; 363 let mut best_size = 0usize;
359 for i in 0..MAP_ENTRIES { 364 for i in 0..MAP_ENTRIES {
360 let d = &MEMORY_MAP[i]; 365 let d = &MEMORY_MAP[i];
361 if d.kind == MEMORY_TYPE_CONVENTIONAL { 366 if d.kind == MEMORY_TYPE_CONVENTIONAL {
362 let sz = d.number_of_pages as usize * 4096; 367 let s = d.physical_start as usize;
368 let e = s + d.number_of_pages as usize * 4096;
369 // Subtract any overlap with the framebuffer region.
370 let (cs, ce) = match fb {
371 Some((b, sz)) if e > b && s < b + sz => (s.max(b), e.min(b + sz)),
372 _ => (e, s), // no overlap → empty range
373 };
374 let mut sz = e - s;
375 if ce > cs {
376 sz -= ce - cs;
377 }
363 if sz > best_size { 378 if sz > best_size {
364 best_start = d.physical_start as usize; 379 best_start = s;
365 best_size = sz; 380 best_size = sz;
366 } 381 }
367 } 382 }
@@ -634,6 +649,22 @@ pub fn init_page_allocator() -> bool {
634 } 649 }
635 } 650 }
636 651
652 // Reserve the GOP framebuffer region even if the map lists it as
653 // conventional — kernel allocations (stacks, DMA buffers) must
654 // never land on the display.
655 if let Some((fbase, fsize)) = crate::gop::framebuffer_region()
656 && fsize > 0
657 {
658 let s = fbase / PAGE_SIZE;
659 let e = (fbase + fsize).div_ceil(PAGE_SIZE);
660 for p in s..e {
661 let idx = p - base_page;
662 if idx < span_pages {
663 *bm.add(idx / 8) |= 1 << (idx % 8);
664 }
665 }
666 }
667
637 // Never hand out page 0 (the null-pointer trap page). 668 // Never hand out page 0 (the null-pointer trap page).
638 if base_page == 0 { 669 if base_page == 0 {
639 *bm |= 0x01; 670 *bm |= 0x01;