Skip to main content

kernel/
printf.rs

1use core::fmt::{self, Write};
2use core::sync::atomic::{AtomicBool, Ordering};
3
4use crate::console::Console;
5use crate::proc;
6use crate::spinlock::SpinLock;
7
8/// Wrapper around console writer
9/// Only used to gate writing behind a mutex lock
10struct Writer;
11
12impl fmt::Write for Writer {
13    fn write_str(&mut self, s: &str) -> fmt::Result {
14        for byte in s.bytes() {
15            Console::putc(byte);
16        }
17        Ok(())
18    }
19}
20
21pub static PRINTF: Printf = Printf {
22    writer: SpinLock::new(Writer, "printf"),
23    locking: AtomicBool::new(true),
24    panicked: AtomicBool::new(false),
25};
26
27pub struct Printf {
28    writer: SpinLock<Writer>,
29    locking: AtomicBool,
30    panicked: AtomicBool,
31}
32
33impl Printf {
34    pub fn is_panicked(&self) -> bool {
35        self.panicked.load(Ordering::Relaxed)
36    }
37}
38
39pub fn _print(args: fmt::Arguments<'_>) {
40    let writer = if PRINTF.locking.load(Ordering::Relaxed) {
41        &mut *PRINTF.writer.lock()
42    } else {
43        // We are panicked, don't care about the lock
44        unsafe { PRINTF.writer.get_mut_unchecked() }
45    };
46
47    writer.write_fmt(args).unwrap();
48}
49
50#[macro_export]
51macro_rules! print {
52    ($($arg:tt)*) => {{
53        $crate::printf::_print(format_args!($($arg)*));
54    }};
55}
56
57#[macro_export]
58macro_rules! println {
59    ($fmt:literal $(,$($arg:tt)+)?) => {
60        $crate::printf::_print(format_args!(concat!($fmt, "\n") $(,$($arg)+)?))
61    };
62}
63
64pub fn panic(info: &core::panic::PanicInfo) -> ! {
65    PRINTF.locking.store(false, Ordering::Relaxed);
66
67    // Safety: we are panicked, don't care about the lock
68    let cpu_id = unsafe { proc::current_id() };
69
70    println!("! hart {} {}", cpu_id, info);
71
72    PRINTF.panicked.store(true, Ordering::Relaxed);
73
74    #[allow(clippy::empty_loop)]
75    loop {}
76}