From f778d0ebb7a5b9095958cce741bf0fdcccc5641c Mon Sep 17 00:00:00 2001 From: Allen Aboytes Date: Fri, 19 Jan 2024 10:32:18 -0800 Subject: [PATCH] Handle RX interrupts from the UART --- src/kernel/src/arch/aarch64/interrupt.rs | 5 ++++ src/kernel/src/machine/arm/common/uart.rs | 13 ++++++++++ src/kernel/src/machine/arm/virt/mod.rs | 3 ++- src/kernel/src/machine/arm/virt/serial.rs | 31 +++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/kernel/src/arch/aarch64/interrupt.rs b/src/kernel/src/arch/aarch64/interrupt.rs index f0ba63ea..97e3c98d 100644 --- a/src/kernel/src/arch/aarch64/interrupt.rs +++ b/src/kernel/src/arch/aarch64/interrupt.rs @@ -16,6 +16,7 @@ use crate::{ processor::current_processor, }; use crate::machine::interrupt::INTERRUPT_CONTROLLER; +use crate::machine::serial::{SERIAL_INT_ID, serial_interrupt_handler}; use super::exception::{ ExceptionContext, exception_handler, save_stack_pointer, restore_stack_pointer, @@ -138,6 +139,10 @@ pub(super) fn irq_exception_handler(_ctx: &mut ExceptionContext) { // call timer interrupt handler cntp_interrupt_handler(); }, + _ if irq_number == *SERIAL_INT_ID => { + // call the serial interrupt handler + serial_interrupt_handler(); + }, _ => panic!("unknown irq number! {}", irq_number) } // signal the GIC that we have serviced the IRQ diff --git a/src/kernel/src/machine/arm/common/uart.rs b/src/kernel/src/machine/arm/common/uart.rs index a7970e58..c9c28f79 100644 --- a/src/kernel/src/machine/arm/common/uart.rs +++ b/src/kernel/src/machine/arm/common/uart.rs @@ -19,6 +19,7 @@ enum Registers { UARTLCR_H = 0x02C, UARTCR = 0x030, UARTIMSC = 0x038, + UARTICR = 0x044, UARTDMACR = 0x048, } @@ -176,6 +177,18 @@ impl PL011 { } } + pub fn clear_rx_interrupt(&self) { + // The UARTICR Register is the interrupt clear register and is write-only. + // On a write of 1, the corresponding interrupt is cleared. + // A write of 0 has no effect. Table 3-17 lists the register bit assignments. + // + // We must write to Receive interrupt clear (RXIC) which is bit 4. This + // Clears the UARTRXINTR interrupt. + unsafe { + self.write_reg(Registers::UARTICR, (0b1 << 4) as u32); + } + } + /// Write a value to a single register. Registers are 32-bits wide. unsafe fn write_reg(&self, register: Registers, value: u32) { let reg = (self.base + register as usize) as *mut u32; diff --git a/src/kernel/src/machine/arm/virt/mod.rs b/src/kernel/src/machine/arm/virt/mod.rs index a2fe57c9..8f0a4777 100644 --- a/src/kernel/src/machine/arm/virt/mod.rs +++ b/src/kernel/src/machine/arm/virt/mod.rs @@ -5,5 +5,6 @@ pub mod processor; pub mod serial; pub fn machine_post_init() { - // TODO: initialize uart with interrupts + // initialize uart with interrupts + serial::SERIAL.late_init(); } \ No newline at end of file diff --git a/src/kernel/src/machine/arm/virt/serial.rs b/src/kernel/src/machine/arm/virt/serial.rs index c76a253e..00c57eb4 100644 --- a/src/kernel/src/machine/arm/virt/serial.rs +++ b/src/kernel/src/machine/arm/virt/serial.rs @@ -7,6 +7,7 @@ use crate::memory::{PhysAddr, pagetables::{ ContiguousProvider, MappingCursor, MappingSettings, Mapper, MappingFlags, }}; +use crate::interrupt::{Destination, TriggerMode}; use crate::arch::memory::mmio::MMIO_ALLOCATOR; lazy_static! { @@ -47,6 +48,12 @@ lazy_static! { serial_port.early_init(clock_freq as u32); serial_port }; + + pub static ref SERIAL_INT_ID: u32 = { + let int_num = crate::machine::info::get_uart_interrupt_num() + .expect("failed to decode UART interrupt number"); + int_num + }; } impl PL011 { @@ -64,6 +71,22 @@ impl PL011 { self.init(clock_freq, BAUD); } } + + /// intitialize the UART driver after the system has enabled interrupts + pub fn late_init(&self) { + // enable the rx side to use interrupts + unsafe { + self.enable_rx_interrupt(); + } + + crate::arch::set_interrupt( + *SERIAL_INT_ID, + false, + TriggerMode::Edge, + crate::interrupt::PinPolarity::ActiveHigh, + Destination::Bsp, + ); + } } pub fn write(data: &[u8], _flags: crate::log::KernelConsoleWriteFlags) { @@ -80,3 +103,11 @@ pub fn write(data: &[u8], _flags: crate::log::KernelConsoleWriteFlags) { } } } + +pub fn serial_interrupt_handler() { + let byte = SERIAL.rx_byte(); + if let Some(x) = byte { + crate::log::push_input_byte(x); + } + SERIAL.clear_rx_interrupt(); +}