diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-02 23:28:29 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-02 23:28:29 +0200 |
| commit | f846a9551bf30d61026fa9c9ccea78479ced321b (patch) | |
| tree | 10158ca300cc51f44fc9afee9c2b3092554d880b /rsnix | |
| parent | v0.5.7: guard reports the drop's size/align — identifies the clobbered struct (diff) | |
| download | rs-dos-f846a9551bf30d61026fa9c9ccea78479ced321b.tar.gz rs-dos-f846a9551bf30d61026fa9c9ccea78479ced321b.zip | |
v0.5.7: drop test-poison hooks; vt heap-struct verify at shell entry
The OptiPlex's first banner write #GPs when the vt cells VecData holds
firmware 0xAA fill instead of a real buffer pointer. The poison/fill
test hooks (stack + free-heap + free-page 0x00AAAAAA) were removed from
the release image — they changed boot behavior and may walk a corrupt
free list over live blocks. Added vt::debug_verify() (cells/rendered
ptr/cap/len + in-heap check) at shell entry: the next real-hardware
boot shows whether the corruption is present at shell entry or lands
during the banner write.
Diffstat (limited to 'rsnix')
| -rw-r--r-- | rsnix/src/vt.rs | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs index 4578f6c..6343b78 100644 --- a/rsnix/src/vt.rs +++ b/rsnix/src/vt.rs | |||
| @@ -138,6 +138,48 @@ pub fn size() -> (usize, usize) { | |||
| 138 | unsafe { (ROWS, COLS) } | 138 | unsafe { (ROWS, COLS) } |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | /// Shell-entry self-check: dump the vt grid's heap structs so a real- | ||
| 142 | /// hardware boot shows whether the cells VecData / data arrays are sane | ||
| 143 | /// at shell entry (the OptiPlex's first banner write #GPs when the | ||
| 144 | /// cells buffer holds firmware 0xAA fill instead of real pointers). | ||
| 145 | pub fn debug_verify() { | ||
| 146 | unsafe { | ||
| 147 | let total = ROWS * COLS; | ||
| 148 | let msg = |m: &str| { | ||
| 149 | crate::serial_println!("vt: {}", m); | ||
| 150 | }; | ||
| 151 | if CELLS.is_null() || RENDERED.is_null() { | ||
| 152 | msg("verify: cells/renderd NULL — vt::init did not run"); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | let c = &*(CELLS as *const Vec<Cell>); | ||
| 156 | let r = &*(RENDERED as *const Vec<Cell>); | ||
| 157 | msg(&alloc::format!( | ||
| 158 | "verify: cells ptr={:#x} cap={:#x} len={:#x} rendered ptr={:#x} cap={:#x} len={:#x} want={:#x}", | ||
| 159 | c.as_ptr() as usize, | ||
| 160 | c.capacity(), | ||
| 161 | c.len(), | ||
| 162 | r.as_ptr() as usize, | ||
| 163 | r.capacity(), | ||
| 164 | r.len(), | ||
| 165 | total | ||
| 166 | )); | ||
| 167 | // The cells array must cover rows*cols and be inside the heap. | ||
| 168 | let heap_ok = crate::memory::heap_range() | ||
| 169 | .map(|(hs, he)| { | ||
| 170 | let p = c.as_ptr() as usize; | ||
| 171 | let bytes = c.capacity().saturating_mul(core::mem::size_of::<Cell>()); | ||
| 172 | p >= hs && p + bytes <= he | ||
| 173 | }) | ||
| 174 | .unwrap_or(false); | ||
| 175 | if c.len() != total || r.len() != total || !heap_ok { | ||
| 176 | msg("verify: FAILED — cells/rendered not sane at shell entry"); | ||
| 177 | } else { | ||
| 178 | msg("verify: ok"); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 141 | pub fn set_cursor_visible(v: bool) { | 183 | pub fn set_cursor_visible(v: bool) { |
| 142 | sync_scroll(); | 184 | sync_scroll(); |
| 143 | unsafe { | 185 | unsafe { |
