Skip to content

Commit

Permalink
Handle RX interrupts from the UART
Browse files Browse the repository at this point in the history
  • Loading branch information
PandaZ3D committed Jan 19, 2024
1 parent f384373 commit f778d0e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/kernel/src/arch/aarch64/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions src/kernel/src/machine/arm/common/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum Registers {
UARTLCR_H = 0x02C,
UARTCR = 0x030,
UARTIMSC = 0x038,
UARTICR = 0x044,
UARTDMACR = 0x048,
}

Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/kernel/src/machine/arm/virt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
31 changes: 31 additions & 0 deletions src/kernel/src/machine/arm/virt/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand All @@ -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();
}

0 comments on commit f778d0e

Please sign in to comment.