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
use crate::rmi::error::Error;
use crate::rmi::error::InternalError::*;
use crate::rmi::realm::Rd;
use crate::rmi::rec::run::{Run, REC_ENTRY_FLAG_EMUL_MMIO};
use armv9a::regs::*;

pub fn emulate_mmio(rd: &mut Rd, vcpu: usize, run: &Run) -> Result<(), Error> {
    let vcpu = rd
        .vcpus
        .get_mut(vcpu)
        .ok_or(Error::RmiErrorOthers(NotExistVCPU))?;
    let context = &mut vcpu.lock().context;

    let flags = run.entry_flags();

    // Host has not completed emulation for an Emulatable Abort.
    if (flags & REC_ENTRY_FLAG_EMUL_MMIO) == 0 {
        return Ok(());
    }

    let esr_el2 = context.sys_regs.esr_el2;
    let esr = EsrEl2::new(esr_el2);
    let isv = esr.get_masked_value(EsrEl2::ISV);
    let ec = esr.get_masked_value(EsrEl2::EC);
    let wnr = esr.get_masked_value(EsrEl2::WNR);
    let rt = esr.get_masked_value(EsrEl2::SRT) as usize;

    if ec != ESR_EL2_EC_DATA_ABORT || isv == 0 {
        return Err(Error::RmiErrorRec);
    }

    // MMIO read case
    if wnr == 0 && rt != 31 {
        let mask = esr.get_access_size_mask();
        let val = run.entry_gpr(0)? & mask;
        let sign_extended = esr.get_masked_value(EsrEl2::SSE);
        if sign_extended != 0 {
            // TODO
            unimplemented!();
        }
        context.gp_regs[rt] = val;
    }
    context.elr += 4;
    Ok(())
}