Files
k-os/crates/adapter-riscv/src/hw/plic.rs

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) };
}
}