Skip to main content

islet_rmm/rec/
gic.rs

1use super::Rec;
2use crate::gic::*;
3use crate::rmi::error::Error;
4use crate::rmi::rec::run::Run;
5
6use aarch64_cpu::registers::*;
7
8pub fn init_gic(rec: &mut Rec<'_>) {
9    let gic_state = &mut rec.context.gic_state;
10    gic_state.ich_hcr_el2 = ICH_HCR_EL2_INIT;
11}
12
13pub fn restore_state(rec: &Rec<'_>) {
14    let gic_state = &rec.context.gic_state;
15    let nr_lrs = nr_lrs();
16    let nr_aprs = nr_aprs();
17
18    for i in 0..=nr_lrs {
19        set_lr(i, gic_state.ich_lr_el2[i]);
20    }
21    for i in 0..=nr_aprs {
22        set_ap0r(i, gic_state.ich_ap0r_el2[i]);
23        set_ap1r(i, gic_state.ich_ap1r_el2[i]);
24    }
25    ICH_VMCR_EL2.set(gic_state.ich_vmcr_el2);
26    ICH_HCR_EL2.set(gic_state.ich_hcr_el2);
27}
28
29pub fn save_state(rec: &mut Rec<'_>) {
30    let gic_state = &mut rec.context.gic_state;
31    let nr_lrs = nr_lrs();
32    let nr_aprs = nr_aprs();
33
34    for i in 0..=nr_lrs {
35        gic_state.ich_lr_el2[i] = get_lr(i);
36    }
37    for i in 0..=nr_aprs {
38        gic_state.ich_ap0r_el2[i] = get_ap0r(i);
39        gic_state.ich_ap1r_el2[i] = get_ap1r(i);
40    }
41
42    gic_state.ich_vmcr_el2 = ICH_VMCR_EL2.get();
43    gic_state.ich_hcr_el2 = ICH_HCR_EL2.get();
44    gic_state.ich_misr_el2 = ICH_MISR_EL2.get();
45
46    ICH_HCR_EL2.set(gic_state.ich_hcr_el2 & !(ICH_HCR_EL2::En.mask << ICH_HCR_EL2::En.shift));
47}
48
49pub fn receive_state_from_host(rec: &mut Rec<'_>, run: &Run) -> Result<(), Error> {
50    let gic_state = &mut rec.context.gic_state;
51    let nr_lrs = nr_lrs();
52
53    gic_state.ich_lr_el2[..nr_lrs].copy_from_slice(&run.entry_gic_lrs()[..nr_lrs]);
54    gic_state.ich_hcr_el2 &= !ICH_HCR_EL2_NS_MASK;
55    gic_state.ich_hcr_el2 |= run.entry_gic_hcr() & ICH_HCR_EL2_NS_MASK;
56    Ok(())
57}
58
59pub fn send_state_to_host(rec: &Rec<'_>, run: &mut Run) -> Result<(), Error> {
60    let gic_state = &rec.context.gic_state;
61    let nr_lrs = nr_lrs();
62
63    run.exit_gic_lrs_mut()[..nr_lrs].copy_from_slice(&gic_state.ich_lr_el2[..nr_lrs]);
64    run.set_gic_misr(gic_state.ich_misr_el2);
65    run.set_gic_vmcr(gic_state.ich_vmcr_el2);
66    run.set_gic_hcr(gic_state.ich_hcr_el2 & (ICH_HCR_EL2_EOI_COUNT_MASK | ICH_HCR_EL2_NS_MASK));
67    Ok(())
68}
69
70pub fn validate_state(run: &Run) -> bool {
71    let hcr = run.entry_gic_hcr();
72
73    /* Validate rec_entry.gicv3_hcr MBZ bits */
74    if (hcr & !ICH_HCR_EL2_NS_MASK) != 0 {
75        return false;
76    }
77
78    for i in 0..nr_lrs() {
79        let lrs = run.entry_gic_lrs();
80        let lr = lrs[i];
81
82        let state = (lr >> ICH_LR0_EL2::State.shift) & ICH_LR0_EL2::State.mask;
83        let vintid = (lr >> ICH_LR0_EL2::vINTID.shift) & ICH_LR0_EL2::vINTID.mask;
84        let priority = (lr >> ICH_LR0_EL2::Priority.shift) & ICH_LR0_EL2::Priority.mask;
85
86        let pintid_mask = ICH_LR0_EL2::pINTID.mask << ICH_LR0_EL2::pINTID.shift;
87        let eoi_mask = ICH_LR0_EL2::EOI.mask << ICH_LR0_EL2::EOI.shift;
88        let only_eoi = pintid_mask & !eoi_mask;
89
90        let hw = (lr >> ICH_LR0_EL2::HW.shift) & ICH_LR0_EL2::HW.mask;
91
92        if state == ICH_LR0_EL2::State::Invalid.into() {
93            continue;
94        }
95
96        /* The RMM Specification imposes the constraint that HW == '0' */
97        if hw != 0
98            /* Check RES0 bits in the Priority field */
99            || priority & pri_res0_mask() != 0
100            /* Only the EOI bit in the pINTID is allowed to be set */
101            || lr & only_eoi != 0
102            /* Check if vINTID is in the valid range */
103            || !valid_vintid(vintid)
104        {
105            return false;
106        }
107
108        /*
109         * Behavior is UNPREDICTABLE if two or more List Registers
110         * specify the same vINTID.
111         */
112        for j in i + 1..=nr_lrs() {
113            let lrs = run.entry_gic_lrs();
114            let lr = lrs[j];
115
116            let vintid_2 = (lr >> ICH_LR0_EL2::vINTID.shift) & ICH_LR0_EL2::vINTID.mask;
117            let state = (lr >> ICH_LR0_EL2::State.shift) & ICH_LR0_EL2::State.mask;
118
119            if state == ICH_LR0_EL2::State::Invalid.into() {
120                continue;
121            }
122
123            if vintid == vintid_2 {
124                return false;
125            }
126        }
127    }
128
129    true
130}