Skip to main content

islet_rmm/rmi/realm/
mod.rs

1pub mod params;
2pub use self::params::Params;
3use super::error::Error;
4use crate::event::RmiHandle;
5use crate::granule::GRANULE_SIZE;
6use crate::granule::{set_granule, GranuleState};
7use crate::host;
8use crate::listen;
9use crate::measurement::{HashContext, MEASUREMENTS_SLOT_RIM};
10use crate::realm::mm::stage2_translation::Stage2Translation;
11use crate::realm::mm::IPATranslation;
12use crate::realm::rd::State;
13use crate::realm::rd::{insert_rtt, Rd};
14use crate::realm::registry::{remove, VMID_SET};
15use crate::rmi::{self, metadata::IsletRealmMetadata};
16use crate::{get_granule, get_granule_if};
17
18use alloc::boxed::Box;
19use alloc::sync::Arc;
20use spin::mutex::Mutex;
21
22extern crate alloc;
23
24pub fn set_event_handler(rmi: &mut RmiHandle) {
25    #[cfg(any(not(kani), feature = "mc_rmi_realm_activate"))]
26    listen!(rmi, rmi::REALM_ACTIVATE, |arg, _, _| {
27        let rd = arg[0];
28        let mut rd_granule = get_granule_if!(rd, GranuleState::RD)?;
29        let mut rd = rd_granule.content_mut::<Rd>()?;
30
31        if let Some(meta) = rd.metadata() {
32            debug!("Realm metadata is in use!");
33            let metadata_granule = get_granule_if!(meta, GranuleState::Metadata)?;
34            let metadata_obj = metadata_granule.content::<IsletRealmMetadata>()?;
35
36            if !metadata_obj.equal_rd_rim(&rd.measurements[MEASUREMENTS_SLOT_RIM]) {
37                error!("Calculated rim and those read from metadata are not the same!");
38                return Err(Error::RmiErrorRealm(0));
39            }
40
41            if !metadata_obj.equal_rd_hash_algo(rd.hash_algo()) {
42                error!("Provided measurement hash algorithm and metadata hash algorithm are different!");
43                return Err(Error::RmiErrorRealm(0));
44            }
45        }
46
47        if !rd.at_state(State::New) {
48            return Err(Error::RmiErrorRealm(0));
49        }
50
51        rd.set_state(State::Active);
52        Ok(())
53    });
54
55    #[cfg(not(kani))]
56    listen!(rmi, rmi::REALM_CREATE, |arg, _, rmm| {
57        let rd = arg[0];
58        let params_ptr = arg[1];
59
60        if rd == params_ptr {
61            return Err(Error::RmiErrorInput);
62        }
63
64        let mut rd_granule = get_granule_if!(rd, GranuleState::Delegated)?;
65        let mut rd_obj = rd_granule.content_mut::<Rd>()?;
66        #[cfg(not(kani))]
67        // `page_table` is currently not reachable in model checking harnesses
68        rmm.page_table.map(rd, true);
69
70        rmm.page_table.map(params_ptr, false);
71        let params = host::copy_from::<Params>(params_ptr).ok_or(Error::RmiErrorInput)?;
72        rmm.page_table.unmap(params_ptr);
73        params.verify_compliance(rd)?;
74
75        for i in 0..params.rtt_num_start as usize {
76            let rtt = params.rtt_base as usize + i * GRANULE_SIZE;
77            let _ = get_granule_if!(rtt, GranuleState::Delegated)?;
78            // The below is added to avoid a fault regarding the RTT entry
79            // during the below stage 2 page table creation
80            rmm.page_table.map(rtt, true);
81        }
82
83        // revisit rmi.create_realm() (is it necessary?)
84        create_realm(params.vmid as usize).map(|_| {
85            let s2 = Box::new(Stage2Translation::new(
86                params.rtt_base as usize,
87                params.rtt_level_start as usize,
88                params.rtt_num_start as usize,
89            )) as Box<dyn IPATranslation>;
90
91            insert_rtt(params.vmid as usize, Arc::new(Mutex::new(s2)));
92
93            rd_obj.init(
94                params.vmid,
95                params.rtt_base as usize,
96                params.rtt_num_start as usize,
97                params.ipa_bits(),
98                params.rtt_level_start as isize,
99                params.rpv,
100                params.sve_en(),
101                params.sve_vl as u64,
102                params.pmu_en(),
103                params.pmu_num_ctrs as usize,
104            )
105        })?;
106
107        let rtt_base = rd_obj.rtt_base();
108        rd_obj.set_hash_algo(params.hash_algo);
109
110        #[cfg(not(kani))]
111        // `rsi` is currently not reachable in model checking harnesses
112        HashContext::new(&mut rd_obj)?.measure_realm_create(&params)?;
113
114        let mut epilogue = move || {
115            for i in 0..params.rtt_num_start as usize {
116                let rtt = rtt_base + i * GRANULE_SIZE;
117                let mut rtt_granule = get_granule_if!(rtt, GranuleState::Delegated)?;
118                set_granule(&mut rtt_granule, GranuleState::RTT)?;
119            }
120            set_granule(&mut rd_granule, GranuleState::RD)
121        };
122
123        epilogue().inspect_err(|_| {
124            #[cfg(not(kani))]
125            // `page_table` is currently not reachable in model checking harnesses
126            rmm.page_table.unmap(rd);
127            remove(params.vmid as usize).expect("Realm should be created before.");
128        })
129    });
130
131    #[cfg(any(not(kani), feature = "mc_rmi_rec_aux_count"))]
132    listen!(rmi, rmi::REC_AUX_COUNT, |arg, ret, _| {
133        let _ = get_granule_if!(arg[0], GranuleState::RD)?;
134        ret[1] = rmi::MAX_REC_AUX_GRANULES;
135        Ok(())
136    });
137
138    #[cfg(any(not(kani), feature = "mc_rmi_realm_destroy"))]
139    listen!(rmi, rmi::REALM_DESTROY, |arg, _ret, rmm| {
140        // get the lock for Rd
141        let mut rd_granule = get_granule_if!(arg[0], GranuleState::RD)?;
142        if rd_granule.num_children() > 0 {
143            return Err(Error::RmiErrorRealm(0));
144        }
145        let mut rd = rd_granule.content::<Rd>()?;
146        let vmid = rd.id();
147        let rtt_base = rd.rtt_base();
148
149        if let Some(meta) = rd.metadata() {
150            let mut meta_granule = get_granule_if!(meta, GranuleState::Metadata)?;
151            set_granule(&mut meta_granule, GranuleState::Delegated)?;
152            rd.set_metadata(None);
153            rmm.page_table.unmap(meta);
154        }
155
156        #[cfg(kani)]
157        // XXX: the below can be guaranteed by Rd's invariants
158        kani::assume(crate::granule::validate_addr(rtt_base));
159
160        #[cfg(not(feature = "gst_page_table"))]
161        {
162            #[cfg(not(kani))]
163            for i in 0..rd.rtt_num_start() {
164                let rtt = rtt_base + i * GRANULE_SIZE;
165
166                let rtt_granule = get_granule!(rtt)?;
167                if rtt_granule.num_children() > 0 {
168                    return Err(Error::RmiErrorRealm(0));
169                }
170            }
171            #[cfg(kani)]
172            {
173                // XXX: we remove the loop and consider only the first iteration
174                //      to reduce the overall verification time
175                let rtt_granule = get_granule!(rtt_base)?;
176                if rtt_granule.num_children() > 0 {
177                    return Err(Error::RmiErrorRealm(0));
178                }
179            }
180        }
181
182        #[cfg(not(kani))]
183        for i in 0..rd.rtt_num_start() {
184            let rtt = rtt_base + i * GRANULE_SIZE;
185            let mut rtt_granule = get_granule!(rtt)?;
186            set_granule(&mut rtt_granule, GranuleState::Delegated)?;
187        }
188        #[cfg(kani)]
189        {
190            // XXX: we remove the loop and consider only the first iteration
191            //      to reduce the overall verification time
192            let mut rtt_granule = get_granule!(rtt_base)?;
193            set_granule(&mut rtt_granule, GranuleState::Delegated)?;
194        }
195
196        // change state when everything goes fine.
197        set_granule(&mut rd_granule, GranuleState::Delegated)?;
198        #[cfg(not(kani))]
199        // `page_table` is currently not reachable in model checking harnesses
200        rmm.page_table.unmap(arg[0]);
201        // TODO: remove the below after modeling `VmidIsFree()`
202        #[cfg(not(kani))]
203        remove(vmid)?;
204
205        Ok(())
206    });
207
208    // ISLET_REALM_SET_METADATA is a vendor specific RMI for provisioning the realm metadata to the Realm
209    // Input registers
210    // x0: function id (0xC7000150)
211    // x1: rd - a physicall address of the RD for the target Realm
212    // x2: mdg - a physicall address of the delegated granule used for storage of the metadata
213    // x3: meta_ptr - a physicall address of the host provided (NS) metadata granule
214    listen!(rmi, rmi::ISLET_REALM_SET_METADATA, |arg, _ret, rmm| {
215        let rd_addr = arg[0];
216        let mdg_addr = arg[1];
217        let meta_ptr = arg[2];
218
219        rmm.page_table.map(meta_ptr, false);
220        let realm_metadata: Box<IsletRealmMetadata> =
221            Box::new(host::copy_from(meta_ptr).ok_or(Error::RmiErrorInput)?);
222        rmm.page_table.unmap(meta_ptr);
223        realm_metadata.dump();
224
225        if let Err(e) = realm_metadata.verify_signature() {
226            error!("Verification of realm metadata signature has failed");
227            Err(e)?;
228        }
229
230        if let Err(e) = realm_metadata.validate() {
231            error!("The content of realm metadata is not valid");
232            Err(e)?;
233        }
234
235        let mut rd_granule = get_granule_if!(rd_addr, GranuleState::RD)?;
236        let mut rd = rd_granule.content_mut::<Rd>()?;
237
238        if !rd.at_state(State::New) {
239            error!("Metadata can only be set for new realms");
240            Err(Error::RmiErrorRealm(0))?;
241        }
242
243        if rd.metadata().is_some() {
244            error!("Metadata is already set");
245            Err(Error::RmiErrorRealm(0))?;
246        }
247
248        rmm.page_table.map(mdg_addr, true);
249        let mut metadata_granule = get_granule_if!(mdg_addr, GranuleState::Delegated)?;
250        let mut metadata_obj = metadata_granule.content_mut::<IsletRealmMetadata>()?;
251
252        *metadata_obj = *realm_metadata.clone();
253        set_granule(&mut metadata_granule, GranuleState::Metadata)?;
254        rd.set_metadata(Some(mdg_addr));
255
256        Ok(())
257    });
258}
259
260fn create_realm(vmid: usize) -> Result<(), Error> {
261    let mut vmid_set = VMID_SET.lock();
262    if vmid_set.contains(&vmid) {
263        return Err(Error::RmiErrorInput);
264    } else {
265        vmid_set.insert(vmid);
266    };
267
268    Ok(())
269}
270
271#[cfg(test)]
272mod test {
273    use crate::realm::rd::{Rd, State};
274    use crate::rmi::{ERROR_INPUT, REALM_ACTIVATE, REALM_CREATE, SUCCESS};
275    use crate::test_utils::*;
276
277    use alloc::vec;
278
279    #[test]
280    fn rmi_realm_create_positive() {
281        let rd = realm_create();
282
283        let ret = rmi::<REALM_ACTIVATE>(&[rd]);
284        assert_eq!(ret[0], SUCCESS);
285
286        unsafe {
287            let rd_obj = &*(rd as *const Rd);
288            assert!(rd_obj.at_state(State::Active));
289        };
290
291        realm_destroy(rd);
292
293        miri_teardown();
294    }
295
296    // Source: https://github.com/ARM-software/cca-rmm-acs
297    // Test Case: cmd_realm_create
298    /*
299        Check 1 : params_align; rd : 0x88300000 params_ptr : 0x88303001 ret : 1
300        Check 2 : params_bound; rd : 0x88300000 params_ptr : 0x1C0B0000 ret : 1
301        Check 3 : params_bound; rd : 0x88300000 params_ptr : 0x1000000001000 ret : 1
302        Check 4 : params_pas; rd : 0x88300000 params_ptr : 0x88309000 ret : 1
303        Check 5 : params_pas; rd : 0x88300000 params_ptr : 0x6000000 ret : 1
304        Check 6 : params_valid; rd : 0x88300000 params_ptr : 0x8830C000 ret : 1
305        Check 7 : params_valid; rd : 0x88300000 params_ptr : 0x8830F000 ret : 1
306        Check 8 : params_supp
307        Skipping Test case
308        Check 9 : params_supp; rd : 0x88300000 params_ptr : 0x88315000 ret : 1
309        Check 10 : params_supp; rd : 0x88300000 params_ptr : 0x88318000 ret : 1
310        Check 11 : params_supp; rd : 0x88300000 params_ptr : 0x8831B000 ret : 1
311        Check 12 : params_supp; rd : 0x88300000 params_ptr : 0x8831E000 ret : 1
312        Check 13 : params_supp; rd : 0x88300000 params_ptr : 0x88321000 ret : 1
313        Check 14 : alias; rd : 0x88306000 params_ptr : 0x88303000 ret : 1
314        Check 15 : rd_align; rd : 0x88300001 params_ptr : 0x88303000 ret : 1
315        Check 16 : rd_bound; rd : 0x1C0B0000 params_ptr : 0x88303000 ret : 1
316        Check 17 : rd_bound; rd : 0x1000000001000 params_ptr : 0x88303000 ret : 1
317        Check 18 : rd_state; rd : 0x88324000 params_ptr : 0x88303000 ret : 1
318        Check 19 : rd_state; rd : 0x88327000 params_ptr : 0x88303000 ret : 1
319        Check 20 : rd_state; rd : 0x88336000 params_ptr : 0x88303000 ret : 1
320        Check 21 : rd_state; rd : 0x8832A000 params_ptr : 0x88303000 ret : 1
321        Check 22 : rd_state; rd : 0x88372000 params_ptr : 0x88303000 ret : 1
322        Check 23 : rtt_align; rd : 0x88300000 params_ptr : 0x88378000 ret : 1
323        Check 24 : rtt_num_level; rd : 0x88300000 params_ptr : 0x8837B000 ret : 1
324        Check 25 : rtt_state; rd : 0x88300000 params_ptr : 0x8837E000 ret : 1
325        Check 26 : vmid_valid
326        Couldn't create VMID Invalid sequence
327        Skipping Test case
328        Check 27 : vmid_valid; rd : 0x88300000 params_ptr : 0x88387000 ret : 1
329    */
330    #[test]
331    fn rmi_realm_create_negative() {
332        let test_data = vec![
333            // TODO: Cover all test data
334            ((0x88300000 as usize, 0x88303001 as usize), ERROR_INPUT),
335        ];
336
337        // main test
338        for (input, output) in test_data {
339            let ret = rmi::<REALM_CREATE>(&[input.0, input.1, 0]);
340            assert_eq!(output, ret[0]);
341        }
342    }
343}