You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.0 KiB
Rust
118 lines
3.0 KiB
Rust
//! 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<QemuOutputInner>,
|
|
}
|
|
|
|
/// 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)*));
|
|
})
|
|
}
|