summaryrefslogtreecommitdiffstats
path: root/shell/src/lib.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-02 01:34:58 +0200
committersalmonik <salmonik@tuta.io>2026-08-02 01:35:37 +0200
commit94d40dadeddfb40cd4fd237294037a562405a2c2 (patch)
treed099fa89a248b53eb7c17ca08489d05e3f50fa8f /shell/src/lib.rs
parentrsnix v0.5.3: fix real-hardware scroll wedge — per-word display push (diff)
downloadrs-dos-94d40dadeddfb40cd4fd237294037a562405a2c2.tar.gz
rs-dos-94d40dadeddfb40cd4fd237294037a562405a2c2.zip
v0.5.4: shadow backbuffer can no longer alias the framebuffer
Real-hardware scroll freeze (no exception, QEMU-clean) — the per-word push (0.5.3) did not fix it, so the wedge is upstream of the push. A QEMU slow-display simulation (new DISPLAY_STALL knob + shell 'stall' command busy-waits per display store, mimicking an uncached real-GPU framebuffer) proved the per-word push and shadow memmove are slow but finite — the shell keeps ticking, scrolls eventually complete. The freeze mechanism QEMU cannot exhibit is the shadow *landing on the framebuffer*: the heap free list spans the fb hole, so the 1.9 MB heap shadow can alias the display on machines where firmware reports the fb as ConventionalMemory — every scroll then becomes an MMIO->MMIO memcpy on an uncached framebuffer, which wedges real hardware (a stall, no fault, hence no dump). Fix: - gop::init_shadow(): allocate the shadow from the fb-aware page allocator (init_page_allocator marks fb pages used per-page), so it can never overlap the display; heap allocation kept only as a fallback with an explicit overlap rejection. Boot log now prints 'gop: shadow @ <addr> ... origin=page-alloc|heap|none'. - Scroll shadow memmove converted to per-word stores (belt and suspenders — immune to any future fb-aliased shadow). - Verified on QEMU: shadow @ 0x100000 vs fb 0x80000000..0x801d5000, overlap=false; all 5 test suites pass; scroll completes even under the stalled-display simulation.
Diffstat (limited to '')
-rw-r--r--shell/src/lib.rs12
1 files changed, 12 insertions, 0 deletions
diff --git a/shell/src/lib.rs b/shell/src/lib.rs
index 3090776..b2c4a1b 100644
--- a/shell/src/lib.rs
+++ b/shell/src/lib.rs
@@ -722,6 +722,7 @@ write `{} <path> TIL <marker>`",
722 "kill" => cmd_kill(&parsed), 722 "kill" => cmd_kill(&parsed),
723 "demo" => cmd_demo(&parsed), 723 "demo" => cmd_demo(&parsed),
724 "fault" => cmd_fault(), 724 "fault" => cmd_fault(),
725 "stall" => cmd_stall(&parsed),
725 _ => term_err(&alloc::format!("unknown command: {}", cmd)), 726 _ => term_err(&alloc::format!("unknown command: {}", cmd)),
726 } 727 }
727} 728}
@@ -819,6 +820,17 @@ fn cmd_fault() {
819 } 820 }
820} 821}
821 822
823/// Set the display-store stall (cycles per word) — diagnostics knob that
824/// simulates the per-write cost of an uncached real-GPU framebuffer so
825/// the preemptive scheduler races long scroll pushes like on real
826/// hardware. `stall 0` disables (default; QEMU RAM framebuffers are
827/// instant).
828fn cmd_stall(p: &Parsed) {
829 let n: u32 = p.args.first().and_then(|a| a.parse().ok()).unwrap_or(0);
830 rsnix::gop::DISPLAY_STALL.store(n, core::sync::atomic::Ordering::Relaxed);
831 term_println(&alloc::format!("stall: display store stall = {}", n));
832}
833
822fn cmd_clear() { 834fn cmd_clear() {
823 rsnix::gop::clear_screen(); 835 rsnix::gop::clear_screen();
824} 836}