summaryrefslogtreecommitdiffstats
path: root/rsnix/src/memory.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-02 15:21:34 +0200
committersalmonik <salmonik@tuta.io>2026-08-02 15:21:34 +0200
commitc7d92071e1dd11c45999457b16554b4abaa73b28 (patch)
treeaff7c7f19adcffe1dd91e1c2514af02c77fd524e /rsnix/src/memory.rs
parentv0.5.5: fix real-hardware boot crash — shadow back in heap as first allocation (diff)
downloadrs-dos-c7d92071e1dd11c45999457b16554b4abaa73b28.tar.gz
rs-dos-c7d92071e1dd11c45999457b16554b4abaa73b28.zip
v0.5.5: crash reports go to a dedicated CRASHLOG USB stick
The fault handler now writes crash.log to the volume labeled CRASHLOG (label-selected via fat::crash_vol), falling back to slot 0. On real hardware the boot USB may be unwritable, so a second stick labeled CRASHLOG survives the write; the shell auto-prints the previous crash report from it at next boot (read_crash_log resolves /disk/<uid>/crash.log through the FAT path, since Disk nodes hold no cached children). - fat.rs: volume_label() + crash_vol() (no allocation) - fs.rs: write_crash_log targets crash_vol(); read_crash_log prefers the CRASHLOG disk node; drop now-unused first_disk() - mkdisk.sh: --label option - test-fault.sh: boots with a dedicated CRASHLOG stick (mkfs -F 32 -n CRASHLOG), verifies crash.log lands there and NOT on the ESP
Diffstat (limited to 'rsnix/src/memory.rs')
-rw-r--r--rsnix/src/memory.rs88
1 files changed, 67 insertions, 21 deletions
diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs
index 605125a..e6896f2 100644
--- a/rsnix/src/memory.rs
+++ b/rsnix/src/memory.rs
@@ -76,6 +76,31 @@ static mut HEAP_END: usize = 0;
76/// Total heap capacity — the original region plus pages added by growth. 76/// Total heap capacity — the original region plus pages added by growth.
77static mut HEAP_CAPACITY: usize = 0; 77static mut HEAP_CAPACITY: usize = 0;
78 78
79/// Kernel image bounds (base..end) captured from the UEFI LoadedImage
80/// protocol before ExitBootServices. Both the heap free list and the
81/// page-allocator bitmap reserve this range so no allocation can ever
82/// land on the running kernel's own code/data/bss pages.
83static mut KERNEL_IMAGE_START: usize = 0;
84static mut KERNEL_IMAGE_END: usize = 0;
85
86/// Record the loaded-image memory range (from EFI_LOADED_IMAGE_PROTOCOL).
87pub fn set_kernel_image_range(base: usize, size: usize) {
88 unsafe {
89 KERNEL_IMAGE_START = base;
90 KERNEL_IMAGE_END = base + size;
91 }
92}
93
94fn kernel_image_range() -> Option<(usize, usize)> {
95 unsafe {
96 if KERNEL_IMAGE_END > KERNEL_IMAGE_START {
97 Some((KERNEL_IMAGE_START, KERNEL_IMAGE_END))
98 } else {
99 None
100 }
101 }
102}
103
79/// Minimum pages `grow_heap` takes from the page allocator per growth. 104/// Minimum pages `grow_heap` takes from the page allocator per growth.
80const HEAP_GROW_PAGES: usize = 64; 105const HEAP_GROW_PAGES: usize = 64;
81 106
@@ -354,11 +379,16 @@ pub unsafe fn refresh_and_exit(bs: &BootServices, image_handle: Handle) -> Resul
354 379
355fn init_heap() { 380fn init_heap() {
356 unsafe { 381 unsafe {
357 // Region the firmware maps for the GOP framebuffer, if known — 382 // Regions that must never be handed out as heap memory, even when
358 // exclude it even when the memory map lists it as conventional 383 // the firmware lists them as conventional:
359 // (some real firmware does exactly that, which would let heap 384 // * the GOP framebuffer (heap allocations overwriting the display),
360 // allocations overwrite the display). 385 // * the kernel image itself (a heap allocation landing on the
361 let fb = crate::gop::framebuffer_region(); 386 // kernel's .bss would silently corrupt statics — observed as a
387 // garbage ACTIVE_VOL and a dead filesystem in the fault path).
388 let holes: [(usize, usize); 2] = [
389 crate::gop::framebuffer_region().unwrap_or((0, 0)),
390 kernel_image_range().unwrap_or((0, 0)),
391 ];
362 let mut best_start = 0usize; 392 let mut best_start = 0usize;
363 let mut best_size = 0usize; 393 let mut best_size = 0usize;
364 for i in 0..MAP_ENTRIES { 394 for i in 0..MAP_ENTRIES {
@@ -366,26 +396,25 @@ fn init_heap() {
366 if d.kind == MEMORY_TYPE_CONVENTIONAL { 396 if d.kind == MEMORY_TYPE_CONVENTIONAL {
367 let s = d.physical_start as usize; 397 let s = d.physical_start as usize;
368 let e = s + d.number_of_pages as usize * 4096; 398 let e = s + d.number_of_pages as usize * 4096;
369 // Split at the framebuffer hole so the free list NEVER 399 // Split at each hole so the free list NEVER contains
370 // contains fb pages: a coarse size subtraction leaves one 400 // reserved pages: a coarse size subtraction leaves one
371 // block *spanning* the hole, letting a large allocation 401 // block *spanning* the hole, letting a large allocation
372 // (e.g. the 1.9 MB display shadow) straddle the display. 402 // (e.g. the 1.9 MB display shadow) straddle it.
373 let mut lo = s; 403 let mut lo = s;
374 if let Some((b, sz)) = fb 404 for (b, sz) in holes {
375 && e > b 405 if sz > 0 && e > b && s < b + sz {
376 && s < b + sz 406 let h0 = b.max(s);
377 { 407 let h1 = (b + sz).min(e);
378 let h0 = b.max(s); 408 if h0 > lo {
379 let h1 = (b + sz).min(e); 409 // Segment before the hole.
380 if h0 > lo { 410 let seg = h0 - lo;
381 // Segment before the hole. 411 if seg > best_size {
382 let seg = h0 - lo; 412 best_start = lo;
383 if seg > best_size { 413 best_size = seg;
384 best_start = lo; 414 }
385 best_size = seg;
386 } 415 }
416 lo = h1;
387 } 417 }
388 lo = h1;
389 } 418 }
390 if e > lo { 419 if e > lo {
391 let seg = e - lo; 420 let seg = e - lo;
@@ -664,6 +693,23 @@ pub fn init_page_allocator() -> bool {
664 } 693 }
665 } 694 }
666 695
696 // Reserve the kernel image so the page allocator never hands out
697 // the running kernel's own code/data/bss pages (DMA buffers and
698 // task stacks landing on the kernel would corrupt it — a heap
699 // allocation over the .bss already broke the FAT ACTIVE_VOL).
700 if let Some((ks, ke)) = kernel_image_range()
701 && ke > ks
702 {
703 let s = ks / PAGE_SIZE;
704 let e = ke.div_ceil(PAGE_SIZE);
705 for p in s..e {
706 let idx = p - base_page;
707 if idx < span_pages {
708 *bm.add(idx / 8) |= 1 << (idx % 8);
709 }
710 }
711 }
712
667 // Reserve the GOP framebuffer region even if the map lists it as 713 // Reserve the GOP framebuffer region even if the map lists it as
668 // conventional — kernel allocations (stacks, DMA buffers) must 714 // conventional — kernel allocations (stacks, DMA buffers) must
669 // never land on the display. 715 // never land on the display.