From 874cc5f38195295a135b6c4479c8788af63d2322 Mon Sep 17 00:00:00 2001 From: Kit Rhett Aultman Date: Mon, 2 Sep 2024 23:01:07 -0400 Subject: [PATCH] trap/console: centralize UART use under console.rs This commit refactors the UART reading code so that all UART interactions go through the MmioSerialPort in console.rs. A previous commit had the UART interrupt handler reading directly from the UART because some sort of issue prevents calling CONSOLE.lock() outside of the console crate. However, it's fine to call this from functions inside the console crate, so this commit implements a console_read() function there which the trap vector can then call. --- src/console.rs | 21 +++++++++++++++++---- src/trap.rs | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/console.rs b/src/console.rs index 03f0a9f..f337df9 100644 --- a/src/console.rs +++ b/src/console.rs @@ -42,10 +42,10 @@ impl core::fmt::Write for Console { static SERIAL_BASE: usize = 0x1000_0000; -// I'm not actually sure Spinlock is necessary here, because I saw that the -// uart_16550 code already uses atomic_ptr, which sure sounds like it has -// synchronization features. - +// Spinlock provides us a means to have a global console that is initialized +// at runtime. Note below that locking outside of this module seems to have +// odd behaviors, especially failure to ever acquire the lock. +// The public specifier is here to enable the use of macros. pub static CONSOLE: Spinlock> = Spinlock::new(None); // Since we can't use something like lazy_static!, we're left with having @@ -56,6 +56,19 @@ pub fn init_console() { *console = Some(unsafe { Console::new(SERIAL_BASE) }) } +// Read a byte from the underlying UART, clearing any asserted interrupt in the process. +// It's not entirely clear why, but locking CONSOLE outside of this module, or at least doing +// so while in interrupt context, seems to never return, but providing a public function +// to do the work gets around this problem. +pub fn console_read() -> u8 { + return CONSOLE + .lock() + .as_mut() + .unwrap_or_else(|| panic!("Failed to acquire console for reading!")) + .serial_port + .receive(); +} + // These, like a lot of the code in here, came courtesy of Meyer Zinn's // baremetal Rust tutorials: https://meyerzinn.tech/posts/2023/03/08/p1-printing-and-allocating/ // I don't know how to use macros that well yet! diff --git a/src/trap.rs b/src/trap.rs index f1a75d2..7f3885b 100644 --- a/src/trap.rs +++ b/src/trap.rs @@ -1,3 +1,4 @@ +use crate::console::console_read; use core::arch::asm; use plic::Plic; @@ -89,8 +90,7 @@ extern "C" fn m_trap( let plic = get_plic(); match plic.claim(0) { Some(int) => { - let uart = 0x1000_0000 as *mut u8; - let data = uart.read_volatile(); + let data = console_read(); print!("{}", data as char); plic.complete(0, int); } -- 2.34.1