From d9fe082ef07b6e5c599585d6911dbad2bbe4c787 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 2 Aug 2026 02:16:40 +0200 Subject: v0.5.5: fix real-hardware boot crash — shadow back in heap as first allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User's machine: boot reached 'rsnix: boot done — shell' then panicked 'len is 0, index 0' at the first cell write — CELLS (the vt grid) was valid at vt::init and empty at the first shell paint, i.e. something stomped the heap between vt::init and the shell banner. The only change in that window vs the working v0.5.3 was the v0.5.4 move of the 1.9 MB display shadow from the heap to the fb-aware page allocator: on this machine's memory layout the page-allocator shadow's fill loop (480K words) clobbered the heap's vt vectors. - Shadow is again the *first* heap allocation, in gop::init before vt::init builds its grids (the v0.5.3 layout that provably boots on the user's hardware) — nothing else in the heap can collide with it. - init_heap now splits the free list at the GOP framebuffer hole instead of subtracting its size from one block that still *spanned* the hole — no heap allocation of any size can land on the display. - Kept the panic-proof try_reserve + fb-overlap rejection + no-shadow warning band; dropped the late init_shadow() call in main.rs. - Verified on QEMU: shadow @ 0x1980020 origin=heap, allocated before vt::init, fb clean at 0x80000000; all 5 suites PASS; 0 warnings. --- rsnix/src/memory.rs | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'rsnix/src/memory.rs') diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs index a947c53..605125a 100644 --- a/rsnix/src/memory.rs +++ b/rsnix/src/memory.rs @@ -366,18 +366,33 @@ fn init_heap() { if d.kind == MEMORY_TYPE_CONVENTIONAL { let s = d.physical_start as usize; let e = s + d.number_of_pages as usize * 4096; - // Subtract any overlap with the framebuffer region. - let (cs, ce) = match fb { - Some((b, sz)) if e > b && s < b + sz => (s.max(b), e.min(b + sz)), - _ => (e, s), // no overlap → empty range - }; - let mut sz = e - s; - if ce > cs { - sz -= ce - cs; + // Split at the framebuffer hole so the free list NEVER + // contains fb pages: a coarse size subtraction leaves one + // block *spanning* the hole, letting a large allocation + // (e.g. the 1.9 MB display shadow) straddle the display. + let mut lo = s; + if let Some((b, sz)) = fb + && e > b + && s < b + sz + { + let h0 = b.max(s); + let h1 = (b + sz).min(e); + if h0 > lo { + // Segment before the hole. + let seg = h0 - lo; + if seg > best_size { + best_start = lo; + best_size = seg; + } + } + lo = h1; } - if sz > best_size { - best_start = s; - best_size = sz; + if e > lo { + let seg = e - lo; + if seg > best_size { + best_start = lo; + best_size = seg; + } } } } -- cgit v1.2.3