summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CONTEXT.md4
-rw-r--r--rsnix/src/fs.rs2
-rw-r--r--rsnix/src/memory.rs7
-rw-r--r--rsnix/src/vt.rs33
4 files changed, 36 insertions, 10 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index 20c60f7..a1ef4bb 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -106,7 +106,9 @@ Single Rust crate (`x86_64-unknown-uefi` target). Module breakdown:
106- `vt.rs` — terminal emulator: cell grid, cursor, ANSI CSI parser (H/J/K, 106- `vt.rs` — terminal emulator: cell grid, cursor, ANSI CSI parser (H/J/K,
107 cursor moves, SGR 16-colour, `?25l/h`), dirty-cell blitting, UTF-8 107 cursor moves, SGR 16-colour, `?25l/h`), dirty-cell blitting, UTF-8
108 decoding (box-drawing `│`/`═`, arrows `←↑→↓`, em dash `—` render 108 decoding (box-drawing `│`/`═`, arrows `←↑→↓`, em dash `—` render
109 procedurally instead of `?`) 109 procedurally instead of `?`). The inverse cursor is mirrored into the
110 rendered grid so scrolling / `clear` can never strand stale inverse
111 cells on the framebuffer.
110- `tty.rs` — line discipline: canonical `read_line` (echo, line buffer, 112- `tty.rs` — line discipline: canonical `read_line` (echo, line buffer,
111 ^C/^D) and raw `read_byte` (terminal byte protocol: arrows → `ESC [ A–D`, 113 ^C/^D) and raw `read_byte` (terminal byte protocol: arrows → `ESC [ A–D`,
112 ^X → `0x18`, …) 114 ^X → `0x18`, …)
diff --git a/rsnix/src/fs.rs b/rsnix/src/fs.rs
index 95a84bf..df9308b 100644
--- a/rsnix/src/fs.rs
+++ b/rsnix/src/fs.rs
@@ -418,7 +418,7 @@ pub fn remove_path(path: &str) -> Result<(), ()> {
418 418
419fn version_text() -> String { 419fn version_text() -> String {
420 alloc::format!( 420 alloc::format!(
421 "rsnix v{} — TempleOS-inspired toy kernel\nUEFI x86_64, identity paging, free-list heap, bitmap pages\n", 421 "rsnix v{} — Official RS-DOS kernel\nUEFI x86_64, identity paging, free-list heap, bitmap pages\n",
422 env!("CARGO_PKG_VERSION") 422 env!("CARGO_PKG_VERSION")
423 ) 423 )
424} 424}
diff --git a/rsnix/src/memory.rs b/rsnix/src/memory.rs
index d33c781..c80edab 100644
--- a/rsnix/src/memory.rs
+++ b/rsnix/src/memory.rs
@@ -436,6 +436,11 @@ pub fn heap_stats() -> HeapStats {
436/// the heap itself (fixed-size stack arrays only). Returns true on success. 436/// the heap itself (fixed-size stack arrays only). Returns true on success.
437pub fn self_test() -> bool { 437pub fn self_test() -> bool {
438 unsafe { 438 unsafe {
439 // Snapshot the heap before we start: earlier boot code (e.g. the
440 // vt cell grids) may legitimately hold live allocations. The test
441 // must return the heap to exactly this state, not to "empty".
442 let before = heap_stats();
443
439 const N: usize = 128; 444 const N: usize = 128;
440 // (ptr, size, align) triplets — fixed array on the stack. 445 // (ptr, size, align) triplets — fixed array on the stack.
441 let mut blocks: [(usize, usize, usize); N] = [(0, 0, 0); N]; 446 let mut blocks: [(usize, usize, usize); N] = [(0, 0, 0); N];
@@ -504,7 +509,7 @@ pub fn self_test() -> bool {
504 ALLOCATOR.dealloc(*ptr as *mut u8, layout); 509 ALLOCATOR.dealloc(*ptr as *mut u8, layout);
505 } 510 }
506 let stats = heap_stats(); 511 let stats = heap_stats();
507 stats.free_blocks == 1 && stats.free_bytes == stats.heap_size 512 stats.free_blocks == before.free_blocks && stats.free_bytes == before.free_bytes
508 } 513 }
509} 514}
510 515
diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs
index 3b81d68..4db08fc 100644
--- a/rsnix/src/vt.rs
+++ b/rsnix/src/vt.rs
@@ -485,20 +485,29 @@ pub fn clear_all() {
485// --------------------------------------------------------------------------- 485// ---------------------------------------------------------------------------
486 486
487/// Blit every cell whose content differs from what the framebuffer shows, 487/// Blit every cell whose content differs from what the framebuffer shows,
488/// then draw the logical cursor (inverse video) on top. 488/// then draw the logical cursor (inverse video) on top. The cursor's
489/// inverse colours are mirrored into RENDERED so that pixel shifts
490/// (scrolling) or full clears can never leave a stale inverse block that
491/// the diff can't see (blank-vs-blank).
489fn flush() { 492fn flush() {
490 let rows = unsafe { ROWS }; 493 let rows = unsafe { ROWS };
491 let cols = unsafe { COLS }; 494 let cols = unsafe { COLS };
492 let n = rows * cols; 495 let n = rows * cols;
496 let cursor_visible = unsafe { CURSOR_VISIBLE };
497 let (cr, cc) = unsafe { (CURSOR_R, CURSOR_C) };
493 { 498 {
494 let cells = cells(); 499 let cells = cells();
495 let rendered = rendered_cells(); 500 let rendered = rendered_cells();
496 for i in 0..n { 501 for i in 0..n {
502 let row = i / cols;
503 let col = i % cols;
504 // The visible cursor cell is owned by the cursor pass below.
505 if cursor_visible && row == cr && col == cc {
506 continue;
507 }
497 let c = cells[i]; 508 let c = cells[i];
498 let r = rendered[i]; 509 let r = rendered[i];
499 if c != r { 510 if c != r {
500 let row = i / cols;
501 let col = i % cols;
502 let fg = PALETTE[c.fg as usize]; 511 let fg = PALETTE[c.fg as usize];
503 let bg = PALETTE[c.bg as usize]; 512 let bg = PALETTE[c.bg as usize];
504 gop::blit_glyph(col, row, c.ch, fg, bg); 513 gop::blit_glyph(col, row, c.ch, fg, bg);
@@ -510,20 +519,30 @@ fn flush() {
510 unsafe { 519 unsafe {
511 let (lr, lc) = LAST_CURSOR; 520 let (lr, lc) = LAST_CURSOR;
512 let moved = (lr, lc) != (CURSOR_R, CURSOR_C); 521 let moved = (lr, lc) != (CURSOR_R, CURSOR_C);
513 // Erase the previous cursor position (restore its normal colours). 522 // Erase the previous cursor position (restore its normal colours)
523 // and record it in RENDERED so the diff stays in sync.
514 if (moved || !CURSOR_VISIBLE) && lr < rows && lc < cols { 524 if (moved || !CURSOR_VISIBLE) && lr < rows && lc < cols {
515 let c = cells()[idx(lr, lc)]; 525 let i = idx(lr, lc);
526 let c = cells()[i];
516 let fg = PALETTE[c.fg as usize]; 527 let fg = PALETTE[c.fg as usize];
517 let bg = PALETTE[c.bg as usize]; 528 let bg = PALETTE[c.bg as usize];
518 gop::blit_glyph(lc, lr, c.ch, fg, bg); 529 gop::blit_glyph(lc, lr, c.ch, fg, bg);
530 rendered_cells()[i] = c;
519 } 531 }
520 LAST_CURSOR = (CURSOR_R, CURSOR_C); 532 LAST_CURSOR = (CURSOR_R, CURSOR_C);
521 // Draw the cursor as an inverse-video cell. 533 // Draw the cursor as an inverse-video cell, mirroring the inverse
534 // colours into RENDERED (scrolling/clearing then repair it).
522 if CURSOR_VISIBLE && CURSOR_R < rows && CURSOR_C < cols { 535 if CURSOR_VISIBLE && CURSOR_R < rows && CURSOR_C < cols {
523 let c = cells()[idx(CURSOR_R, CURSOR_C)]; 536 let i = idx(CURSOR_R, CURSOR_C);
537 let c = cells()[i];
524 let fg = PALETTE[c.fg as usize]; 538 let fg = PALETTE[c.fg as usize];
525 let bg = PALETTE[c.bg as usize]; 539 let bg = PALETTE[c.bg as usize];
526 gop::blit_glyph(CURSOR_C, CURSOR_R, c.ch, bg, fg); 540 gop::blit_glyph(CURSOR_C, CURSOR_R, c.ch, bg, fg);
541 rendered_cells()[i] = Cell {
542 ch: c.ch,
543 fg: c.bg,
544 bg: c.fg,
545 };
527 } 546 }
528 } 547 }
529} 548}