axplat_aarch64_peripherals/
pl011.rs

1//! PL011 UART.
2
3use arm_pl011::Pl011Uart;
4use axplat::mem::VirtAddr;
5use kspin::SpinNoIrq;
6use lazyinit::LazyInit;
7
8static UART: LazyInit<SpinNoIrq<Pl011Uart>> = LazyInit::new();
9
10fn do_putchar(uart: &mut Pl011Uart, c: u8) {
11    match c {
12        b'\n' => {
13            uart.putchar(b'\r');
14            uart.putchar(b'\n');
15        }
16        c => uart.putchar(c),
17    }
18}
19
20/// Writes a byte to the console.
21pub fn putchar(c: u8) {
22    do_putchar(&mut UART.lock(), c);
23}
24
25/// Reads a byte from the console, or returns [`None`] if no input is available.
26pub fn getchar() -> Option<u8> {
27    UART.lock().getchar()
28}
29
30/// Write a slice of bytes to the console.
31pub fn write_bytes(bytes: &[u8]) {
32    let mut uart = UART.lock();
33    for c in bytes {
34        do_putchar(&mut uart, *c);
35    }
36}
37
38/// Reads bytes from the console into the given mutable slice.
39/// Returns the number of bytes read.
40pub fn read_bytes(bytes: &mut [u8]) -> usize {
41    let mut read_len = 0;
42    while read_len < bytes.len() {
43        if let Some(c) = getchar() {
44            bytes[read_len] = c;
45        } else {
46            break;
47        }
48        read_len += 1;
49    }
50    read_len
51}
52
53/// Early stage initialization of the PL011 UART driver.
54pub fn init_early(uart_base: VirtAddr) {
55    UART.init_once(SpinNoIrq::new(Pl011Uart::new(uart_base.as_mut_ptr())));
56    UART.lock().init();
57}
58
59/// UART IRQ Handler
60pub fn irq_handler() {
61    let is_receive_interrupt = UART.lock().is_receive_interrupt();
62    UART.lock().ack_interrupts();
63    if is_receive_interrupt {
64        while let Some(c) = getchar() {
65            putchar(c);
66        }
67    }
68}
69
70/// Default implementation of [`axplat::console::ConsoleIf`] using the
71/// PL011 UART.
72#[macro_export]
73macro_rules! console_if_impl {
74    ($name:ident) => {
75        struct $name;
76
77        #[axplat::impl_plat_interface]
78        impl axplat::console::ConsoleIf for $name {
79            /// Writes given bytes to the console.
80            fn write_bytes(bytes: &[u8]) {
81                $crate::pl011::write_bytes(bytes);
82            }
83
84            /// Reads bytes from the console into the given mutable slice.
85            ///
86            /// Returns the number of bytes read.
87            fn read_bytes(bytes: &mut [u8]) -> usize {
88                $crate::pl011::read_bytes(bytes)
89            }
90        }
91    };
92}