summaryrefslogtreecommitdiffstats
path: root/rsnix/src
diff options
context:
space:
mode:
Diffstat (limited to 'rsnix/src')
-rw-r--r--rsnix/src/gop.rs72
1 files changed, 56 insertions, 16 deletions
diff --git a/rsnix/src/gop.rs b/rsnix/src/gop.rs
index 437bf9d..7b97d14 100644
--- a/rsnix/src/gop.rs
+++ b/rsnix/src/gop.rs
@@ -265,28 +265,40 @@ pub fn init_shadow() {
265 let mut origin = "none"; 265 let mut origin = "none";
266 266
267 // Primary: fb-aware page allocator (fb pages already marked 267 // Primary: fb-aware page allocator (fb pages already marked
268 // used by init_page_allocator). 268 // used by init_page_allocator). Defensively refuse the range if
269 // it ever overlaps the fb region anyway.
269 if let Some(p) = crate::memory::alloc_pages(pages) { 270 if let Some(p) = crate::memory::alloc_pages(pages) {
270 SHADOW = p as *mut u32;
271 SHADOW_WORDS = words;
272 origin = "page-alloc";
273 for i in 0..words {
274 *SHADOW.add(i) = fb.bg;
275 }
276 } else {
277 // Fallback: heap, rejected if it overlaps the fb region.
278 let v: alloc::vec::Vec<u32> = alloc::vec![0; words];
279 let p = v.as_ptr() as usize;
280 let overlaps = FB_REGION_SIZE > 0 271 let overlaps = FB_REGION_SIZE > 0
281 && p < FB_REGION_BASE + FB_REGION_SIZE 272 && p < FB_REGION_BASE + FB_REGION_SIZE
282 && p + bytes > FB_REGION_BASE; 273 && p + bytes > FB_REGION_BASE;
283 if !overlaps { 274 if !overlaps {
284 SHADOW = v.as_ptr() as *mut u32; 275 SHADOW = p as *mut u32;
285 SHADOW_WORDS = words; 276 SHADOW_WORDS = words;
286 origin = "heap"; 277 origin = "page-alloc";
287 core::mem::forget(v); // shadow owns the memory now 278 for i in 0..words {
288 } else { 279 *SHADOW.add(i) = fb.bg;
289 drop(v); 280 }
281 }
282 }
283 if origin == "none" {
284 // Fallback: heap — must never panic here: an OOM would halt
285 // the kernel before the shell banner, a blank screen on real
286 // hardware (the old `vec![0; words]` could abort). On any
287 // failure we degrade to no-shadow mode instead.
288 #[allow(clippy::slow_vector_initialization)] // deliberate: try_reserve must not panic
289 let mut v: alloc::vec::Vec<u32> = alloc::vec::Vec::new();
290 if v.try_reserve_exact(words).is_ok() {
291 v.resize(words, 0); // can't fail after the reserve
292 let p = v.as_ptr() as usize;
293 let overlaps = FB_REGION_SIZE > 0
294 && p < FB_REGION_BASE + FB_REGION_SIZE
295 && p + bytes > FB_REGION_BASE;
296 if !overlaps {
297 SHADOW = v.as_ptr() as *mut u32;
298 SHADOW_WORDS = words;
299 origin = "heap";
300 core::mem::forget(v); // shadow owns the memory now
301 }
290 } 302 }
291 } 303 }
292 let (rbase, rsize) = (FB_REGION_BASE, FB_REGION_SIZE); 304 let (rbase, rsize) = (FB_REGION_BASE, FB_REGION_SIZE);
@@ -319,6 +331,34 @@ pub fn init_shadow() {
319 } 331 }
320} 332}
321 333
334/// Draw a one-line boot-progress marker to the display (row 0,
335/// white-on-black). Real hardware has no serial console, so every
336/// boot stage is written straight to the framebuffer — the last visible
337/// marker before a hang identifies where the kernel died. Uses the
338/// direct-display glyph path (the shadow may not exist yet in early
339/// boot); the shell banner overwrites row 0 at first paint.
340pub fn boot_marker(msg: &str) {
341 let Some(fb) = fb().as_ref() else {
342 return;
343 };
344 let cols = fb.width / 8;
345 let white = (0xFFu8, 0xFFu8, 0xFFu8);
346 let black = (0x00u8, 0x00u8, 0x00u8);
347 let mut c = 0usize;
348 for &b in msg.as_bytes().iter().take(cols) {
349 if b < 0x80 {
350 blit_glyph(c, 0, b as u16, white, black);
351 c += 1;
352 }
353 }
354 // Blank the rest of the row so a shorter message can't leave stale
355 // glyphs behind.
356 while c < cols {
357 blit_glyph(c, 0, b' ' as u16, white, black);
358 c += 1;
359 }
360}
361
322// --------------------------------------------------------------------------- 362// ---------------------------------------------------------------------------
323// Public text API — the text surface now lives in `crate::vt`; these wrappers 363// Public text API — the text surface now lives in `crate::vt`; these wrappers
324// keep callers (shell, macros) unchanged. 364// keep callers (shell, macros) unchanged.