1use crate::types::irq_mutex::{IrqMutex, IrqMutexGuard};
7
8const LOG_BUFFER_SIZE: usize = u16::MAX as usize;
10
11struct KernelPrintState {
13 log_buf: [u8; LOG_BUFFER_SIZE],
15 log_head: usize,
17 log_tail: usize,
19 cursor_x: usize,
20 cursor_y: usize,
21}
22
23static KPRINT_STATE: IrqMutex<KernelPrintState> = IrqMutex::new(KernelPrintState {
25 log_buf: [0u8; LOG_BUFFER_SIZE],
26 log_head: 0,
27 log_tail: 0,
28 cursor_x: 0,
29 cursor_y: 0,
30});
31
32fn write_log_buf(state: &mut KernelPrintState, s: &str) {
34 for &b in s.as_bytes() {
35 state.log_buf[state.log_head % LOG_BUFFER_SIZE] = b;
36 state.log_head = state.log_head.wrapping_add(1);
37 if state.log_head.wrapping_sub(state.log_tail) > LOG_BUFFER_SIZE {
38 state.log_tail = state.log_tail.wrapping_add(1);
39 }
40 }
41}
42
43fn kprint(state: &mut IrqMutexGuard<'static, KernelPrintState>, string: &str, color: Option<u32>) {
45 use crate::SIMPLE_STATE;
46
47 write_log_buf(state, string);
48
49 if SIMPLE_STATE.serial.is_completed() {
50 use crate::logging::_serial::_Serial;
51 SIMPLE_STATE.serial.get().unwrap().write(string);
52 }
53
54 let basic_fb = &SIMPLE_STATE.basic_fb;
55 let basic_fb_psf2_font = &SIMPLE_STATE.basic_fb_psf2_font;
56
57 if basic_fb.is_completed() && basic_fb_psf2_font.is_completed() {
58 let fb = basic_fb.get().unwrap();
59 let font = basic_fb_psf2_font.get().unwrap();
60
61 let s = &mut **state;
62 font.draw_string(fb, string, &mut s.cursor_x, &mut s.cursor_y, color);
63
64 let last_row = fb.height as usize - font.glyph_height();
65 if s.cursor_y > last_row {
66 s.cursor_y = last_row;
67
68 unsafe {
70 let src = fb.fb_pointer.add(font.glyph_height() * fb.bytes_per_row as usize);
71 let dst = fb.fb_pointer;
72 let count = (fb.height as usize - font.glyph_height()) * fb.bytes_per_row as usize;
73 core::ptr::copy(src, dst, count);
74 }
75
76 unsafe {
78 let start = (fb.height as usize - font.glyph_height()) * fb.bytes_per_row as usize;
79 let end = fb.height as usize * fb.bytes_per_row as usize;
80 for i in start..end {
81 fb.fb_pointer.add(i).write_volatile(0u32);
82 }
83 }
84 }
85 }
86}
87
88pub unsafe fn force_unlock_kprint_state() {
94 KPRINT_STATE.force_unlock();
95}
96
97pub struct KernelWriter {
99 lock: IrqMutexGuard<'static, KernelPrintState>
100}
101impl KernelWriter {
102 pub fn lock() -> Self {
104 Self { lock: KPRINT_STATE.lock() }
105 }
106
107 pub fn print_raw(&mut self, string: &str, color: Option<u32>) {
109 kprint(&mut self.lock, string, color);
110 }
111}
112impl core::fmt::Write for KernelWriter {
113 fn write_str(&mut self, string: &str) -> core::fmt::Result {
114 kprint(&mut self.lock, string, None);
115 Ok(())
116 }
117}
118
119#[macro_export]
121macro_rules! kprint {
122 ($($arg:tt)*) => {
123 {
124 let _ = core::fmt::write(
125 &mut $crate::logging::kprint::KernelWriter::lock(),
126 format_args!($($arg)*)
127 );
128 }
129 };
130}
131
132pub enum LogLevelColor {
133 Emergency = 0x00ff00aa,
134 Alert = 0x00ffaa00,
135 Critical = 0x008a00ff,
136 Error = 0x00ff0000,
137 Warn = 0x00ffff00,
138 Info = 0x0000ff00,
139 Debug = 0x000000ff,
140}
141
142#[macro_export]
144macro_rules! kemerg {
145 ($($arg:tt)*) => {
146 {
147 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
148 let mut w = KernelWriter::lock();
149 w.print_raw("! ", Some(LogLevelColor::Emergency as u32));
150 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
151 w.print_raw("\n", None);
152 }
153 };
154}
155#[macro_export]
157macro_rules! kalert {
158 ($($arg:tt)*) => {
159 {
160 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
161 let mut w = KernelWriter::lock();
162 w.print_raw("A ", Some(LogLevelColor::Alert as u32));
163 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
164 w.print_raw("\n", None);
165 }
166 };
167}
168#[macro_export]
170macro_rules! kcrit {
171 ($($arg:tt)*) => {
172 {
173 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
174 let mut w = KernelWriter::lock();
175 w.print_raw("C ", Some(LogLevelColor::Critical as u32));
176 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
177 w.print_raw("\n", None);
178 }
179 };
180}
181#[macro_export]
183macro_rules! kerror {
184 ($($arg:tt)*) => {
185 {
186 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
187 let mut w = KernelWriter::lock();
188 w.print_raw("E ", Some(LogLevelColor::Error as u32));
189 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
190 w.print_raw("\n", None);
191 }
192 };
193}
194#[macro_export]
196macro_rules! kwarn {
197 ($($arg:tt)*) => {
198 {
199 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
200 let mut w = KernelWriter::lock();
201 w.print_raw("W ", Some(LogLevelColor::Warn as u32));
202 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
203 w.print_raw("\n", None);
204 }
205 };
206}
207#[macro_export]
209macro_rules! kinfo {
210 ($($arg:tt)*) => {
211 {
212 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
213 let mut w = KernelWriter::lock();
214 w.print_raw("I ", Some(LogLevelColor::Info as u32));
215 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
216 w.print_raw("\n", None);
217 }
218 };
219}
220#[macro_export]
222macro_rules! kdebug {
223 ($($arg:tt)*) => {
224 #[cfg(feature = "debug-logging")]
225 {
226 use $crate::logging::kprint::{KernelWriter, LogLevelColor};
227 let mut w = KernelWriter::lock();
228 w.print_raw("D ", Some(LogLevelColor::Debug as u32));
229 let _ = core::fmt::write(&mut w, format_args!($($arg)*));
230 w.print_raw("\n", None);
231 }
232 };
233}