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