From ab7d87bcde31c1681ea09c30534dde840a58d6fa Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 1 Aug 2026 22:28:34 +0200 Subject: rsnix v0.5.2: fault diagnostics + real-hardware scroll-crash hardening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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: '!!! 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. --- rsdos/src/main.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'rsdos') diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs index 13923ea..6dbad5f 100644 --- a/rsdos/src/main.rs +++ b/rsdos/src/main.rs @@ -87,16 +87,10 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut rsnix::serial::init(); rsnix::serial_println!("=== rsnix boot ==="); - // Stash the memory map - let map_key = match rsnix::memory::capture_memory_map(bs) { - Ok(k) => k, - Err(e) => { - rsnix::serial_println!("mem: capture_memory_map failed 0x{:x}", e); - 0 - } - }; - - // Locate GOP (Graphics Output Protocol) + // Locate GOP (Graphics Output Protocol) *before* the memory map is + // captured: the heap/page allocators need to know the framebuffer + // region so they never hand out its pages (some real firmware lists + // it as conventional memory). let mut gop_interface: *mut core::ffi::c_void = core::ptr::null_mut(); let gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; let gop_result = unsafe { @@ -106,6 +100,20 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut &mut gop_interface, ) }; + if gop_result == EFI_SUCCESS { + let gop = unsafe { &mut *(gop_interface as *mut GraphicsOutputProtocol) }; + rsnix::gop::peek_fb_region(gop); + } + + // Stash the memory map + let map_key = match rsnix::memory::capture_memory_map(bs) { + Ok(k) => k, + Err(e) => { + rsnix::serial_println!("mem: capture_memory_map failed 0x{:x}", e); + 0 + } + }; + if gop_result == EFI_SUCCESS { let gop = unsafe { &mut *(gop_interface as *mut GraphicsOutputProtocol) }; rsnix::serial_println!("gop: framebuffer found"); -- cgit v1.2.3