summaryrefslogtreecommitdiffstats
path: root/rsnix/src/vt.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-17 14:53:52 +0200
committersalmonik <salmonik@tuta.io>2026-08-17 14:53:52 +0200
commitbe868a43185826b02bf6d091019bb779678525bb (patch)
tree586988c15f1d700b1621c7f0208584b30878a56c /rsnix/src/vt.rs
parentv0.5.10: change em-dashes to dashes (diff)
downloadrs-dos-be868a43185826b02bf6d091019bb779678525bb.tar.gz
rs-dos-be868a43185826b02bf6d091019bb779678525bb.zip
USB2/1.1 (EHCI/UHCI) drivers + real-hardware bring-up hardening
- Add polled EHCI (USB2) and UHCI (USB1.1) host-controller drivers with HID boot mouse support, wired into cursor polling and the 'usb' shell cmd - Add USB Legacy ownership handoff (claim_usb_legacy) plus config_write_byte - Harden boot: verify the PIT/timer ticks before shell entry, EOI stray interrupts in the LAPIC to stop interrupt storms, bound PS/2 controller waits, and INTx-disable AHCI (polled driver) - Add boot stage markers, klog screen echo, and QR lock; scheduler mark_shell_running; NO_USB stopgap to keep BIOS USB-Legacy input alive - alloc_pages_above for DMA buffers that must avoid low conventional memory - Expand DEBUG_NOTES with EHCI/QEMU bring-up findings
Diffstat (limited to '')
-rw-r--r--rsnix/src/vt.rs51
1 files changed, 49 insertions, 2 deletions
diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs
index 4ffb44d..9444063 100644
--- a/rsnix/src/vt.rs
+++ b/rsnix/src/vt.rs
@@ -121,9 +121,11 @@ pub fn init() {
121 COLS = cols; 121 COLS = cols;
122 CELLS = Box::into_raw(Box::new(vec![BLANK; rows * cols])); 122 CELLS = Box::into_raw(Box::new(vec![BLANK; rows * cols]));
123 RENDERED = Box::into_raw(Box::new(vec![BLANK; rows * cols])); 123 RENDERED = Box::into_raw(Box::new(vec![BLANK; rows * cols]));
124 CURSOR_R = 0; 124 // Home below row 0: row 0 is the boot-marker status line, so the
125 // terminal (shell + klog screen echo) must never write to it.
126 CURSOR_R = 1;
125 CURSOR_C = 0; 127 CURSOR_C = 0;
126 LAST_CURSOR = (0, 0); 128 LAST_CURSOR = (1, 0);
127 CURSOR_VISIBLE = true; 129 CURSOR_VISIBLE = true;
128 SGR_FG = 7; 130 SGR_FG = 7;
129 SGR_BG = 0; 131 SGR_BG = 0;
@@ -133,6 +135,13 @@ pub fn init() {
133 } 135 }
134} 136}
135 137
138/// True once the terminal is initialised (grids live). The klog screen
139/// echo checks this so serial lines printed before vt::init (very early
140/// boot) are skipped instead of hitting a null grid.
141pub fn ready() -> bool {
142 unsafe { ROWS != 0 && !CELLS.is_null() }
143}
144
136/// (rows, cols) — matches the editor's expected (rows, cols) ordering. 145/// (rows, cols) — matches the editor's expected (rows, cols) ordering.
137pub fn size() -> (usize, usize) { 146pub fn size() -> (usize, usize) {
138 unsafe { (ROWS, COLS) } 147 unsafe { (ROWS, COLS) }
@@ -667,10 +676,41 @@ pub fn sync_scroll() {
667// public writing API 676// public writing API
668// --------------------------------------------------------------------------- 677// ---------------------------------------------------------------------------
669 678
679/// Disable interrupts unless they are already off (nested-safe). Returns
680/// whether they were on, so `irq_restore` re-enables exactly when needed.
681/// The terminal write path uses this so a klog screen-echo (which can run
682/// in ISR context) can never tear a shell write, and a task-context write
683/// can never be split by a tick.
684fn irq_off() -> bool {
685 let rflags: u64;
686 unsafe {
687 core::arch::asm!(
688 "pushfq; pop {}",
689 out(reg) rflags,
690 options(nostack, preserves_flags)
691 );
692 if rflags & (1 << 9) != 0 {
693 core::arch::asm!("cli", options(nostack, preserves_flags));
694 true
695 } else {
696 false
697 }
698 }
699}
700
701fn irq_restore(was_on: bool) {
702 if was_on {
703 unsafe {
704 core::arch::asm!("sti", options(nostack, preserves_flags));
705 }
706 }
707}
708
670/// Write raw bytes (ANSI-capable). Used by full-screen apps. UTF-8 709/// Write raw bytes (ANSI-capable). Used by full-screen apps. UTF-8
671/// sequences are decoded so Unicode glyphs (box-drawing, arrows) render; 710/// sequences are decoded so Unicode glyphs (box-drawing, arrows) render;
672/// undecodable bytes become '?'. 711/// undecodable bytes become '?'.
673pub fn write_bytes(b: &[u8]) { 712pub fn write_bytes(b: &[u8]) {
713 let on = irq_off();
674 let mut i = 0; 714 let mut i = 0;
675 while i < b.len() { 715 while i < b.len() {
676 let byte = b[i]; 716 let byte = b[i];
@@ -701,20 +741,27 @@ pub fn write_bytes(b: &[u8]) {
701 } 741 }
702 } 742 }
703 flush(); 743 flush();
744 irq_restore(on);
704} 745}
705 746
706/// Write a UTF-8 string (plain text; Unicode glyphs render, others '?'). 747/// Write a UTF-8 string (plain text; Unicode glyphs render, others '?').
748/// Atomic with respect to interrupts: a klog screen-echo in ISR context
749/// cannot interleave with a shell write, and a tick cannot split a write.
707pub fn write_str(s: &str) { 750pub fn write_str(s: &str) {
751 let on = irq_off();
708 for c in s.chars() { 752 for c in s.chars() {
709 write_char(c); 753 write_char(c);
710 } 754 }
711 flush(); 755 flush();
756 irq_restore(on);
712} 757}
713 758
714/// Write a single ASCII byte / char. 759/// Write a single ASCII byte / char.
715pub fn put_char(b: u8) { 760pub fn put_char(b: u8) {
761 let on = irq_off();
716 put_byte(b); 762 put_byte(b);
717 flush(); 763 flush();
764 irq_restore(on);
718} 765}
719 766
720/// Clear the whole screen, reset colours, home the cursor. 767/// Clear the whole screen, reset colours, home the cursor.