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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
pub(crate) mod params;
pub(crate) use self::params::Params;
use super::error::Error;
use crate::event::Mainloop;
use crate::granule::GRANULE_SIZE;
use crate::granule::{set_granule, GranuleState};
use crate::host;
use crate::listen;
use crate::measurement::HashContext;
use crate::mm::translation::PageTable;
use crate::realm::mm::stage2_translation::Stage2Translation;
use crate::realm::mm::IPATranslation;
use crate::realm::rd::State;
use crate::realm::rd::{insert_rtt, Rd};
use crate::realm::registry::{remove, VMID_SET};
use crate::rmi;
use crate::{get_granule, get_granule_if};
use alloc::boxed::Box;
use alloc::sync::Arc;
use spin::mutex::Mutex;
extern crate alloc;
pub fn set_event_handler(mainloop: &mut Mainloop) {
#[cfg(any(not(kani), feature = "mc_rmi_realm_activate"))]
listen!(mainloop, rmi::REALM_ACTIVATE, |arg, _, _| {
let rd = arg[0];
let mut rd_granule = get_granule_if!(rd, GranuleState::RD)?;
let mut rd = rd_granule.content_mut::<Rd>()?;
if !rd.at_state(State::New) {
return Err(Error::RmiErrorRealm(0));
}
rd.set_state(State::Active);
Ok(())
});
#[cfg(not(kani))]
listen!(mainloop, rmi::REALM_CREATE, |arg, _, rmm| {
let rd = arg[0];
let params_ptr = arg[1];
if rd == params_ptr {
return Err(Error::RmiErrorInput);
}
let mut rd_granule = get_granule_if!(rd, GranuleState::Delegated)?;
let mut rd_obj = rd_granule.content_mut::<Rd>()?;
#[cfg(not(kani))]
// `page_table` is currently not reachable in model checking harnesses
rmm.page_table.map(rd, true);
let params = host::copy_from::<Params>(params_ptr).ok_or(Error::RmiErrorInput)?;
params.verify_compliance(rd)?;
for i in 0..params.rtt_num_start as usize {
let rtt = params.rtt_base as usize + i * GRANULE_SIZE;
let _ = get_granule_if!(rtt, GranuleState::Delegated)?;
// The below is added to avoid a fault regarding the RTT entry
// during the below stage 2 page table creation
PageTable::get_ref().map(rtt, true);
}
// revisit rmi.create_realm() (is it necessary?)
create_realm(params.vmid as usize).map(|_| {
let s2 = Box::new(Stage2Translation::new(
params.rtt_base as usize,
params.rtt_level_start as usize,
params.rtt_num_start as usize,
)) as Box<dyn IPATranslation>;
insert_rtt(params.vmid as usize, Arc::new(Mutex::new(s2)));
rd_obj.init(
params.vmid,
params.rtt_base as usize,
params.rtt_num_start as usize,
params.ipa_bits(),
params.rtt_level_start as isize,
params.rpv,
)
})?;
let rtt_base = rd_obj.rtt_base();
rd_obj.set_hash_algo(params.hash_algo);
#[cfg(not(kani))]
// `rsi` is currently not reachable in model checking harnesses
HashContext::new(&mut rd_obj)?.measure_realm_create(¶ms)?;
let mut epilogue = move || {
for i in 0..params.rtt_num_start as usize {
let rtt = rtt_base + i * GRANULE_SIZE;
let mut rtt_granule = get_granule_if!(rtt, GranuleState::Delegated)?;
set_granule(&mut rtt_granule, GranuleState::RTT)?;
}
set_granule(&mut rd_granule, GranuleState::RD)
};
epilogue().map_err(|e| {
#[cfg(not(kani))]
// `page_table` is currently not reachable in model checking harnesses
rmm.page_table.unmap(rd);
remove(params.vmid as usize).expect("Realm should be created before.");
e
})
});
#[cfg(any(not(kani), feature = "mc_rmi_rec_aux_count"))]
listen!(mainloop, rmi::REC_AUX_COUNT, |arg, ret, _| {
let _ = get_granule_if!(arg[0], GranuleState::RD)?;
ret[1] = rmi::MAX_REC_AUX_GRANULES;
Ok(())
});
#[cfg(not(kani))]
listen!(mainloop, rmi::REALM_DESTROY, |arg, _ret, rmm| {
// get the lock for Rd
let mut rd_granule = get_granule_if!(arg[0], GranuleState::RD)?;
#[cfg(feature = "gst_page_table")]
if rd_granule.num_children() > 0 {
return Err(Error::RmiErrorRealm(0));
}
let rd = rd_granule.content::<Rd>()?;
let vmid = rd.id();
#[cfg(feature = "gst_page_table")]
if rd_granule.num_children() > 0 {
return Err(Error::RmiErrorRealm(0));
}
let rtt_base = rd.rtt_base();
for i in 0..rd.rtt_num_start() {
let rtt = rtt_base + i * GRANULE_SIZE;
let mut rtt_granule = get_granule_if!(rtt, GranuleState::RTT)?;
set_granule(&mut rtt_granule, GranuleState::Delegated)?;
}
// change state when everything goes fine.
set_granule(&mut rd_granule, GranuleState::Delegated)?;
#[cfg(not(kani))]
// `page_table` is currently not reachable in model checking harnesses
rmm.page_table.unmap(arg[0]);
remove(vmid)?;
Ok(())
});
}
fn create_realm(vmid: usize) -> Result<(), Error> {
let mut vmid_set = VMID_SET.lock();
if vmid_set.contains(&vmid) {
return Err(Error::RmiErrorInput);
} else {
vmid_set.insert(vmid);
};
Ok(())
}
#[cfg(test)]
mod test {
use crate::realm::rd::{Rd, State};
use crate::rmi::{ERROR_INPUT, REALM_ACTIVATE, REALM_CREATE, SUCCESS};
use crate::test_utils::*;
use alloc::vec;
#[test]
fn rmi_realm_create_positive() {
let rd = realm_create();
let ret = rmi::<REALM_ACTIVATE>(&[rd]);
assert_eq!(ret[0], SUCCESS);
unsafe {
let rd_obj = &*(rd as *const Rd);
assert!(rd_obj.at_state(State::Active));
};
realm_destroy(rd);
miri_teardown();
}
// Source: https://github.com/ARM-software/cca-rmm-acs
// Test Case: cmd_realm_create
/*
Check 1 : params_align; rd : 0x88300000 params_ptr : 0x88303001 ret : 1
Check 2 : params_bound; rd : 0x88300000 params_ptr : 0x1C0B0000 ret : 1
Check 3 : params_bound; rd : 0x88300000 params_ptr : 0x1000000001000 ret : 1
Check 4 : params_pas; rd : 0x88300000 params_ptr : 0x88309000 ret : 1
Check 5 : params_pas; rd : 0x88300000 params_ptr : 0x6000000 ret : 1
Check 6 : params_valid; rd : 0x88300000 params_ptr : 0x8830C000 ret : 1
Check 7 : params_valid; rd : 0x88300000 params_ptr : 0x8830F000 ret : 1
Check 8 : params_supp
Skipping Test case
Check 9 : params_supp; rd : 0x88300000 params_ptr : 0x88315000 ret : 1
Check 10 : params_supp; rd : 0x88300000 params_ptr : 0x88318000 ret : 1
Check 11 : params_supp; rd : 0x88300000 params_ptr : 0x8831B000 ret : 1
Check 12 : params_supp; rd : 0x88300000 params_ptr : 0x8831E000 ret : 1
Check 13 : params_supp; rd : 0x88300000 params_ptr : 0x88321000 ret : 1
Check 14 : alias; rd : 0x88306000 params_ptr : 0x88303000 ret : 1
Check 15 : rd_align; rd : 0x88300001 params_ptr : 0x88303000 ret : 1
Check 16 : rd_bound; rd : 0x1C0B0000 params_ptr : 0x88303000 ret : 1
Check 17 : rd_bound; rd : 0x1000000001000 params_ptr : 0x88303000 ret : 1
Check 18 : rd_state; rd : 0x88324000 params_ptr : 0x88303000 ret : 1
Check 19 : rd_state; rd : 0x88327000 params_ptr : 0x88303000 ret : 1
Check 20 : rd_state; rd : 0x88336000 params_ptr : 0x88303000 ret : 1
Check 21 : rd_state; rd : 0x8832A000 params_ptr : 0x88303000 ret : 1
Check 22 : rd_state; rd : 0x88372000 params_ptr : 0x88303000 ret : 1
Check 23 : rtt_align; rd : 0x88300000 params_ptr : 0x88378000 ret : 1
Check 24 : rtt_num_level; rd : 0x88300000 params_ptr : 0x8837B000 ret : 1
Check 25 : rtt_state; rd : 0x88300000 params_ptr : 0x8837E000 ret : 1
Check 26 : vmid_valid
Couldn't create VMID Invalid sequence
Skipping Test case
Check 27 : vmid_valid; rd : 0x88300000 params_ptr : 0x88387000 ret : 1
*/
#[test]
fn rmi_realm_create_negative() {
let test_data = vec![
// TODO: Cover all test data
((0x88300000 as usize, 0x88303001 as usize), ERROR_INPUT),
];
// main test
for (input, output) in test_data {
let ret = rmi::<REALM_CREATE>(&[input.0, input.1, 0]);
assert_eq!(output, ret[0]);
}
}
}