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