61 lines
1.6 KiB
Rust
61 lines
1.6 KiB
Rust
use crate::board;
|
|
|
|
const PLIC: usize = crate::mmu::phys_to_virt(board::PLIC_BASE);
|
|
const PLIC_PRIORITY: usize = PLIC;
|
|
|
|
// External interrupts go to the boot hart only: its supervisor context is
|
|
// 2 * hart + 1 on QEMU virt (even contexts are machine mode).
|
|
fn context() -> usize {
|
|
2 * crate::smp::boot_hart() + 1
|
|
}
|
|
|
|
fn enable_base() -> usize {
|
|
PLIC + 0x2000 + context() * 0x80
|
|
}
|
|
|
|
fn threshold() -> usize {
|
|
PLIC + 0x20_0000 + context() * 0x1000
|
|
}
|
|
|
|
fn claim_reg() -> usize {
|
|
threshold() + 4
|
|
}
|
|
|
|
pub struct Plic;
|
|
|
|
impl Plic {
|
|
pub fn init() {
|
|
unsafe { core::ptr::write_volatile(threshold() as *mut u32, 0) };
|
|
}
|
|
|
|
pub fn enable(irq: u32) {
|
|
let word = (irq / 32) as usize;
|
|
let bit = irq % 32;
|
|
let addr = enable_base() + word * 4;
|
|
unsafe {
|
|
let current = core::ptr::read_volatile(addr as *const u32);
|
|
core::ptr::write_volatile(addr as *mut u32, current | (1 << bit));
|
|
}
|
|
let prio_addr = PLIC_PRIORITY + (irq as usize) * 4;
|
|
unsafe { core::ptr::write_volatile(prio_addr as *mut u32, 1) };
|
|
}
|
|
|
|
pub fn disable(irq: u32) {
|
|
let word = (irq / 32) as usize;
|
|
let bit = irq % 32;
|
|
let addr = enable_base() + word * 4;
|
|
unsafe {
|
|
let current = core::ptr::read_volatile(addr as *const u32);
|
|
core::ptr::write_volatile(addr as *mut u32, current & !(1 << bit));
|
|
}
|
|
}
|
|
|
|
pub fn claim() -> u32 {
|
|
unsafe { core::ptr::read_volatile(claim_reg() as *const u32) }
|
|
}
|
|
|
|
pub fn complete(irq: u32) {
|
|
unsafe { core::ptr::write_volatile(claim_reg() as *mut u32, irq) };
|
|
}
|
|
}
|