strat9_kernel/arch/x86_64/
vgabuf.rs1#[path = "vga/log_queue.rs"]
5mod log_queue;
6use core::sync::atomic::{AtomicBool, Ordering};
7use log_queue::{Line, LogQueue};
8
9static CONSOLE_TASK_ACTIVE: AtomicBool = AtomicBool::new(false);
10
11pub fn console_task_active() -> bool {
12 CONSOLE_TASK_ACTIVE.load(Ordering::Acquire)
13}
14
15pub const VGABUF_CAPACITY: usize = log_queue::CAPACITY;
16pub const VGABUF_LINE_LEN: usize = log_queue::LINE_LEN;
17static QUEUE: LogQueue = LogQueue::new();
18const FLUSH_BATCH: usize = 30;
19
20pub fn vgabuf_write(line: &[u8]) {
21 QUEUE.push(line);
22}
23pub fn vgabuf_total_written() -> usize {
24 QUEUE.written()
25}
26pub fn vgabuf_total_dropped() -> usize {
27 QUEUE.dropped()
28}
29
30fn write_line(writer: &mut impl core::fmt::Write, line: &Line) {
31 if let Ok(s) = core::str::from_utf8(line.as_bytes()) {
32 let _ = writer.write_str(s);
33 if !s.ends_with('\n') {
34 let _ = writer.write_str("\n");
35 }
36 } else {
37 let _ = writer.write_str("<non-utf8>\n");
38 }
39}
40
41pub fn vgabuf_flush_to_framebuffer() {
44 if !crate::arch::x86_64::vga::is_available() {
45 vgabuf_drain_discard();
46 return;
47 }
48 let Some(mut writer) = crate::arch::x86_64::vga::VGA_WRITER.try_lock() else {
49 return;
50 };
51 let mut flushed = 0;
52 for _ in 0..FLUSH_BATCH {
53 let Some(line) = QUEUE.pop() else {
54 break;
55 };
56 write_line(&mut *writer, &line);
57 flushed += 1;
58 }
59 if flushed > 0 {
60 writer.flush_display();
61 } else {
62 writer.present_if_due(false);
63 }
64}
65
66fn vgabuf_drain_discard() {
67 for _ in 0..VGABUF_CAPACITY {
68 if QUEUE.pop().is_none() {
69 break;
70 }
71 }
72}
73
74pub fn vgabuf_flush_all() {
75 if !crate::arch::x86_64::vga::is_available() {
76 vgabuf_drain_discard();
77 return;
78 }
79 let Some(mut writer) = crate::arch::x86_64::vga::VGA_WRITER.try_lock() else {
80 vgabuf_flush_all_direct();
81 return;
82 };
83 for _ in 0..VGABUF_CAPACITY {
84 let Some(line) = QUEUE.pop() else {
85 break;
86 };
87 write_line(&mut *writer, &line);
88 }
89 writer.present_if_due(true);
90}
91
92fn vgabuf_flush_all_direct() {
93 const MAX_LINES: usize = 16;
96 let mut owned = [Line::EMPTY; MAX_LINES];
97 let mut count = 0;
98 for slot in &mut owned {
99 let Some(line) = QUEUE.pop() else {
100 break;
101 };
102 *slot = line;
103 count += 1;
104 }
105 let mut lines = [""; MAX_LINES];
106 for i in 0..count {
107 lines[i] = core::str::from_utf8(owned[i].as_bytes()).unwrap_or("<non-utf8>");
108 }
109 if count > 0 {
110 crate::arch::x86_64::vga::panic_draw_direct(&lines[..count]);
111 }
112}
113
114pub extern "C" fn console_task_main() -> ! {
116 CONSOLE_TASK_ACTIVE.store(true, Ordering::Release);
117 let mut last_tick = u64::MAX;
118 loop {
119 let tick = crate::process::scheduler::ticks();
120 if tick != last_tick {
121 last_tick = tick;
122 if !crate::debug_cfg::is_quiet() {
123 vgabuf_flush_to_framebuffer();
124 }
125 }
126 crate::process::yield_task();
127 }
128}