Skip to main content

strat9_kernel/
debug.rs

1use crate::x86_crate_shim::instructions::port::Port;
2use core::fmt;
3
4/// Raw e9 debugcon marker: writes a single byte to port 0xe9 using inline asm.
5/// This works even when the Port type from x86_64 crate doesn't.
6#[macro_export]
7macro_rules! e9_mark {
8    ($byte:expr) => {
9        unsafe { core::arch::asm!("out 0xe9, al", in("al") $byte, options(nomem, nostack)); }
10    };
11}
12
13pub struct QemuDebug;
14
15impl fmt::Write for QemuDebug {
16    fn write_str(&mut self, s: &str) -> fmt::Result {
17        let mut port = Port::new(0xe9);
18        for &byte in s.as_bytes() {
19            unsafe {
20                port.write(byte);
21            }
22        }
23        Ok(())
24    }
25}
26
27#[macro_export]
28macro_rules! e9_print {
29    ($($arg:tt)*) => {
30        {
31            use core::fmt::Write;
32            let _ = write!($crate::debug::QemuDebug, $($arg)*);
33        }
34    };
35}
36
37#[macro_export]
38macro_rules! e9_println {
39    () => {
40        if !$crate::debug_cfg::is_quiet() {
41            $crate::e9_print!("\n");
42        }
43    };
44    ($($arg:tt)*) => {
45        if !$crate::debug_cfg::is_quiet() {
46            $crate::e9_print!("{}\n", format_args!($($arg)*));
47        }
48    };
49}
50
51/// Log a boot milestone with elapsed time since kernel entry.
52///
53/// Output format: `[boot +     12ms] Paging initialized`
54#[macro_export]
55macro_rules! boot_milestone {
56    ($($arg:tt)*) => {
57        if !$crate::debug_cfg::is_quiet() {
58            $crate::serial_println!(
59                "[boot +{:>6}ms] {}",
60                $crate::arch::boot_timestamp::elapsed_ms(),
61                format_args!($($arg)*)
62            );
63            if $crate::arch::vga::is_available() {
64                let mut vbuf = [0u8; $crate::arch::vgabuf::VGABUF_LINE_LEN];
65                let mut vpos = 0usize;
66                use core::fmt::Write;
67                struct VgaBufWriter<'a> {
68                    buf: &'a mut [u8],
69                    pos: &'a mut usize,
70                }
71                impl Write for VgaBufWriter<'_> {
72                    fn write_str(&mut self, s: &str) -> core::fmt::Result {
73                        let bytes = s.as_bytes();
74                        let remaining = self.buf.len().saturating_sub(*self.pos);
75                        let n = bytes.len().min(remaining);
76                        self.buf[*self.pos..*self.pos + n].copy_from_slice(&bytes[..n]);
77                        *self.pos += n;
78                        Ok(())
79                    }
80                }
81                let _ = write!(
82                    VgaBufWriter { buf: &mut vbuf, pos: &mut vpos },
83                    "[boot +{:>6}ms] {}\n",
84                    $crate::arch::boot_timestamp::elapsed_ms(),
85                    format_args!($($arg)*)
86                );
87                if vpos > 0 {
88                    $crate::arch::vgabuf::vgabuf_write(&vbuf[..vpos]);
89                }
90            }
91        }
92    };
93}