fix: kernel: correct plic driver and enable external interrupt on trap init

This commit is contained in:
Paul Pan 2024-08-23 19:26:28 +08:00
parent 9b2cca3f69
commit d0bf1b876b
3 changed files with 43 additions and 25 deletions

View File

@ -29,7 +29,10 @@ impl TrapOps for Trap {
// anyway, clear sscratch // anyway, clear sscratch
riscv::register::sscratch::write(0); riscv::register::sscratch::write(0);
// set trap_entry // 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) => { T::Interrupt(I::SupervisorExternal) => {
// TODO: handle external interrupt, e.g. plic // TODO: handle external interrupt, e.g. plic
panic_fatal!("Unhandled External Interrupt");
}, },
T::Exception(E::InstructionPageFault) | T::Exception(E::LoadPageFault) | T::Exception(E::StorePageFault) => { T::Exception(E::InstructionPageFault) | T::Exception(E::LoadPageFault) | T::Exception(E::StorePageFault) => {
if from_kernel { if from_kernel {

View File

@ -1,10 +1,12 @@
use super::IrqDriver; use super::IrqDriver;
use crate::arch::layout::mmap_phys_to_virt;
use crate::drivers::Driver; use crate::drivers::Driver;
use crate::entry::HART_ID; use crate::entry::HART_ID;
use crate::plat::irq::IrqController; use crate::plat::irq::IrqController;
use core::sync::atomic::{AtomicPtr, Ordering}; use core::sync::atomic::{AtomicPtr, Ordering};
use fdt::{node::FdtNode, Fdt}; use fdt::{node::FdtNode, Fdt};
use log::trace; 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_OCCUPIED: usize = u32::MAX as usize; // OpenSBI will rewrite IRQ_M_EXT to this value
const IRQ_S_EXT: usize = 9; 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_OFFSET: usize = 0x200000;
const PLIC_CONTROL_STRIDE: usize = 0x1000; const PLIC_CONTROL_STRIDE: usize = 0x1000;
#[repr(C, align(0x1000))]
#[derive(Debug)]
struct PlicCtrl {
threshold: *mut u32,
claim: *mut u32,
}
#[derive(Debug)] #[derive(Debug)]
pub struct IrqPlic pub struct IrqPlic
where IrqPlic: IrqDriver where IrqPlic: IrqDriver
{ {
priority: AtomicPtr<u32>, priority: AtomicPtr<u32>,
pending: AtomicPtr<u32>, pending: AtomicPtr<u32>,
enable: AtomicPtr<u32>, enable: AtomicPtr<u32>,
control: AtomicPtr<PlicCtrl>, threshold: AtomicPtr<u32>,
claim: AtomicPtr<u32>,
nr_irqs: usize, nr_irqs: usize,
} }
@ -49,8 +45,12 @@ impl IrqPlic {
self.enable.load(Ordering::Relaxed) self.enable.load(Ordering::Relaxed)
} }
fn control(&self) -> *mut PlicCtrl { fn threshold(&self) -> *mut u32 {
self.control.load(Ordering::Relaxed) 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") .expect("no PLIC base address available")
.next() .next()
.unwrap() .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 let nr_irqs = node
.property("riscv,ndev") .property("riscv,ndev")
@ -110,14 +112,19 @@ impl Driver for IrqPlic {
let priority = unsafe { base_address.add(PLIC_PRIORITY_OFFSET) as *mut u32 }; 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 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 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 { Self {
priority: AtomicPtr::new(priority), priority: AtomicPtr::new(priority),
pending: AtomicPtr::new(pending), pending: AtomicPtr::new(pending),
enable: AtomicPtr::new(enable), enable: AtomicPtr::new(enable),
control: AtomicPtr::new(control), threshold: AtomicPtr::new(threshold),
nr_irqs: nr_irqs.unwrap(), claim: AtomicPtr::new(claim),
nr_irqs: nr_irqs.unwrap(),
} }
} }
} }
@ -128,9 +135,12 @@ impl IrqController for IrqPlic {
return; return;
} }
// set priority = 1
unsafe { IrqPlic::priority(self).add(irq).write_volatile(1) };
// set enable = 1
let word = irq / 32; let word = irq / 32;
let bit = irq % 32; let bit = irq % 32;
let val = unsafe { IrqPlic::enable(self).add(word).read_volatile() }; let val = unsafe { IrqPlic::enable(self).add(word).read_volatile() };
let val = val | (1 << bit); let val = val | (1 << bit);
unsafe { IrqPlic::enable(self).add(word).write_volatile(val) }; unsafe { IrqPlic::enable(self).add(word).write_volatile(val) };
@ -141,12 +151,15 @@ impl IrqController for IrqPlic {
return; return;
} }
// set enable = 0
let word = irq / 32; let word = irq / 32;
let bit = irq % 32; let bit = irq % 32;
let val = unsafe { IrqPlic::enable(self).add(word).read_volatile() }; let val = unsafe { IrqPlic::enable(self).add(word).read_volatile() };
let val = val & !(1 << bit); let val = val & !(1 << bit);
unsafe { IrqPlic::enable(self).add(word).write_volatile(val) }; 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 { fn is_pending(&mut self, irq: usize) -> bool {
@ -162,7 +175,7 @@ impl IrqController for IrqPlic {
} }
fn claim(&mut self) -> Option<usize> { fn claim(&mut self) -> Option<usize> {
let val = unsafe { IrqPlic::control(self).as_ref().unwrap().claim.read_volatile() }; let val = unsafe { IrqPlic::claim(self).read_volatile() };
if val > 0 { if val > 0 {
Some(val as usize) Some(val as usize)
@ -177,7 +190,7 @@ impl IrqController for IrqPlic {
} }
let val = irq as u32; let val = irq as u32;
unsafe { IrqPlic::control(self).as_ref().unwrap().claim.write_volatile(val) }; unsafe { IrqPlic::claim(self).write_volatile(val) };
} }
} }

View File

@ -40,6 +40,7 @@ impl IrqController for DummyIrqDriver {
fn complete(&mut self, _: usize) {} fn complete(&mut self, _: usize) {}
} }
// TODO: per-core irq driver
static IRQ_DRIVER: Mutex<IrqDriver> = Mutex::new(IrqDriver::DummyIrqDriver(DummyIrqDriver)); static IRQ_DRIVER: Mutex<IrqDriver> = Mutex::new(IrqDriver::DummyIrqDriver(DummyIrqDriver));
pub fn set_irq_driver(driver: IrqDriver) { pub fn set_irq_driver(driver: IrqDriver) {