mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
fix: kernel: correct plic driver and enable external interrupt on trap init
This commit is contained in:
parent
9b2cca3f69
commit
d0bf1b876b
@ -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 {
|
||||||
|
@ -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) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user