Skip to content

Commit

Permalink
Merge pull request #1378 from stlankes/irq
Browse files Browse the repository at this point in the history
remove spinlock in interrupt handlers
  • Loading branch information
mkroening authored Oct 11, 2024
2 parents 6bc21db + 1e7b91d commit 03e6260
Show file tree
Hide file tree
Showing 22 changed files with 356 additions and 252 deletions.
88 changes: 49 additions & 39 deletions src/arch/aarch64/kernel/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ use crate::arch::aarch64::kernel::scheduler::State;
use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags};
use crate::arch::aarch64::mm::{virtualmem, PhysAddr};
use crate::core_scheduler;
#[cfg(not(feature = "pci"))]
use crate::drivers::mmio::get_interrupt_handlers;
#[cfg(feature = "pci")]
use crate::drivers::pci::get_interrupt_handlers;
use crate::drivers::{InterruptHandlerQueue, InterruptLine};
use crate::scheduler::{self, CoreId};

/// The ID of the first Private Peripheral Interrupt.
Expand All @@ -27,13 +32,11 @@ const SPI_START: u8 = 32;
/// Software-generated interrupt for rescheduling
pub(crate) const SGI_RESCHED: u8 = 1;

type InterruptHandlerQueue = VecDeque<fn()>;

/// Number of the timer interrupt
static mut TIMER_INTERRUPT: u32 = 0;
/// Possible interrupt handlers
static INTERRUPT_HANDLERS: InterruptSpinMutex<HashMap<u8, InterruptHandlerQueue, RandomState>> =
InterruptSpinMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)));
static INTERRUPT_HANDLERS: OnceCell<HashMap<u8, InterruptHandlerQueue, RandomState>> =
OnceCell::new();
/// Driver for the Arm Generic Interrupt Controller version 3 (or 4).
pub(crate) static mut GIC: OnceCell<GicV3> = OnceCell::new();

Expand Down Expand Up @@ -76,18 +79,39 @@ pub fn disable() {
}
}

#[allow(dead_code)]
pub(crate) fn irq_install_handler(irq_number: u8, handler: fn()) {
debug!("Install handler for interrupt {}", irq_number);
let irq_number = irq_number + SPI_START;
let mut guard = INTERRUPT_HANDLERS.lock();
if let Some(queue) = guard.get_mut(&irq_number) {
queue.push_back(handler);
} else {
let mut queue = VecDeque::new();
queue.push_back(handler);
guard.insert(irq_number, queue);
pub(crate) fn install_handlers() {
let mut handlers: HashMap<InterruptLine, InterruptHandlerQueue, RandomState> =
HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0));

fn timer_handler() {
debug!("Handle timer interrupt");

// disable timer
unsafe {
asm!(
"msr cntp_cval_el0, xzr",
"msr cntp_ctl_el0, xzr",
options(nostack, nomem),
);
}
}

for (key, value) in get_interrupt_handlers().into_iter() {
handlers.insert(key + SPI_START, value);
}

unsafe {
if let Some(queue) = handlers.get_mut(&(u8::try_from(TIMER_INTERRUPT).unwrap() + PPI_START))
{
queue.push_back(timer_handler);
} else {
let mut queue = VecDeque::<fn()>::new();
queue.push_back(timer_handler);
handlers.insert(u8::try_from(TIMER_INTERRUPT).unwrap() + PPI_START, queue);
}
}

INTERRUPT_HANDLERS.set(handlers).unwrap();
}

#[no_mangle]
Expand All @@ -98,9 +122,11 @@ pub(crate) extern "C" fn do_fiq(_state: &State) -> *mut usize {
debug!("Receive fiq {}", vector);
increment_irq_counter(vector);

if let Some(queue) = INTERRUPT_HANDLERS.lock().get(&vector) {
for handler in queue.iter() {
handler();
if let Some(handlers) = INTERRUPT_HANDLERS.get() {
if let Some(queue) = handlers.get(&vector) {
for handler in queue.iter() {
handler();
}
}
}
crate::executor::run();
Expand All @@ -124,9 +150,11 @@ pub(crate) extern "C" fn do_irq(_state: &State) -> *mut usize {
debug!("Receive interrupt {}", vector);
increment_irq_counter(vector);

if let Some(queue) = INTERRUPT_HANDLERS.lock().get(&vector) {
for handler in queue.iter() {
handler();
if let Some(handlers) = INTERRUPT_HANDLERS.get() {
if let Some(queue) = handlers.get(&vector) {
for handler in queue.iter() {
handler();
}
}
}
crate::executor::run();
Expand Down Expand Up @@ -280,24 +308,6 @@ pub(crate) fn init() {
irq, irqtype, irqflags
);

fn timer_handler() {
debug!("Handle timer interrupt");

// disable timer
unsafe {
asm!(
"msr cntp_cval_el0, xzr",
"msr cntp_ctl_el0, xzr",
options(nostack, nomem),
);
}
}

let mut queue = VecDeque::<fn()>::new();
queue.push_back(timer_handler);
INTERRUPT_HANDLERS
.lock()
.insert(u8::try_from(irq).unwrap() + PPI_START, queue);
IRQ_NAMES
.lock()
.insert(u8::try_from(irq).unwrap() + PPI_START, "Timer");
Expand Down
6 changes: 0 additions & 6 deletions src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,3 @@ pub(crate) fn memory_barrier() {
asm!("dmb ish", options(nostack, nomem, preserves_flags),);
}
}

pub fn init_drivers() {
// Initialize PCI Drivers
#[cfg(feature = "pci")]
crate::drivers::pci::init_drivers();
}
99 changes: 51 additions & 48 deletions src/arch/riscv64/kernel/interrupts.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use alloc::collections::VecDeque;
use alloc::vec::Vec;

use ahash::RandomState;
use hashbrown::HashMap;
use hermit_sync::{InterruptSpinMutex, SpinMutex};
use hermit_sync::{InterruptTicketMutex, OnceCell, SpinMutex};
use riscv::asm::wfi;
use riscv::register::{scause, sie, sip, sstatus, stval};
use trapframe::TrapFrame;

#[cfg(not(feature = "pci"))]
use crate::drivers::mmio::get_interrupt_handlers;
#[cfg(feature = "pci")]
use crate::drivers::pci::get_interrupt_handlers;
use crate::drivers::InterruptHandlerQueue;
use crate::scheduler;

/// base address of the PLIC, only one access at the same time is allowed
Expand All @@ -19,12 +23,11 @@ static PLIC_CONTEXT: SpinMutex<u16> = SpinMutex::new(0x0);
/// PLIC context for new interrupt handlers
static CURRENT_INTERRUPTS: SpinMutex<Vec<u32>> = SpinMutex::new(Vec::new());

type InterruptHandlerQueue = VecDeque<fn()>;
static INTERRUPT_HANDLERS: InterruptSpinMutex<HashMap<u8, InterruptHandlerQueue, RandomState>> =
InterruptSpinMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)));
static INTERRUPT_HANDLERS: OnceCell<HashMap<u8, InterruptHandlerQueue, RandomState>> =
OnceCell::new();

/// Init Interrupts
pub fn install() {
pub(crate) fn install() {
unsafe {
// Intstall trap handler
trapframe::init();
Expand All @@ -34,28 +37,32 @@ pub fn install() {
}

/// Init PLIC
pub fn init_plic(base: usize, context: u16) {
pub(crate) fn init_plic(base: usize, context: u16) {
*PLIC_BASE.lock() = base;
*PLIC_CONTEXT.lock() = context;
}

/// Enable Interrupts
#[inline]
pub fn enable() {
pub(crate) fn enable() {
unsafe {
sstatus::set_sie();
}
}

#[cfg(all(feature = "pci", feature = "tcp"))]
pub fn add_irq_name(irq_number: u8, name: &'static str) {
warn!("add_irq_name({irq_number}, {name}) called but not implemented");
static IRQ_NAMES: InterruptTicketMutex<HashMap<u8, &'static str, RandomState>> =
InterruptTicketMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)));

#[allow(dead_code)]
pub(crate) fn add_irq_name(irq_number: u8, name: &'static str) {
debug!("Register name \"{}\" for interrupt {}", name, irq_number);
IRQ_NAMES.lock().insert(irq_number, name);
}

/// Waits for the next interrupt (Only Supervisor-level software/timer interrupt for now)
/// and calls the specific handler
#[inline]
pub fn enable_and_wait() {
pub(crate) fn enable_and_wait() {
unsafe {
//Enable Supervisor-level software interrupts
sie::set_ssoft();
Expand Down Expand Up @@ -105,45 +112,37 @@ pub fn enable_and_wait() {

/// Disable Interrupts
#[inline]
pub fn disable() {
pub(crate) fn disable() {
unsafe { sstatus::clear_sie() };
}

/// Currently not needed because we use the trapframe crate
#[cfg(feature = "tcp")]
pub fn irq_install_handler(irq_number: u8, handler: fn()) {
unsafe {
let base_ptr = PLIC_BASE.lock();
let context = PLIC_CONTEXT.lock();
debug!(
"Install handler for interrupt {}, context {}",
irq_number, *context
);

let mut guard = INTERRUPT_HANDLERS.lock();
if let Some(queue) = guard.get_mut(&irq_number) {
queue.push_back(handler);
} else {
let mut queue = VecDeque::new();
queue.push_back(handler);
guard.insert(irq_number, queue);
pub(crate) fn install_handlers() {
let handlers = get_interrupt_handlers();

for irq_number in handlers.keys() {
unsafe {
let base_ptr = PLIC_BASE.lock();
let context = PLIC_CONTEXT.lock();

// Set priority to 7 (highest on FU740)
let prio_address = *base_ptr + *irq_number as usize * 4;
core::ptr::write_volatile(prio_address as *mut u32, 1);
// Set Threshold to 0 (lowest)
let thresh_address = *base_ptr + 0x20_0000 + 0x1000 * (*context as usize);
core::ptr::write_volatile(thresh_address as *mut u32, 0);
// Enable irq for context
const PLIC_ENABLE_OFFSET: usize = 0x002000;
let enable_address = *base_ptr
+ PLIC_ENABLE_OFFSET
+ 0x80 * (*context as usize)
+ ((*irq_number / 32) * 4) as usize;
debug!("enable_address {:x}", enable_address);
core::ptr::write_volatile(enable_address as *mut u32, 1 << (irq_number % 32));
}

// Set priority to 7 (highest on FU740)
let prio_address = *base_ptr + irq_number as usize * 4;
core::ptr::write_volatile(prio_address as *mut u32, 1);
// Set Threshold to 0 (lowest)
let thresh_address = *base_ptr + 0x20_0000 + 0x1000 * (*context as usize);
core::ptr::write_volatile(thresh_address as *mut u32, 0);
// Enable irq for context
const PLIC_ENABLE_OFFSET: usize = 0x002000;
let enable_address = *base_ptr
+ PLIC_ENABLE_OFFSET
+ 0x80 * (*context as usize)
+ ((irq_number / 32) * 4) as usize;
debug!("enable_address {:x}", enable_address);
core::ptr::write_volatile(enable_address as *mut u32, 1 << (irq_number % 32));
}

INTERRUPT_HANDLERS.set(handlers).unwrap();
}

// Derived from rCore: https://github.com/rcore-os/rCore
Expand Down Expand Up @@ -205,9 +204,11 @@ fn external_handler() {
}

// Call handler
if let Some(queue) = INTERRUPT_HANDLERS.lock().get(&u8::try_from(irq).unwrap()) {
for handler in queue.iter() {
handler();
if let Some(handlers) = INTERRUPT_HANDLERS.get() {
if let Some(queue) = handlers.get(&u8::try_from(irq).unwrap()) {
for handler in queue.iter() {
handler();
}
}
}
crate::executor::run();
Expand All @@ -234,3 +235,5 @@ fn external_eoi() {
}
}
}

pub(crate) fn print_statistics() {}
6 changes: 4 additions & 2 deletions src/arch/riscv64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::env;

// Used to store information about available harts. The index of the hart in the vector
// represents its CpuId and does not need to match its hart_id
pub static mut HARTS_AVAILABLE: Vec<usize> = Vec::new();
pub(crate) static mut HARTS_AVAILABLE: Vec<usize> = Vec::new();

/// Kernel header to announce machine features
static BOOT_INFO: OnceCell<BootInfo> = OnceCell::new();
Expand Down Expand Up @@ -208,4 +208,6 @@ pub fn boot_next_processor() {
}
}

pub fn print_statistics() {}
pub fn print_statistics() {
interrupts::print_statistics();
}
6 changes: 0 additions & 6 deletions src/arch/riscv64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,3 @@ pub mod mm;
pub(crate) fn memory_barrier() {
riscv::asm::sfence_vma_all()
}

pub fn init_drivers() {
// Initialize PCI Drivers
#[cfg(feature = "pci")]
crate::drivers::pci::init_drivers();
}
Loading

0 comments on commit 03e6260

Please sign in to comment.