//! Serial port (UART 16550, COM1 at I/O port 0x3F8). //! QEMU forwards it to your terminal with `-serial stdio`, which makes it the //! easiest way to see kernel output without a screen. use lazy_static::lazy_static; use spin::Mutex; use uart_16550::SerialPort; lazy_static! { /// The one global COM1 port, initialised on first use, behind a spinlock. pub static ref SERIAL1: Mutex = { let mut port = unsafe { SerialPort::new(0x3F8) }; port.init(); Mutex::new(port) }; } #[doc(hidden)] pub fn _print(args: core::fmt::Arguments) { use core::fmt::Write; // Disable interrupts while we hold the lock. Otherwise an interrupt // handler that also prints would spin forever waiting for a lock held by // the code it interrupted (a deadlock). x86_64::instructions::interrupts::without_interrupts(|| { SERIAL1.lock().write_fmt(args).expect("printing to serial failed"); }); // And to the virtio console (hvc0), if there is one. x86_64::instructions::interrupts::without_interrupts(|| crate::virtio::console::log(args)); } /// Like `print!`, but to the serial port. #[macro_export] macro_rules! serial_print { ($($arg:tt)*) => ($crate::serial::_print(format_args!($($arg)*))); } /// Like `println!`, but to the serial port. Uses "\n" (QEMU passes it through). #[macro_export] macro_rules! serial_println { () => ($crate::serial_print!("\n")); ($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(concat!($fmt, "\n"), $($arg)*)); }