From 23c07e794e23f84105391b99b8132bf4c9b394a3 Mon Sep 17 00:00:00 2001 From: Kit Rhett Aultman Date: Mon, 2 Sep 2024 19:56:39 -0400 Subject: [PATCH] console/main/trap: enable interrupts, handle UART interrupt This commit enables interrupts and configures the RISC-V PLIC to deliver interrupts for the UART (interrupt 10 for qemu). To do this: * mstatus and mie are configured for m-mode interrupts (mstatus also likely has s-mode turned on, but we won't use s-mode until we have to). * The MmioSerialPort didn't have its init function called; doing so sets the interrupt enable bits on the UART. * Configures the PLIC to deliver interrupt 10 on priority 1. * Adds code to the exception handler to claim, handle, and complete the interrupt. A few notes here: * There's only one interrupt source right now...the UART. So servicing the interrupt is done right in the handler. There's no need to determine any other interrupt sources or worry about timing beyond this, for now. * Because the MmioSerialPort was really mostly set up for the benefit of console output, it's not really set up to be used by the interrupt handler. The code's a bit messy to ensure we read the pending byte and just echo it back to the terminal. Future commits should address the awkwardness going on here. --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/console.rs | 3 ++- src/main.rs | 3 +++ src/trap.rs | 34 +++++++++++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7e35c5..4ef88eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,12 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "plic" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad606bf31d67b0e10a161b7df7d6a97dda7be22ce4bebcff889476e867c9b7a" + [[package]] name = "raw-cpuid" version = "10.7.0" @@ -53,6 +59,7 @@ name = "riscv" version = "0.1.0" dependencies = [ "buddy_system_allocator", + "plic", "spinning_top", "uart_16550", ] diff --git a/Cargo.toml b/Cargo.toml index ab3c17d..9495ccb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ target = "riscv64gc-unknown-none-elf" buddy_system_allocator = "0.9.1" spinning_top = "0.3.0" uart_16550 = "0.3.0" +plic = { version = "0.0.2", features = ["primitive-id"] } # We need to turn off panic unwinding # so we set the panic behavior to abort diff --git a/src/console.rs b/src/console.rs index 511e1a5..03f0a9f 100644 --- a/src/console.rs +++ b/src/console.rs @@ -20,7 +20,8 @@ pub struct Console { impl Console { pub unsafe fn new(base: usize) -> Self { - let serial_port = MmioSerialPort::new(base); + let mut serial_port = MmioSerialPort::new(base); + serial_port.init(); Console { serial_port } } diff --git a/src/main.rs b/src/main.rs index d7e0076..3e81694 100644 --- a/src/main.rs +++ b/src/main.rs @@ -114,6 +114,9 @@ extern "C" fn entry() -> ! { "csrw mtvec, t2", trap_frame = in(reg)(&raw mut trap::TRAP_FRAME as usize) ); + + // We're now good to take interrupts + trap::init_interrupts(); } println!("Kernel init complete"); diff --git a/src/trap.rs b/src/trap.rs index ac45c5f..f1a75d2 100644 --- a/src/trap.rs +++ b/src/trap.rs @@ -1,3 +1,6 @@ +use core::arch::asm; +use plic::Plic; + #[repr(C)] #[derive(Clone, Copy)] pub struct TrapFrame { @@ -26,6 +29,21 @@ impl TrapFrame { pub static mut TRAP_FRAME: TrapFrame = TrapFrame::new(); +// unsafe: call only once! +pub unsafe fn init_interrupts() { + asm!("csrsi mstatus, 0b1000", "li t2, 0xaaa", "csrw mie, t2"); + let plic = get_plic(); + // Enable interrupts of any priority on the PLIC + plic.set_threshold(0, 0); + // PLIC interrupt 10 is the UART on qemu + plic.set_priority(10, 1); + plic.enable(10, 0); +} + +unsafe fn get_plic() -> &'static Plic { + return &*(0xc000000 as *const Plic); +} + #[no_mangle] extern "C" fn m_trap( epc: usize, @@ -66,7 +84,21 @@ extern "C" fn m_trap( }, 11 => { // Machine external (interrupt from Platform Interrupt Controller (PLIC)) - println!("Machine external interrupt CPU#{}", hart); + // Since we have only the UART to deal with, this one's pretty easy. + unsafe { + let plic = get_plic(); + match plic.claim(0) { + Some(int) => { + let uart = 0x1000_0000 as *mut u8; + let data = uart.read_volatile(); + print!("{}", data as char); + plic.complete(0, int); + } + _ => { + println!("No interrupt pending?!") + } + } + } } _ => { panic!("Unhandled async trap CPU#{} -> {}\n", hart, cause_num); -- 2.34.1