//! The module implementing the printing features. //! //! For now, the console is implemented here, this may change in the future. //! The console is implemented using the magic qemu output right now. use core::fmt; use crate::synchronization::PseudoLock; use crate::synchronization::Mutex; /// This trait implement the same features as `core::fmt::Write`, /// except it operate on shared references (`&self`) instead of /// mutable references (`&mut self`). pub trait Write { /// Write a single character. fn write_char(&self, c: char); /// Write a Rust format string. fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; /// Block until the last buffered character has been physically put on the TX wire. fn flush(&self); } /// Inner Qemu output. struct QemuOutputInner; /// Qemu output, access to the inner ressources is protected by /// a mutex. struct QemuOutput { inner: PseudoLock, } /// The address for the magic qemu output const QEMU_MAGIC_OUTPUT_ADDR: *mut u8 = 0x3F20_1000 as *mut u8; static QEMU_OUTPUT: QemuOutput = QemuOutput::new(); impl QemuOutputInner { /// Constructor for QemuOutputInner. const fn new() -> Self { Self {} } /// Write a character to the output. fn write_char(&mut self, c: char) { unsafe { core::ptr::write_volatile(QEMU_MAGIC_OUTPUT_ADDR, c as u8); } } } impl QemuOutput { pub const fn new() -> Self { Self { inner: PseudoLock::new(QemuOutputInner::new()), } } } /// Allow to use QemuOutputInner for print! and formating macros. /// `write_str` needs `&mut self` (mutable ref), so we can implement /// it only on the inner type, the `QemuOutput` need to be manipulable /// using unmutable references (`&self`), so we will use a custom /// interface for it. impl fmt::Write for QemuOutputInner { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { // \n -> \r\n if c == '\n' { self.write_char('\r'); } self.write_char(c); } Ok(()) } } impl Write for QemuOutput { fn write_char(&self, c: char) { self.inner.lock(|q_out| q_out.write_char(c)) } fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result { self.inner.lock(|q_out| fmt::Write::write_fmt(q_out, args)) } /// Empty function, the qemu uart has no buffering afaik fn flush(&self) { // self.inner.lock(|q_out| q_out.flush()) } } /// Return a reference to the Qemu Output. pub fn console() -> &'static dyn Write { &QEMU_OUTPUT } /// The backend for printing to the console. pub fn _print(args: fmt::Arguments) { console().write_fmt(args).unwrap(); } /// The printing macro. #[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); } /// The line printing macro. #[macro_export] macro_rules! println { () => ($crate::print!("\n")); ($($arg:tt)*) => ({ $crate::print::_print(format_args_nl!($($arg)*)); }) }