From 3e2261d83176752f3ea21e0c97f330b4c1757437 Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 4 Aug 2026 01:44:05 +0200 Subject: v0.5.9: fix OptiPlex heap crash — EBS retry must not rebuild the free list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: on real hardware SetMode can invalidate the pre-captured ExitBootServices map key, so EBS fails and the retry refreshed the map via capture_memory_map -> init_heap, which REBUILT the free list from the raw map and wiped the allocation state of every pre-EBS live object (the display shadow and the vt grids). Their spans became free while still live, later allocations carved inside the shadow, and the display writes clobbered them — zeroed back-pointers (family A ptr=0x404443e0 block=0x0) and gray glyph pixels (family B 0xaaaaaa00aaaaaa = 0x00AAAAAA = PALETTE[7] fg-7 text colour, not a firmware scrub). Fix: refresh_and_exit now re-captures the map and returns a fresh EBS key without rebuilding the free list (refresh_map_key); the free list is the authoritative live-allocation state. Verified in QEMU under a forced EBS failure (SIMULATE_EBS_FAILURE test hook): verify ok, probe NOT free, flhead outside the shadow — identical to a clean boot, and the full shell sequence is crash-free. Also: removed the crash-family debug markers from the screen (boot-time heapdbg lines, vt verify marker, shadow marker) — the vt grid self-check stays serial-only. Version 0.5.8 -> 0.5.9. --- rsdos/src/main.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'rsdos') diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs index 42f95e5..e40098d 100644 --- a/rsdos/src/main.rs +++ b/rsdos/src/main.rs @@ -185,7 +185,7 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut } else { rsnix::serial_println!("gop: not found (0x{:x})", gop_result); } - rsnix::gop::boot_marker("rsnix v0.5.5 booting.."); + rsnix::gop::boot_marker("rsnix v0.5.9 booting.."); rsnix::vt::init(); let (rows, cols) = rsnix::vt::size(); rsnix::serial_println!("vt: terminal ready ({}x{})", rows, cols); @@ -207,7 +207,15 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut } // ExitBootServices — we now own the machine - if unsafe { (bs.exit_boot_services)(image_handle, map_key) } != EFI_SUCCESS { + // DEBUG (OptiPlex sim): corrupt the first key so EBS fails once and + // the retry path (capture_memory_map -> init_heap rebuild) runs — the + // exact condition that wiped the pre-EBS shadow on real hardware. + let ebs_first_key = if rsnix::memory::simulate_ebs_failure() { + map_key ^ 1 + } else { + map_key + }; + if unsafe { (bs.exit_boot_services)(image_handle, ebs_first_key) } != EFI_SUCCESS { rsnix::serial_println!("WARN: ExitBootServices failed, retrying..."); match unsafe { rsnix::memory::refresh_and_exit(bs, image_handle) } { Ok(_) => {} @@ -351,14 +359,10 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut // whether the corruption is already present at shell entry or lands // later, and prints the exact field values when it is. rsnix::vt::debug_verify(); + shell::run(); } -/// Write the OptiPlex's 0x00AAAAAA scrub pattern over the stack region -/// the shell's frames will reuse, leaving only 256 B of live frame -/// headroom. 128 KiB covers the whole shell frame chain on QEMU and -/// the OptiPlex. Best-effort: the region is below rsp inside the boot -/// stack mapping; the call into `shell::run` overwrites the top word. // --------------------------------------------------------------------------- // Print a memory summary from the stashed memory map // --------------------------------------------------------------------------- -- cgit v1.2.3