trap/console: centralize UART use under console.rs master
authorKit Rhett Aultman <kit@kitaultman.com>
Tue, 3 Sep 2024 03:01:07 +0000 (23:01 -0400)
committerKit Rhett Aultman <kit@kitaultman.com>
Tue, 3 Sep 2024 03:01:07 +0000 (23:01 -0400)
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
src/trap.rs

index 03f0a9fba711d27e99d2d250503b8aef53d75926..f337df9ceb60ad5cec259060b439b74f195dea9b 100644 (file)
@@ -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<Option<Console>> = 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!
index f1a75d2791df9090a0090a655ebe1427d69379d2..7f3885b122d59d9a4918c19620ab1e4ccd90cc19 100644 (file)
@@ -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);
                         }