1use core::fmt::{self, Write};
2use core::sync::atomic::{AtomicBool, Ordering};
3
4use crate::proc;
5use crate::spinlock::SpinLock;
6use crate::uart;
7
8pub struct Writer;
13
14impl Write for Writer {
15 fn write_str(&mut self, s: &str) -> fmt::Result {
16 uart::write_sync(s.as_bytes());
17 Ok(())
18 }
19}
20
21pub static PRINTF: Printf = Printf {
22 writer: SpinLock::new(Writer, "printf"),
23 panicking: AtomicBool::new(false),
24 panicked: AtomicBool::new(false),
25};
26
27pub struct Printf {
28 writer: SpinLock<Writer>,
30 panicking: AtomicBool,
36 panicked: AtomicBool,
41}
42
43impl Printf {
44 pub fn is_panicking(&self) -> bool {
45 self.panicking.load(Ordering::Relaxed)
46 }
47
48 pub fn is_panicked(&self) -> bool {
49 self.panicked.load(Ordering::Relaxed)
50 }
51}
52
53pub fn print(args: fmt::Arguments<'_>) {
58 let writer = if !PRINTF.is_panicking() {
59 &mut *PRINTF.writer.lock()
60 } else {
61 unsafe { PRINTF.writer.get_mut_unchecked() }
63 };
64
65 writer.write_fmt(args).unwrap();
66}
67
68#[macro_export]
69macro_rules! print {
70 ($($arg:tt)*) => {{
71 $crate::printf::print(format_args!($($arg)*));
72 }};
73}
74
75#[macro_export]
76macro_rules! println {
77 ($fmt:literal $(,$($arg:tt)+)?) => {
78 $crate::printf::print(format_args!(concat!($fmt, "\n") $(,$($arg)+)?))
79 };
80}
81
82struct PanicBuffer<const N: usize> {
87 data: [u8; N],
88 len: usize,
89}
90
91impl<const N: usize> Write for PanicBuffer<N> {
92 fn write_str(&mut self, s: &str) -> fmt::Result {
93 let bytes = s.as_bytes();
94 let space = self.data.len() - self.len;
95 let n = bytes.len().min(space);
96 self.data[self.len..self.len + n].copy_from_slice(&bytes[..n]);
97 self.len += n;
98 Ok(())
99 }
100}
101
102pub fn panic(info: &core::panic::PanicInfo) -> ! {
103 PRINTF.panicking.store(true, Ordering::Relaxed);
104
105 let cpu_id = unsafe { proc::current_id() };
108
109 let mut buf = PanicBuffer::<256> {
110 data: [0; 256],
111 len: 0,
112 };
113 let _ = writeln!(buf, "\n! hart {} {}", cpu_id, info);
114 uart::write_sync(&buf.data[..buf.len]);
115
116 PRINTF.panicked.store(true, Ordering::Relaxed);
117
118 loop {
119 core::hint::spin_loop();
120 }
121}