diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index 48936ef..d9bfe84 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -29,7 +29,10 @@ impl TrapOps for Trap { // anyway, clear sscratch riscv::register::sscratch::write(0); // set trap_entry - unsafe { riscv::register::stvec::write(trap_entry as usize, TrapMode::Direct) } + unsafe { riscv::register::stvec::write(trap_entry as usize, TrapMode::Direct) }; + // enable interrupt + unsafe { riscv::register::sie::set_ssoft() }; + unsafe { riscv::register::sie::set_sext() }; } } @@ -88,6 +91,7 @@ impl TrapContextOps for TrapContext { }, T::Interrupt(I::SupervisorExternal) => { // TODO: handle external interrupt, e.g. plic + panic_fatal!("Unhandled External Interrupt"); }, T::Exception(E::InstructionPageFault) | T::Exception(E::LoadPageFault) | T::Exception(E::StorePageFault) => { if from_kernel { diff --git a/kernel/src/drivers/irq/plic.rs b/kernel/src/drivers/irq/plic.rs index 28ca3d0..e93c97e 100644 --- a/kernel/src/drivers/irq/plic.rs +++ b/kernel/src/drivers/irq/plic.rs @@ -1,10 +1,12 @@ use super::IrqDriver; +use crate::arch::layout::mmap_phys_to_virt; use crate::drivers::Driver; use crate::entry::HART_ID; use crate::plat::irq::IrqController; use core::sync::atomic::{AtomicPtr, Ordering}; use fdt::{node::FdtNode, Fdt}; use log::trace; +use utils::addr::PhysAddr; const IRQ_OCCUPIED: usize = u32::MAX as usize; // OpenSBI will rewrite IRQ_M_EXT to this value const IRQ_S_EXT: usize = 9; @@ -17,21 +19,15 @@ const PLIC_ENABLE_STRIDE: usize = 0x80; const PLIC_CONTROL_OFFSET: usize = 0x200000; const PLIC_CONTROL_STRIDE: usize = 0x1000; -#[repr(C, align(0x1000))] -#[derive(Debug)] -struct PlicCtrl { - threshold: *mut u32, - claim: *mut u32, -} - #[derive(Debug)] pub struct IrqPlic where IrqPlic: IrqDriver { - priority: AtomicPtr, - pending: AtomicPtr, - enable: AtomicPtr, - control: AtomicPtr, + priority: AtomicPtr, + pending: AtomicPtr, + enable: AtomicPtr, + threshold: AtomicPtr, + claim: AtomicPtr, nr_irqs: usize, } @@ -49,8 +45,12 @@ impl IrqPlic { self.enable.load(Ordering::Relaxed) } - fn control(&self) -> *mut PlicCtrl { - self.control.load(Ordering::Relaxed) + fn threshold(&self) -> *mut u32 { + self.threshold.load(Ordering::Relaxed) + } + + fn claim(&self) -> *mut u32 { + self.claim.load(Ordering::Relaxed) } } @@ -65,7 +65,9 @@ impl Driver for IrqPlic { .expect("no PLIC base address available") .next() .unwrap() - .starting_address as *mut u8; + .starting_address; + let base_address = unsafe { mmap_phys_to_virt(PhysAddr::from(base_address)) }; + let base_address: *mut u8 = base_address.into(); let nr_irqs = node .property("riscv,ndev") @@ -110,14 +112,19 @@ impl Driver for IrqPlic { let priority = unsafe { base_address.add(PLIC_PRIORITY_OFFSET) as *mut u32 }; let pending = unsafe { base_address.add(PLIC_PENDING_OFFSET) as *mut u32 }; let enable = unsafe { base_address.add(PLIC_ENABLE_OFFSET + ctx_id * PLIC_ENABLE_STRIDE) as *mut u32 }; - let control = unsafe { (base_address.add(PLIC_CONTROL_OFFSET) as *mut PlicCtrl).add(ctx_id) }; + let threshold = unsafe { base_address.add(PLIC_CONTROL_OFFSET + ctx_id * PLIC_CONTROL_STRIDE) as *mut u32 }; + let claim = unsafe { threshold.add(1) }; + + // Reset context threshold to 0 + unsafe { threshold.write_volatile(0) }; Self { - priority: AtomicPtr::new(priority), - pending: AtomicPtr::new(pending), - enable: AtomicPtr::new(enable), - control: AtomicPtr::new(control), - nr_irqs: nr_irqs.unwrap(), + priority: AtomicPtr::new(priority), + pending: AtomicPtr::new(pending), + enable: AtomicPtr::new(enable), + threshold: AtomicPtr::new(threshold), + claim: AtomicPtr::new(claim), + nr_irqs: nr_irqs.unwrap(), } } } @@ -128,9 +135,12 @@ impl IrqController for IrqPlic { return; } + // set priority = 1 + unsafe { IrqPlic::priority(self).add(irq).write_volatile(1) }; + + // set enable = 1 let word = irq / 32; let bit = irq % 32; - let val = unsafe { IrqPlic::enable(self).add(word).read_volatile() }; let val = val | (1 << bit); unsafe { IrqPlic::enable(self).add(word).write_volatile(val) }; @@ -141,12 +151,15 @@ impl IrqController for IrqPlic { return; } + // set enable = 0 let word = irq / 32; let bit = irq % 32; - let val = unsafe { IrqPlic::enable(self).add(word).read_volatile() }; let val = val & !(1 << bit); unsafe { IrqPlic::enable(self).add(word).write_volatile(val) }; + + // set priority = 0 + unsafe { IrqPlic::priority(self).add(irq).write_volatile(0) }; } fn is_pending(&mut self, irq: usize) -> bool { @@ -162,7 +175,7 @@ impl IrqController for IrqPlic { } fn claim(&mut self) -> Option { - let val = unsafe { IrqPlic::control(self).as_ref().unwrap().claim.read_volatile() }; + let val = unsafe { IrqPlic::claim(self).read_volatile() }; if val > 0 { Some(val as usize) @@ -177,7 +190,7 @@ impl IrqController for IrqPlic { } let val = irq as u32; - unsafe { IrqPlic::control(self).as_ref().unwrap().claim.write_volatile(val) }; + unsafe { IrqPlic::claim(self).write_volatile(val) }; } } diff --git a/kernel/src/plat/irq.rs b/kernel/src/plat/irq.rs index a5b7978..dcad959 100644 --- a/kernel/src/plat/irq.rs +++ b/kernel/src/plat/irq.rs @@ -40,6 +40,7 @@ impl IrqController for DummyIrqDriver { fn complete(&mut self, _: usize) {} } +// TODO: per-core irq driver static IRQ_DRIVER: Mutex = Mutex::new(IrqDriver::DummyIrqDriver(DummyIrqDriver)); pub fn set_irq_driver(driver: IrqDriver) {