Skip to main content

islet_rmm/rmi/realm/
params.rs

1use crate::const_assert_eq;
2use crate::granule::{GRANULE_SHIFT, GRANULE_SIZE};
3use crate::measurement::Hashable;
4use crate::pmu;
5use crate::realm::mm::rtt::{RTT_PAGE_LEVEL, RTT_STRIDE};
6use crate::rmi::error::Error;
7use crate::rmi::features;
8use crate::rmi::{HASH_ALGO_SHA256, HASH_ALGO_SHA512};
9use crate::simd;
10
11use armv9a::{define_bitfield, define_bits, define_mask};
12use autopadding::*;
13
14define_bits!(
15    RmiRealmFlags,
16    Lpa2[0 - 0],
17    Sve[1 - 1],
18    Pmu[2 - 2],
19    Reserved[63 - 3]
20);
21
22pad_struct_and_impl_default!(
23pub struct Params {
24    0x0    pub flags: u64,
25    0x8    pub s2sz: u8,
26    0x10   pub sve_vl: u8,
27    0x18   pub num_bps: u8,
28    0x20   pub num_wps: u8,
29    0x28   pub pmu_num_ctrs: u8,
30    0x30   pub hash_algo: u8,
31    0x400  pub rpv: [u8; 64],
32    0x800  pub vmid: u16,
33    0x808  pub rtt_base: u64,
34    0x810  pub rtt_level_start: i64,
35    0x818  pub rtt_num_start: u32,
36    0x1000 => @END,
37}
38);
39
40const_assert_eq!(core::mem::size_of::<Params>(), GRANULE_SIZE);
41const SUPPORTED: u64 = 1;
42
43impl core::fmt::Debug for Params {
44    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45        f.debug_struct("Params")
46            .field(
47                "flags",
48                &format_args!(
49                    "lpa2: {:?} sve: {:?} pmu: {:?}",
50                    RmiRealmFlags::new(self.flags).get_masked_value(RmiRealmFlags::Lpa2),
51                    RmiRealmFlags::new(self.flags).get_masked_value(RmiRealmFlags::Sve),
52                    RmiRealmFlags::new(self.flags).get_masked_value(RmiRealmFlags::Pmu)
53                ),
54            )
55            .field("s2sz", &self.s2sz)
56            .field("sve_vl", &self.sve_vl)
57            .field("num_bps", &self.num_bps)
58            .field("num_wps", &self.num_wps)
59            .field("pmu_num_ctrs", &self.pmu_num_ctrs)
60            .field("hash_algo", &self.hash_algo)
61            .field("rpv", &self.rpv)
62            .field("vmid", &self.vmid)
63            .field("rtt_base", &format_args!("{:#X}", &self.rtt_base))
64            .field("rtt_level_start", &self.rtt_level_start)
65            .field("rtt_num_start", &self.rtt_num_start)
66            .finish()
67    }
68}
69
70impl Hashable for Params {
71    fn hash(
72        &self,
73        hasher: &crate::measurement::Hasher,
74        out: &mut [u8],
75    ) -> Result<(), crate::measurement::MeasurementError> {
76        hasher.hash_fields_into(out, |alg| {
77            alg.hash_u64(self.flags);
78            alg.hash(self._padflags);
79            alg.hash_u8(self.s2sz);
80            alg.hash(self._pads2sz);
81            alg.hash_u8(self.sve_vl);
82            alg.hash(self._padsve_vl);
83            alg.hash_u8(self.num_bps);
84            alg.hash(self._padnum_bps);
85            alg.hash_u8(self.num_wps);
86            alg.hash(self._padnum_wps);
87            alg.hash_u8(self.pmu_num_ctrs);
88            alg.hash(self._padpmu_num_ctrs);
89            alg.hash_u8(self.hash_algo);
90            alg.hash(self._padhash_algo);
91            alg.hash([0u8; 64]); // rpv is not used
92            alg.hash(self._padrpv);
93            alg.hash_u16(0); // vmid is not used
94            alg.hash(self._padvmid);
95            alg.hash_u64(0); // rtt_base is not used
96            alg.hash(self._padrtt_base);
97            alg.hash_u64(0); // rtt_level_start is not used
98            alg.hash(self._padrtt_level_start);
99            alg.hash_u32(0); // rtt_num_start is not used
100            alg.hash(self._padrtt_num_start);
101        })
102    }
103}
104
105impl Params {
106    pub fn ipa_bits(&self) -> usize {
107        self.s2sz as usize
108    }
109
110    pub fn sve_en(&self) -> bool {
111        let flags = RmiRealmFlags::new(self.flags);
112        flags.get_masked_value(RmiRealmFlags::Sve) == SUPPORTED
113    }
114
115    pub fn pmu_en(&self) -> bool {
116        let flags = RmiRealmFlags::new(self.flags);
117        flags.get_masked_value(RmiRealmFlags::Pmu) == SUPPORTED
118    }
119
120    pub fn verify_compliance(&self, rd: usize) -> Result<(), Error> {
121        trace!("{:?}", self);
122        if self.rtt_base as usize == rd {
123            return Err(Error::RmiErrorInput);
124        }
125
126        if !(self.rtt_base as usize).is_multiple_of(GRANULE_SIZE) {
127            return Err(Error::RmiErrorInput);
128        }
129
130        if !features::validate(self.s2sz as usize) {
131            return Err(Error::RmiErrorInput);
132        }
133
134        // Check misconfigurations between IPA size and SL
135        let ipa_bits = self.ipa_bits();
136        let rtt_slvl = self.rtt_level_start as usize;
137
138        let level = RTT_PAGE_LEVEL
139            .checked_sub(rtt_slvl)
140            .ok_or(Error::RmiErrorInput)?;
141        let min_ipa_bits = level * RTT_STRIDE + GRANULE_SHIFT + 1;
142        let max_ipa_bits = min_ipa_bits + (RTT_STRIDE - 1) + 4;
143        let sl_ipa_bits = (level * RTT_STRIDE) + GRANULE_SHIFT + RTT_STRIDE;
144
145        if (ipa_bits < min_ipa_bits) || (ipa_bits > max_ipa_bits) {
146            return Err(Error::RmiErrorInput);
147        }
148
149        let s2_num_root_rtts = {
150            if sl_ipa_bits >= ipa_bits {
151                1
152            } else {
153                1 << (ipa_bits - sl_ipa_bits)
154            }
155        };
156        if s2_num_root_rtts != self.rtt_num_start {
157            return Err(Error::RmiErrorInput);
158        }
159
160        // TODO: We don't support pmu, lpa2
161        let flags = RmiRealmFlags::new(self.flags);
162        if flags.get_masked_value(RmiRealmFlags::Lpa2) != features::LPA2_VALUE {
163            return Err(Error::RmiErrorInput);
164        }
165        if !simd::validate(self.sve_en(), self.sve_vl as u64) {
166            return Err(Error::RmiErrorInput);
167        }
168        if self.pmu_en()
169            && (!pmu::pmu_present()
170                || self.pmu_num_ctrs > pmu::pmu_num_ctrs() as u8
171                || (self.pmu_num_ctrs == 0 && !pmu::hpmn0_present()))
172        {
173            return Err(Error::RmiErrorInput);
174        }
175
176        match self.hash_algo {
177            HASH_ALGO_SHA256 | HASH_ALGO_SHA512 => Ok(()),
178            _ => Err(Error::RmiErrorInput),
179        }
180    }
181}
182
183impl safe_abstraction::raw_ptr::RawPtr for Params {}
184
185impl safe_abstraction::raw_ptr::SafetyChecked for Params {}
186
187impl safe_abstraction::raw_ptr::SafetyAssured for Params {
188    fn is_initialized(&self) -> bool {
189        // Given the fact that this memory is initialized by the Host,
190        // it's not possible to unequivocally guarantee
191        // that the values have been initialized from the perspective of the RMM.
192        // However, any values, whether correctly initialized or not, will undergo
193        // verification during the Measurement phase.
194        // Consequently, this function returns `true`.
195        true
196    }
197
198    fn verify_ownership(&self) -> bool {
199        // This memory has permissions from the Host's perspective,
200        // which inherently implies that exclusive ownership cannot be guaranteed by the RMM alone.
201        // However, since the RMM only performs read operations and any incorrect values will be
202        // verified during the Measurement phase.
203        // Consequently, this function returns `true`.
204        true
205    }
206}