1use crate::asm::{smc, SMC_SUCCESS};
2use crate::event::RmiHandle;
3use crate::granule::{set_granule, GranuleState};
4use crate::listen;
5use crate::rmi;
6use crate::rmi::error::Error;
7#[cfg(not(feature = "gst_page_table"))]
8use crate::{get_granule, get_granule_if};
9#[cfg(feature = "gst_page_table")]
10use crate::{get_granule, get_granule_if, set_state_and_get_granule};
11
12#[cfg(feature = "gst_page_table")]
13use vmsa::error::Error as MmError;
14
15extern crate alloc;
16
17pub const MARK_REALM: usize = 0xc400_01b0;
19pub const MARK_NONSECURE: usize = 0xc400_01b1;
20
21pub fn set_event_handler(rmi: &mut RmiHandle) {
22 #[cfg(any(not(kani), feature = "mc_rmi_granule_delegate"))]
23 listen!(rmi, rmi::GRANULE_DELEGATE, |arg, _, rmm| {
24 let addr = arg[0];
25
26 #[cfg(feature = "gst_page_table")]
27 let mut granule = match get_granule_if!(addr, GranuleState::Undelegated) {
28 Err(MmError::MmNoEntry) => set_state_and_get_granule!(addr, GranuleState::Undelegated),
29 other => other,
30 }?;
31 #[cfg(not(feature = "gst_page_table"))]
32 let mut granule = get_granule_if!(addr, GranuleState::Undelegated)?;
33
34 #[cfg(any(miri, test, fuzzing))]
36 core::mem::drop(granule);
37
38 if smc(MARK_REALM, &[addr])[0] != SMC_SUCCESS {
39 return Err(Error::RmiErrorInput);
40 }
41
42 #[cfg(not(kani))]
43 rmm.page_table.map(addr, true);
45
46 #[cfg(any(miri, test, fuzzing))]
47 let mut granule = get_granule_if!(addr, GranuleState::Undelegated)?;
48 set_granule(&mut granule, GranuleState::Delegated).inspect_err(|_| {
49 #[cfg(not(kani))]
50 rmm.page_table.unmap(addr);
52 })?;
53 #[cfg(not(kani))]
54 rmm.page_table.unmap(addr);
56 Ok(())
57 });
58
59 #[cfg(any(not(kani), feature = "mc_rmi_granule_undelegate"))]
60 listen!(rmi, rmi::GRANULE_UNDELEGATE, |arg, _, rmm| {
61 let addr = arg[0];
62 let mut granule = get_granule_if!(addr, GranuleState::Delegated)?;
63
64 #[cfg(any(miri, test, fuzzing))]
66 core::mem::drop(granule);
67
68 if smc(MARK_NONSECURE, &[addr])[0] != SMC_SUCCESS {
69 panic!(
70 "A delegated granule should only be undelegated on request from RMM. {:X}",
71 addr
72 );
73 }
74
75 #[cfg(any(miri, test, fuzzing))]
76 let mut granule = get_granule_if!(addr, GranuleState::Delegated)?;
77
78 #[cfg(not(kani))]
79 rmm.page_table.map(addr, false);
81 set_granule(&mut granule, GranuleState::Undelegated).inspect_err(|_| {
82 #[cfg(not(kani))]
83 rmm.page_table.unmap(addr);
85 })?;
86 #[cfg(not(kani))]
87 rmm.page_table.unmap(addr);
89 Ok(())
90 });
91}
92
93#[cfg(test)]
94mod test {
95 use crate::rmi::gpt::GranuleState;
96 use crate::rmi::{ERROR_INPUT, GRANULE_DELEGATE, GRANULE_UNDELEGATE, SUCCESS};
97 use crate::test_utils::*;
98 use crate::{get_granule, get_granule_if};
99
100 use alloc::vec;
101
102 #[test]
103 fn rmi_granule_delegate_positive() {
104 let mocking_addr = mock::host::alloc_granule(IDX_RD);
105 let ret = rmi::<GRANULE_DELEGATE>(&[mocking_addr]);
106 assert_eq!(ret[0], SUCCESS);
107 assert!(get_granule_if!(mocking_addr, GranuleState::Delegated).is_ok());
108
109 let ret = rmi::<GRANULE_UNDELEGATE>(&[mocking_addr]);
110 assert_eq!(ret[0], SUCCESS);
111 assert!(get_granule_if!(mocking_addr, GranuleState::Undelegated).is_ok());
112
113 miri_teardown();
114 }
115
116 #[test]
131 fn rmi_granule_delegate_negative() {
132 let test_data = vec![
133 (0x88300001, ERROR_INPUT),
134 (0x1C0B0000, ERROR_INPUT),
135 (0x1000000001000, ERROR_INPUT),
136 ];
138
139 for (input, output) in test_data {
140 let ret = rmi::<GRANULE_DELEGATE>(&[input]);
141 assert_eq!(output, ret[0]);
142 }
143 }
144
145 #[test]
158 fn rmi_granule_undelegate() {
159 let test_data = vec![
160 (0x88300001, ERROR_INPUT),
161 (0x1C0B0000, ERROR_INPUT),
162 (0x1000000001000, ERROR_INPUT),
163 (0x8830C000, ERROR_INPUT),
164 ];
166
167 for (input, output) in test_data {
168 let ret = rmi::<GRANULE_UNDELEGATE>(&[input]);
169 assert_eq!(output, ret[0]);
170 }
171
172 miri_teardown();
173 }
174}