diff options
Diffstat (limited to 'rsnix/src/vt.rs')
| -rw-r--r-- | rsnix/src/vt.rs | 69 |
1 files changed, 44 insertions, 25 deletions
diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs index 88f8d43..4ffb44d 100644 --- a/rsnix/src/vt.rs +++ b/rsnix/src/vt.rs | |||
| @@ -138,6 +138,29 @@ pub fn size() -> (usize, usize) { | |||
| 138 | unsafe { (ROWS, COLS) } | 138 | unsafe { (ROWS, COLS) } |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | /// DEBUG (crash-family): read one cell's raw word (ch | fg<<16 | bg<<24) | ||
| 142 | /// from the live cells grid and the rendered grid, for the given text | ||
| 143 | /// row/col. Returns (raw_cell, raw_rendered). | ||
| 144 | pub fn cell_raw(r: usize, c: usize) -> (u32, u32) { | ||
| 145 | unsafe { | ||
| 146 | if CELLS.is_null() || RENDERED.is_null() { | ||
| 147 | return (0xFFFF_FFFF, 0xFFFF_FFFF); | ||
| 148 | } | ||
| 149 | let raw = |v: &Vec<Cell>| -> u32 { | ||
| 150 | if r < ROWS && c < COLS { | ||
| 151 | let cell = v[r * COLS + c]; | ||
| 152 | cell.ch as u32 | ((cell.fg as u32) << 16) | ((cell.bg as u32) << 24) | ||
| 153 | } else { | ||
| 154 | 0xFFFF_FFFE | ||
| 155 | } | ||
| 156 | }; | ||
| 157 | ( | ||
| 158 | raw(&*(CELLS as *const Vec<Cell>)), | ||
| 159 | raw(&*(RENDERED as *const Vec<Cell>)), | ||
| 160 | ) | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 141 | /// Shell-entry self-check: dump the vt grid's heap structs so a real- | 164 | /// 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 | 165 | /// hardware boot shows whether the cells VecData / data arrays are sane |
| 143 | /// at shell entry (the OptiPlex's first banner write #GPs when the | 166 | /// at shell entry (the OptiPlex's first banner write #GPs when the |
| @@ -184,9 +207,12 @@ pub fn debug_verify() { | |||
| 184 | // other three probe slots as zero-initialized). A stale cells | 207 | // other three probe slots as zero-initialized). A stale cells |
| 185 | // data pointer that happens to be in-heap still passes the | 208 | // data pointer that happens to be in-heap still passes the |
| 186 | // range checks (len/cap look fine) but its "cells" read back as | 209 | // range checks (len/cap look fine) but its "cells" read back as |
| 187 | // the underlying memory's leftover fill — the OptiPlex shows | 210 | // the underlying memory's leftover fill. NOTE: the OptiPlex |
| 188 | // the firmware 0x00AAAAAA scrub there. BLANK (0x70020) vs | 211 | // dump value 0x00AAAAAA is the VGA GRAY text colour |
| 189 | // scrub (0x00AAAAAA) is cleanly distinguishable. | 212 | // (rgb(170,170,170) = PALETTE[7] = fg 7), i.e. rendered shadow |
| 213 | // pixels — the memory read as heap held display text, not a | ||
| 214 | // firmware scrub. BLANK (0x70020) vs 0x00AAAAAA is cleanly | ||
| 215 | // distinguishable. | ||
| 190 | let blank_raw = BLANK.ch as u32 | ((BLANK.fg as u32) << 16) | ((BLANK.bg as u32) << 24); | 216 | let blank_raw = BLANK.ch as u32 | ((BLANK.fg as u32) << 16) | ((BLANK.bg as u32) << 24); |
| 191 | let mut content_ok = true; | 217 | let mut content_ok = true; |
| 192 | let mut rcontent_ok = true; | 218 | let mut rcontent_ok = true; |
| @@ -269,31 +295,24 @@ pub fn debug_verify() { | |||
| 269 | r_probes_raw[2], | 295 | r_probes_raw[2], |
| 270 | r_probes_raw[3] | 296 | r_probes_raw[3] |
| 271 | )); | 297 | )); |
| 272 | // Bottom-anchored: row 0-1 get overwritten by the shell | 298 | // NOTE: debug markers are serial-only now; the crash family |
| 273 | // banner, row 2 by the prompt (and a stale crash.log | 299 | // was resolved (EBS-retry free-list rebuild) and the screen |
| 274 | // replays at rows 2+), so this marker must live at the very | 300 | // must stay clean for users. |
| 275 | // bottom to stay readable until the user can copy it. | 301 | crate::serial_println!( |
| 276 | crate::gop::boot_marker_at( | 302 | "vt: c {:#x} cap={:#x} {} | r {:#x} {}", |
| 277 | &alloc::format!( | 303 | c.as_ptr() as usize, |
| 278 | "vt: c {:#x} cap={:#x} {} | r {:#x} {}", | 304 | c.capacity(), |
| 279 | c.as_ptr() as usize, | 305 | if content_ok { "ok" } else { "GARBAGE" }, |
| 280 | c.capacity(), | 306 | r.as_ptr() as usize, |
| 281 | if content_ok { "ok" } else { "GARBAGE" }, | 307 | if rcontent_ok { "ok" } else { "GARBAGE" } |
| 282 | r.as_ptr() as usize, | ||
| 283 | if rcontent_ok { "ok" } else { "GARBAGE" } | ||
| 284 | ), | ||
| 285 | crate::gop::bottom_row(1), | ||
| 286 | ); | 308 | ); |
| 287 | } else { | 309 | } else { |
| 288 | msg("verify: ok"); | 310 | msg("verify: ok"); |
| 289 | crate::gop::boot_marker_at( | 311 | crate::serial_println!( |
| 290 | &alloc::format!( | 312 | "vt: c {:#x} cap={:#x} ok | r {:#x} ok", |
| 291 | "vt: c {:#x} cap={:#x} ok | r {:#x} ok", | 313 | c.as_ptr() as usize, |
| 292 | c.as_ptr() as usize, | 314 | c.capacity(), |
| 293 | c.capacity(), | 315 | r.as_ptr() as usize |
| 294 | r.as_ptr() as usize | ||
| 295 | ), | ||
| 296 | crate::gop::bottom_row(1), | ||
| 297 | ); | 316 | ); |
| 298 | } | 317 | } |
| 299 | } | 318 | } |
