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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use crate::asm::{smc, SMC_SUCCESS};
use crate::event::Mainloop;
use crate::granule::{set_granule, GranuleState};
use crate::listen;
use crate::rmi;
use crate::rmi::error::Error;
#[cfg(not(feature = "gst_page_table"))]
use crate::{get_granule, get_granule_if};
#[cfg(feature = "gst_page_table")]
use crate::{get_granule, get_granule_if, set_state_and_get_granule};

#[cfg(feature = "gst_page_table")]
use vmsa::error::Error as MmError;

extern crate alloc;

// defined in trusted-firmware-a/include/services/rmmd_svc.h
pub const MARK_REALM: usize = 0xc400_01b0;
pub const MARK_NONSECURE: usize = 0xc400_01b1;

pub fn set_event_handler(mainloop: &mut Mainloop) {
    #[cfg(any(not(kani), feature = "mc_rmi_granule_delegate"))]
    listen!(mainloop, rmi::GRANULE_DELEGATE, |arg, _, rmm| {
        let addr = arg[0];
        #[cfg(feature = "gst_page_table")]
        let mut granule = match get_granule_if!(addr, GranuleState::Undelegated) {
            Err(MmError::MmNoEntry) => set_state_and_get_granule!(addr, GranuleState::Undelegated),
            other => other,
        }?;
        #[cfg(not(feature = "gst_page_table"))]
        let mut granule = get_granule_if!(addr, GranuleState::Undelegated)?;

        if smc(MARK_REALM, &[addr])[0] != SMC_SUCCESS {
            return Err(Error::RmiErrorInput);
        }
        #[cfg(not(kani))]
        // `page_table` is currently not reachable in model checking harnesses
        rmm.page_table.map(addr, true);
        set_granule(&mut granule, GranuleState::Delegated).map_err(|e| {
            #[cfg(not(kani))]
            // `page_table` is currently not reachable in model checking harnesses
            rmm.page_table.unmap(addr);
            e
        })?;
        #[cfg(not(kani))]
        // `page_table` is currently not reachable in model checking harnesses
        rmm.page_table.unmap(addr);
        Ok(())
    });

    #[cfg(any(not(kani), feature = "mc_rmi_granule_undelegate"))]
    listen!(mainloop, rmi::GRANULE_UNDELEGATE, |arg, _, rmm| {
        let addr = arg[0];
        let mut granule = get_granule_if!(addr, GranuleState::Delegated)?;

        if smc(MARK_NONSECURE, &[addr])[0] != SMC_SUCCESS {
            panic!(
                "A delegated granule should only be undelegated on request from RMM. {:X}",
                addr
            );
        }

        #[cfg(not(kani))]
        // `page_table` is currently not reachable in model checking harnesses
        rmm.page_table.map(addr, false);
        set_granule(&mut granule, GranuleState::Undelegated).map_err(|e| {
            #[cfg(not(kani))]
            // `page_table` is currently not reachable in model checking harnesses
            rmm.page_table.unmap(addr);
            e
        })?;
        #[cfg(not(kani))]
        // `page_table` is currently not reachable in model checking harnesses
        rmm.page_table.unmap(addr);
        Ok(())
    });
}