Skip to main content

islet_rmm/rec/
mmio.rs

1use crate::rec::{Rec, RmmRecEmulatableAbort::EmulatableAbort};
2use crate::rmi::error::Error;
3use crate::rmi::rec::run::{EntryFlag, Run};
4use armv9a::regs::*;
5
6pub fn emulate_mmio(rec: &mut Rec<'_>, run: &Run) -> Result<(), Error> {
7    let flags = run.entry_flags();
8
9    // Host has not completed emulation for an Emulatable Abort.
10    // if INJECT_SEA is set then the value of EMUL_MMIO is ignored.
11    if flags.get_masked(EntryFlag::INJECT_SEA | EntryFlag::EMUL_MMIO) == 0 {
12        return Ok(());
13    }
14
15    let esr_el2 = rec.context.sys_regs.esr_el2;
16    let esr = EsrEl2::new(esr_el2);
17    let ec = esr.get_masked_value(EsrEl2::EC);
18    let wnr = esr.get_masked_value(EsrEl2::WNR);
19    let rt = esr.get_masked_value(EsrEl2::SRT) as usize;
20
21    if ec != ESR_EL2_EC_DATA_ABORT || rec.emulatable_abort() != EmulatableAbort {
22        return Err(Error::RmiErrorRec);
23    }
24
25    // MMIO read case
26    if wnr == 0 && rt != 31 {
27        let mask = esr.get_access_size_mask();
28        let val = run.entry_gpr(0)? & mask;
29        let sign_extended = esr.get_masked_value(EsrEl2::SSE);
30        if sign_extended != 0 {
31            // TODO
32            unimplemented!();
33        }
34        rec.context.gp_regs[rt] = val;
35    }
36    rec.context.elr_el2 += 4;
37    Ok(())
38}