kernel/
printf.rs

1use core::fmt::{self, Write};
2use core::panic::PanicInfo;
3use core::sync::atomic::{AtomicBool, Ordering};
4
5use crate::console;
6use crate::proc::Cpus;
7use crate::spinlock::Mutex;
8
9pub static PRINTF: Printf = Printf {
10    writer: Mutex::new(Writer, "printf"),
11    locking: AtomicBool::new(true),
12    panicked: AtomicBool::new(false),
13};
14
15pub struct Printf {
16    writer: Mutex<Writer>,
17    locking: AtomicBool,
18    panicked: AtomicBool,
19}
20
21impl Printf {
22    pub fn is_panicked(&self) -> &AtomicBool {
23        &self.panicked
24    }
25}
26
27pub struct Writer;
28
29impl Writer {
30    fn print(&self, c: u8) {
31        console::putc(c)
32    }
33}
34
35impl fmt::Write for Writer {
36    fn write_str(&mut self, s: &str) -> fmt::Result {
37        for byte in s.bytes() {
38            self.print(byte);
39        }
40        Ok(())
41    }
42}
43
44pub fn _print(args: fmt::Arguments<'_>, newline: bool) {
45    if PRINTF.locking.load(Ordering::Relaxed) {
46        let mut lock = PRINTF.writer.lock();
47        lock.write_fmt(args).unwrap();
48        if newline {
49            lock.write_char('\n');
50        }
51    } else {
52        // We are panicked, don't care about the lock
53        unsafe {
54            let writer = PRINTF.writer.get_mut_unchecked();
55            writer.write_fmt(args).unwrap();
56            if newline {
57                writer.write_char('\n');
58            }
59        }
60    }
61}
62
63#[macro_export]
64macro_rules! print {
65    ($($arg:tt)*) => {{
66        $crate::printf::_print(format_args!($($arg)*), false);
67    }};
68}
69
70#[macro_export]
71macro_rules! println {
72    () => {
73        $crate::print!("\n");
74    };
75    ($($arg:tt)*) => {{
76        $crate::printf::_print(format_args!($($arg)*), true);
77    }};
78}
79
80static mut EWRITER: Writer = Writer;
81
82pub fn _eprint(args: fmt::Arguments<'_>) {
83    unsafe {
84        EWRITER.write_fmt(args).unwrap();
85    }
86}
87
88#[macro_export]
89macro_rules! eprint {
90    ($($arg:tt)*) => {{
91        $crate::printf::_eprint(format_args!($($arg)*));
92    }};
93}
94
95pub fn handle_panic(info: &PanicInfo) -> ! {
96    PRINTF.locking.store(false, Ordering::Relaxed);
97
98    let cpu_id = unsafe { Cpus::get_id() };
99    eprint!("hart {cpu_id} panicked: {info}\n");
100
101    PRINTF.panicked.store(false, Ordering::Relaxed);
102
103    loop {}
104}