Skip to content

Commit

Permalink
remove spinlock in interrupt handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
stlankes committed Sep 3, 2024
1 parent f9ed74a commit 8cc0977
Show file tree
Hide file tree
Showing 21 changed files with 297 additions and 214 deletions.
83 changes: 44 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;
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,34 @@ 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 = get_interrupt_handlers();

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

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

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 +117,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 +145,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 +303,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();
}
77 changes: 37 additions & 40 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::{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,9 +23,8 @@ 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() {
Expand Down Expand Up @@ -110,40 +113,32 @@ pub fn disable() {
}

/// 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 +200,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 Down
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();
}
39 changes: 16 additions & 23 deletions src/arch/x86_64/kernel/interrupts.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use alloc::collections::{BTreeMap, VecDeque};
use alloc::collections::BTreeMap;
use core::arch::asm;
use core::sync::atomic::{AtomicU64, Ordering};

use ahash::RandomState;
use hashbrown::HashMap;
use hermit_sync::{InterruptSpinMutex, InterruptTicketMutex};
use hermit_sync::{InterruptSpinMutex, InterruptTicketMutex, OnceCell};
#[cfg(not(feature = "idle-poll"))]
use x86_64::instructions::interrupts::enable_and_hlt;
pub use x86_64::instructions::interrupts::{disable, enable};
Expand All @@ -16,11 +16,14 @@ use crate::arch::x86_64::kernel::core_local::{core_scheduler, increment_irq_coun
use crate::arch::x86_64::kernel::{apic, processor};
use crate::arch::x86_64::mm::paging::{page_fault_handler, BasePageSize, PageSize};
use crate::arch::x86_64::swapgs;
#[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::{self, CoreId};

type InterruptHandlerQueue = VecDeque<fn()>;
static IRQ_HANDLERS: InterruptSpinMutex<HashMap<u8, InterruptHandlerQueue, RandomState>> =
InterruptSpinMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)));
static IRQ_HANDLERS: OnceCell<HashMap<u8, InterruptHandlerQueue, RandomState>> = OnceCell::new();
static IRQ_NAMES: InterruptTicketMutex<HashMap<u8, &'static str, RandomState>> =
InterruptTicketMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)));

Expand Down Expand Up @@ -158,32 +161,22 @@ pub(crate) fn install() {
IRQ_NAMES.lock().insert(7, "FPU");
}

#[cfg(any(feature = "fuse", feature = "tcp", feature = "udp", feature = "vsock"))]
pub fn irq_install_handler(irq_number: u8, handler: fn()) {
debug!("Install handler for interrupt {}", irq_number);

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

fn handle_interrupt(stack_frame: ExceptionStackFrame, index: u8, _error_code: Option<u64>) {
crate::arch::x86_64::swapgs(&stack_frame);
use crate::arch::kernel::core_local::core_scheduler;
use crate::scheduler::PerCoreSchedulerExt;

if let Some(map) = IRQ_HANDLERS.lock().get(&(index - 32)) {
debug!("received interrupt {index}");
for handler in map.iter() {
handler();
if let Some(handlers) = IRQ_HANDLERS.get() {
if let Some(map) = handlers.get(&(index - 32)) {
debug!("received interrupt {index}");
for handler in map.iter() {
handler();
}
}
} else {
warn!("received unhandled interrupt {index}");
}

apic::eoi();
Expand Down
8 changes: 0 additions & 8 deletions src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,3 @@ pub(crate) fn memory_barrier() {
asm!("mfence", options(nostack, nomem, preserves_flags),);
}
}

pub fn init_drivers() {
// Initialize PCI Drivers
#[cfg(feature = "pci")]
crate::drivers::pci::init_drivers();
#[cfg(all(not(feature = "pci"), any(feature = "tcp", feature = "udp")))]
crate::arch::x86_64::kernel::mmio::init_drivers();
}
7 changes: 7 additions & 0 deletions src/drivers/fs/virtio_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq;
use crate::drivers::virtio::virtqueue::{
AvailBufferToken, BufferElem, BufferType, Virtq, VqIndex, VqSize,
};
use crate::drivers::Driver;
use crate::fs::fuse::{self, FuseInterface, Rsp, RspHeader};
use crate::mm::device_alloc::DeviceAlloc;

Expand Down Expand Up @@ -195,6 +196,12 @@ impl FuseInterface for VirtioFsDriver {
}
}

impl Driver for VirtioFsDriver {
fn get_interrupt_number(&self) -> InterruptLine {
self.irq
}
}

/// Error module of virtios filesystem driver.
pub mod error {
/// Network filesystem error enum.
Expand Down
Loading

0 comments on commit 8cc0977

Please sign in to comment.