Skip to main content

islet_rmm/
gic.rs

1use aarch64_cpu::registers::*;
2use lazy_static::lazy_static;
3
4pub const ICH_HCR_EL2_INIT: u64 = (ICH_HCR_EL2::En.mask << ICH_HCR_EL2::En.shift)
5    + (ICH_HCR_EL2::vSGIEOICount.mask << ICH_HCR_EL2::vSGIEOICount.shift)
6    + (ICH_HCR_EL2::DVIM.mask << ICH_HCR_EL2::DVIM.shift);
7
8// Interrupt Controller List Registers (ICH_LR)
9const ICH_LR_PRIORITY_WIDTH: u64 = 8;
10
11pub const ICH_HCR_EL2_NS_MASK: u64 = (ICH_HCR_EL2::UIE.mask << ICH_HCR_EL2::UIE.shift)
12    | (ICH_HCR_EL2::LRENPIE.mask << ICH_HCR_EL2::LRENPIE.shift)
13    | (ICH_HCR_EL2::NPIE.mask << ICH_HCR_EL2::NPIE.shift)
14    | (ICH_HCR_EL2::VGrp1DIE.mask << ICH_HCR_EL2::VGrp1DIE.shift)
15    | (ICH_HCR_EL2::VGrp1EIE.mask << ICH_HCR_EL2::VGrp1EIE.shift)
16    | (ICH_HCR_EL2::VGrp0DIE.mask << ICH_HCR_EL2::VGrp0DIE.shift)
17    | (ICH_HCR_EL2::VGrp0EIE.mask << ICH_HCR_EL2::VGrp0EIE.shift)
18    | (ICH_HCR_EL2::TDIR.mask << ICH_HCR_EL2::TDIR.shift);
19
20const ICH_HCR_EL2_EOI_COUNT_WIDTH: usize = 5;
21pub const ICH_HCR_EL2_EOI_COUNT_MASK: u64 =
22    ((!0u64) >> (64 - ICH_HCR_EL2_EOI_COUNT_WIDTH)) << ICH_HCR_EL2::EOIcount.shift;
23
24const MAX_SPI_ID: u64 = 1019;
25
26const MIN_EPPI_ID: u64 = 1056;
27const MAX_EPPI_ID: u64 = 1119;
28
29const MIN_ESPI_ID: u64 = 4096;
30const MAX_ESPI_ID: u64 = 5119;
31
32const MIN_LPI_ID: u64 = 8192;
33
34#[allow(dead_code)]
35pub struct GicFeatures {
36    pub nr_lrs: usize,
37    pub nr_aprs: usize,
38    pub pri_res0_mask: u64,
39    pub max_vintid: u64,
40    pub ext_range: bool,
41}
42
43lazy_static! {
44    pub static ref GIC_FEATURES: GicFeatures = {
45        trace!("read gic features");
46        let nr_lrs = ICH_VTR_EL2.read(ICH_VTR_EL2::ListRegs) as usize;
47        trace!("nr_lrs (LIST) {}", nr_lrs);
48        let id = ICH_VTR_EL2.read(ICH_VTR_EL2::IDbits);
49        let max_vintid = if id == 0 {
50            (1u64 << 16) - 1
51        } else {
52            (1u64 << 24) - 1
53        };
54        trace!("id {} max_vintid {}", id, max_vintid);
55        let pre = ICH_VTR_EL2.read(ICH_VTR_EL2::PREbits) + 1;
56        let nr_aprs = (1 << (pre - 5)) - 1;
57        trace!("pre {}, nr_aprs {}", pre, nr_aprs);
58        let pri = ICH_VTR_EL2.read(ICH_VTR_EL2::PRIbits) + 1;
59        let pri_res0_mask = (1u64 << (ICH_LR_PRIORITY_WIDTH - pri)) - 1;
60        trace!("pri {} pri_res0_mask {}", pri, pri_res0_mask);
61        let ext_range = ICC_CTLR_EL1.read(ICC_CTLR_EL1::ExtRange) != 0;
62        trace!("icc_ctlr ext_range {}", ext_range);
63        GicFeatures {
64            nr_lrs,
65            nr_aprs,
66            pri_res0_mask,
67            max_vintid,
68            ext_range,
69        }
70    };
71}
72
73pub fn nr_lrs() -> usize {
74    GIC_FEATURES.nr_lrs
75}
76
77pub fn nr_aprs() -> usize {
78    GIC_FEATURES.nr_aprs
79}
80
81pub fn pri_res0_mask() -> u64 {
82    GIC_FEATURES.pri_res0_mask
83}
84
85pub fn set_lr(i: usize, val: u64) {
86    match i {
87        0 => ICH_LR0_EL2.set(val),
88        1 => ICH_LR1_EL2.set(val),
89        2 => ICH_LR2_EL2.set(val),
90        3 => ICH_LR3_EL2.set(val),
91        4 => ICH_LR4_EL2.set(val),
92        5 => ICH_LR5_EL2.set(val),
93        6 => ICH_LR6_EL2.set(val),
94        7 => ICH_LR7_EL2.set(val),
95        8 => ICH_LR8_EL2.set(val),
96        9 => ICH_LR9_EL2.set(val),
97        10 => ICH_LR10_EL2.set(val),
98        11 => ICH_LR11_EL2.set(val),
99        12 => ICH_LR12_EL2.set(val),
100        13 => ICH_LR13_EL2.set(val),
101        14 => ICH_LR14_EL2.set(val),
102        15 => ICH_LR15_EL2.set(val),
103        _ => {}
104    }
105}
106
107pub fn set_ap0r(i: usize, val: u64) {
108    match i {
109        0 => ICH_AP0R0_EL2.set(val),
110        1 => ICH_AP0R1_EL2.set(val),
111        2 => ICH_AP0R2_EL2.set(val),
112        3 => ICH_AP0R3_EL2.set(val),
113        _ => {}
114    }
115}
116
117pub fn set_ap1r(i: usize, val: u64) {
118    match i {
119        0 => ICH_AP1R0_EL2.set(val),
120        1 => ICH_AP1R1_EL2.set(val),
121        2 => ICH_AP1R2_EL2.set(val),
122        3 => ICH_AP1R3_EL2.set(val),
123        _ => {}
124    }
125}
126
127pub fn get_lr(i: usize) -> u64 {
128    match i {
129        0 => ICH_LR0_EL2.get(),
130        1 => ICH_LR1_EL2.get(),
131        2 => ICH_LR2_EL2.get(),
132        3 => ICH_LR3_EL2.get(),
133        4 => ICH_LR4_EL2.get(),
134        5 => ICH_LR5_EL2.get(),
135        6 => ICH_LR6_EL2.get(),
136        7 => ICH_LR7_EL2.get(),
137        8 => ICH_LR8_EL2.get(),
138        9 => ICH_LR9_EL2.get(),
139        10 => ICH_LR10_EL2.get(),
140        11 => ICH_LR11_EL2.get(),
141        12 => ICH_LR12_EL2.get(),
142        13 => ICH_LR13_EL2.get(),
143        14 => ICH_LR14_EL2.get(),
144        15 => ICH_LR15_EL2.get(),
145        _ => unreachable!(),
146    }
147}
148
149pub fn get_ap0r(i: usize) -> u64 {
150    match i {
151        0 => ICH_AP0R0_EL2.get(),
152        1 => ICH_AP0R1_EL2.get(),
153        2 => ICH_AP0R2_EL2.get(),
154        3 => ICH_AP0R3_EL2.get(),
155        _ => unreachable!(),
156    }
157}
158
159pub fn get_ap1r(i: usize) -> u64 {
160    match i {
161        0 => ICH_AP1R0_EL2.get(),
162        1 => ICH_AP1R1_EL2.get(),
163        2 => ICH_AP1R2_EL2.get(),
164        3 => ICH_AP1R3_EL2.get(),
165        _ => unreachable!(),
166    }
167}
168
169pub fn valid_vintid(intid: u64) -> bool {
170    /* Check for INTID [0..1019] and [8192..] */
171    if intid <= MAX_SPI_ID || (intid >= MIN_LPI_ID && intid <= GIC_FEATURES.max_vintid) {
172        return true;
173    }
174
175    /*
176     * If extended INTID range sopported, check for
177     * Extended PPI [1056..1119] and Extended SPI [4096..5119]
178     */
179    if GIC_FEATURES.ext_range {
180        return (intid >= MIN_EPPI_ID && intid <= MAX_EPPI_ID)
181            || (intid >= MIN_ESPI_ID && intid <= MAX_ESPI_ID);
182    }
183
184    false
185}