RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / src / arch / aarch64 / console.rs
1884 bytes ยท raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Text out through the board's UART. `puts_raw` is for the very first
//! line, before the MMU is on (it only does byte loads: with the MMU off
//! all memory is "device" memory, where an unaligned access faults, and
//! `core::fmt` makes no promises about that). `print!`/`println!` are for
//! after.

use core::fmt::{self, Write};
use spin::Mutex;

struct Console;

impl Write for Console {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let uart = super::board::current().uart();
        for b in s.bytes() {
            if b == b'\n' {
                uart.putc(b'\r');
            }
            uart.putc(b);
        }
        Ok(())
    }
}

static LOCK: Mutex<()> = Mutex::new(());

/// One line, no formatting, safe with the MMU off.
pub fn puts_raw(s: &str) {
    let uart = super::board::current().uart();
    let bytes = s.as_bytes();
    let mut i = 0;
    while i < bytes.len() {
        uart.putc(bytes[i]);
        i += 1;
    }
    uart.putc(b'\r');
    uart.putc(b'\n');
}

/// The `arch` interface's text out.
pub fn write_str(s: &str) {
    _print(format_args!("{}", s));
}

#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
    let _guard = LOCK.lock();
    let _ = Console.write_fmt(args);
}

/// Like `print!`, to the arm64 kernel's console.
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => { $crate::arch::aarch64::console::_print(format_args!($($arg)*)) };
}

/// Like `println!`, to the arm64 kernel's console.
#[macro_export]
macro_rules! println {
    () => { $crate::print!("\n") };
    ($($arg:tt)*) => { $crate::arch::aarch64::console::_print(format_args!("{}\n", format_args!($($arg)*))) };
}

/// For the fatal-exception path only: the interrupted code may have been
/// in the middle of a `println!`, holding the lock, and it will never run
/// again.
pub unsafe fn force_unlock() {
    unsafe { LOCK.force_unlock() };
}