1use core::fmt;
2
3const UART0_BASE: usize = 0x3F20_1000;
4
5const UART0_DR: *mut u32 = UART0_BASE as *mut u32;
6const UART0_FR: *mut u32 = (UART0_BASE + 0x18) as *mut u32;
7const UART0_IBRD: *mut u32 = (UART0_BASE + 0x24) as *mut u32;
8const UART0_FBRD: *mut u32 = (UART0_BASE + 0x28) as *mut u32;
9const UART0_LCRH: *mut u32 = (UART0_BASE + 0x2C) as *mut u32;
10const UART0_CR: *mut u32 = (UART0_BASE + 0x30) as *mut u32;
11const UART0_IMSC: *mut u32 = (UART0_BASE + 0x38) as *mut u32;
12const UART0_ICR: *mut u32 = (UART0_BASE + 0x44) as *mut u32;
13
14const GPIO_BASE: usize = 0x3F20_0000;
16const GPFSEL1: *mut u32 = (GPIO_BASE + 0x04) as *mut u32;
17const GPPUD: *mut u32 = (GPIO_BASE + 0x94) as *mut u32;
18const GPPUDCLK0: *mut u32 = (GPIO_BASE + 0x98) as *mut u32;
19
20pub struct Uart;
21
22static mut SERIAL_CHAR_COUNT: usize = 0;
23
24impl Uart {
25 fn query_uart_clock() -> u32 {
27 #[repr(C, align(16))]
30 struct ClockReq {
31 buf: [u32; 9],
32 }
33 let mut req = ClockReq {
34 buf: [
35 9 * 4, 0, 0x0003_0002, 8, 0, 0x0000_0002, 0, 0, 0,
44 ],
45 };
46 let ptr = req.buf.as_mut_ptr();
47 let slice = unsafe { core::slice::from_raw_parts_mut(ptr, 9) };
48
49 unsafe {
51 let addr = slice.as_ptr() as usize;
52 let cache_line = 64usize;
53 let start = addr & !(cache_line - 1);
54 let end = addr + 9 * 4;
55 let mut cur = start;
56 while cur < end {
57 core::arch::asm!("dc civac, {}", in(reg) cur, options(nostack));
58 cur += cache_line;
59 }
60 core::arch::asm!("dsb sy", options(nostack));
61 }
62
63 const MBOX_BASE: usize = 0x3F00_B880;
65 const MBOX_READ: *mut u32 = MBOX_BASE as *mut u32;
66 const MBOX_STATUS: *mut u32 = (MBOX_BASE + 0x18) as *mut u32;
67 const MBOX_WRITE: *mut u32 = (MBOX_BASE + 0x20) as *mut u32;
68
69 let addr_val = req.buf.as_ptr() as u32;
70 let data = (addr_val & !0xF) | 8; unsafe {
73 while (core::ptr::read_volatile(MBOX_STATUS) & 0x8000_0000) != 0 {}
74 core::ptr::write_volatile(MBOX_WRITE, data);
75 loop {
76 while (core::ptr::read_volatile(MBOX_STATUS) & 0x4000_0000) != 0 {}
77 let res = core::ptr::read_volatile(MBOX_READ);
78 if res == data {
79 break;
80 }
81 }
82 let addr = slice.as_ptr() as usize;
84 let cache_line = 64usize;
85 let start = addr & !(cache_line - 1);
86 let end = addr + 9 * 4;
87 let mut cur = start;
88 while cur < end {
89 core::arch::asm!("dc civac, {}", in(reg) cur, options(nostack));
90 cur += cache_line;
91 }
92 core::arch::asm!("dsb sy", options(nostack));
93 }
94
95 if req.buf[1] == 0x8000_0000 && req.buf[6] != 0 {
96 req.buf[6]
97 } else {
98 48_000_000 }
100 }
101
102 pub fn init() {
103 unsafe {
104 core::ptr::write_volatile(UART0_CR, 0);
106
107 let mut gpfsel1 = core::ptr::read_volatile(GPFSEL1);
109 gpfsel1 &= !(0b111 << 12);
111 gpfsel1 |= 0b100 << 12;
112 gpfsel1 &= !(0b111 << 15);
114 gpfsel1 |= 0b100 << 15;
115 core::ptr::write_volatile(GPFSEL1, gpfsel1);
116
117 core::ptr::write_volatile(GPPUD, 0);
119 for _ in 0..150 {
120 core::arch::asm!("nop");
121 }
122 core::ptr::write_volatile(GPPUDCLK0, (1 << 14) | (1 << 15));
123 for _ in 0..150 {
124 core::arch::asm!("nop");
125 }
126 core::ptr::write_volatile(GPPUDCLK0, 0);
127
128 core::ptr::write_volatile(UART0_ICR, 0x7FF);
130
131 core::ptr::write_volatile(UART0_IMSC, 0);
133
134 let uart_clk = Self::query_uart_clock();
137 let baud = 115200u32;
138 let divisor_x64 = ((uart_clk as u64) * 4) / (baud as u64); let ibrd = (divisor_x64 / 64) as u32;
140 let fbrd = (divisor_x64 % 64) as u32;
141 core::ptr::write_volatile(UART0_IBRD, ibrd);
142 core::ptr::write_volatile(UART0_FBRD, fbrd);
143
144 core::ptr::write_volatile(UART0_LCRH, 0x70);
146
147 core::ptr::write_volatile(UART0_CR, 0x301);
149 }
150 }
151
152 pub fn send(c: u8) {
153 unsafe {
154 while (core::ptr::read_volatile(UART0_FR) & 0x20) != 0 {}
156 core::ptr::write_volatile(UART0_DR, c as u32);
157 }
158 }
159
160 pub fn has_char() -> bool {
162 unsafe { (core::ptr::read_volatile(UART0_FR) & 0x10) == 0 }
163 }
164
165 pub fn recv() -> u8 {
167 unsafe {
168 while !Self::has_char() {}
169 (core::ptr::read_volatile(UART0_DR) & 0xFF) as u8
170 }
171 }
172
173 pub fn send_string(s: &str) {
174 unsafe {
175 let mut prev = 0u8;
176 for b in s.bytes() {
177 if b == b'\n' {
178 if prev != b'\r' {
179 Self::send(b'\r');
180 }
181 Self::send(b);
182 SERIAL_CHAR_COUNT = 0;
183 prev = b;
184 } else {
185 if !crate::AUTO_TEST_BROWSER && SERIAL_CHAR_COUNT >= 55 {
186 Self::send(b'\r');
187 Self::send(b'\n');
188 SERIAL_CHAR_COUNT = 0;
189 }
190 Self::send(b);
191 if !crate::AUTO_TEST_BROWSER {
192 SERIAL_CHAR_COUNT += 1;
193 }
194 prev = b;
195 }
196 }
197 }
198 }
199}
200
201impl fmt::Write for Uart {
202 fn write_str(&mut self, s: &str) -> fmt::Result {
203 Self::send_string(s);
204 Ok(())
205 }
206}
207
208#[macro_export]
210macro_rules! print {
211 ($($arg:tt)*) => {
212 $crate::kernel::uart::emit_raw(core::format_args!($($arg)*));
215 };
216}
217
218#[macro_export]
219macro_rules! println {
220 () => ($crate::print!("\n"));
221 ($($arg:tt)*) => ({
226 $crate::kernel::uart::emit_raw(core::format_args!("{}\n", core::format_args!($($arg)*)));
227 })
228}
229
230use core::sync::atomic::{AtomicBool, Ordering};
231
232static IS_SILENT: AtomicBool = AtomicBool::new(false);
233
234pub fn set_silent(silent: bool) {
235 IS_SILENT.store(silent, Ordering::Relaxed);
236}
237
238pub fn is_silent() -> bool {
239 IS_SILENT.load(Ordering::Relaxed)
240}
241
242static LOG_LOCK: spin::Mutex<()> = spin::Mutex::new(());
255
256fn try_lock_log() -> Option<spin::MutexGuard<'static, ()>> {
280 let start = crate::kernel::timer::get_ticks();
281 let mut spins: u32 = 0;
282 loop {
283 if let Some(g) = LOG_LOCK.try_lock() {
284 return Some(g);
285 }
286 core::hint::spin_loop();
287 spins = spins.wrapping_add(1);
288 if crate::kernel::timer::get_ticks().wrapping_sub(start) > 20 {
290 return None;
291 }
292 if spins > 50_000_000 {
294 return None;
295 }
296 }
297}
298
299pub fn emit_raw(args: core::fmt::Arguments) {
309 use core::fmt::Write;
310 let guard = try_lock_log();
311 let mut uart = Uart;
312 let _ = uart.write_fmt(args);
313 #[allow(unused_unsafe)]
314 unsafe {
315 if crate::kernel::draw::SPLASH_ACTIVE {
316 let mut writer = crate::kernel::draw::SplashWriter;
317 let _ = writer.write_fmt(args);
318 }
319 }
320 drop(guard);
321}
322
323pub fn emit_line(level_str: &str, args: core::fmt::Arguments) {
324 use core::fmt::Write;
325 let mut line = crate::kernel::uart_line_buf::LineBuf::new();
326 let _ = line.write_str(level_str);
327 let _ = line.write_str(" ");
328 let _ = line.write_fmt(args);
329 if line.was_truncated() {
330 line.trim_to_char_boundary();
333 let _ = line.write_str("...");
334 }
335 let _ = line.write_str("\n");
336
337 let guard = try_lock_log();
338
339 let text = core::str::from_utf8(line.as_bytes()).unwrap_or("[log: invalid utf-8]\n");
341 let mut uart = Uart;
342 let _ = uart.write_str(text);
343 #[allow(unused_unsafe)]
344 unsafe {
345 if crate::kernel::draw::SPLASH_ACTIVE {
346 let mut writer = crate::kernel::draw::SplashWriter;
347 let _ = writer.write_str(text);
348 }
349 }
350 drop(guard);
351}
352
353#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
354pub enum LogLevel {
355 Error = 0,
356 Warn = 1,
357 Info = 2,
358 Debug = 3,
359}
360
361pub const CURRENT_LOG_LEVEL: LogLevel = LogLevel::Warn;
363
364#[macro_export]
365macro_rules! log {
366 ($level:expr, $($arg:tt)*) => {
367 if !$crate::kernel::uart::is_silent() {
368 if $level <= $crate::kernel::uart::CURRENT_LOG_LEVEL {
369 let level_str = match $level {
370 $crate::kernel::uart::LogLevel::Error => "[ERROR]",
371 $crate::kernel::uart::LogLevel::Warn => "[WARN ]",
372 $crate::kernel::uart::LogLevel::Info => "[INFO ]",
373 $crate::kernel::uart::LogLevel::Debug => "[DEBUG]",
374 };
375 $crate::kernel::uart::emit_line(level_str, core::format_args!($($arg)*));
381 }
382 }
383 };
384}
385
386#[macro_export]
387macro_rules! error {
388 ($($arg:tt)*) => ($crate::log!($crate::kernel::uart::LogLevel::Error, $($arg)*));
389}
390
391#[macro_export]
392macro_rules! warn {
393 ($($arg:tt)*) => ($crate::log!($crate::kernel::uart::LogLevel::Warn, $($arg)*));
394}
395
396#[macro_export]
397macro_rules! info {
398 ($($arg:tt)*) => ($crate::log!($crate::kernel::uart::LogLevel::Info, $($arg)*));
399}
400
401#[macro_export]
402macro_rules! debug {
403 ($($arg:tt)*) => ($crate::log!($crate::kernel::uart::LogLevel::Debug, $($arg)*));
404}