hal_riscv/hw/imsic.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
use super::csr::{Sireg, Siselect, Stopei};
use bit_field::BitField;
/// The Incoming Message-Signalled Interrupt Controller (IMSIC) is a hardware component associated
/// with a hart that coordinates incoming message-signalled interrupts (MSIs), and signals to the
/// hart when pending interrupts need to be serviced.
///
/// Each IMSIC has a register file in memory for devices to write to (to trigger an interrupt), as
/// well as a CSR interface for the hart to configure it via. There are separate interrupt files
/// for each privilege level.
pub struct Imsic {}
impl Imsic {
pub fn init() {
unsafe {
// Enable the IMSIC
Siselect::write(Siselect::EIDELIVERY);
Sireg::write(1);
// Set the priority to see all interrupts
Siselect::write(Siselect::EITHRESHOLD);
Sireg::write(0);
}
}
pub fn enable(number: usize) {
/*
* On RV64, the even-numbered registers are not selectable. We need to skip over one
* register for each 64-bit block of interrupts.
*/
let eie_reg = Siselect::EIE_BASE + 2 * (number / 64);
let eie_bit = number % 64;
unsafe {
Siselect::write(eie_reg);
let mut value = Sireg::read();
value.set_bit(eie_bit, true);
Sireg::write(value);
}
}
pub fn pop() -> u16 {
let stopei = Stopei::read() as u32;
/*
* Bits 0..11 = interrupt priority (should actually be the same as the identity)
* Bits 16..27 = interrupt identity
*/
stopei.get_bits(16..27) as u16
}
}