1pub mod attestation;
2pub mod constraint;
3pub mod error;
4pub mod hostcall;
5pub mod measurement;
6pub mod psci;
7pub mod ripas;
8pub mod sealing;
9pub mod version;
10
11use alloc::vec::Vec;
12
13use crate::define_interface;
14use crate::event::RsiHandle;
15use crate::granule::{GranuleState, GRANULE_SIZE};
16use crate::listen;
17use crate::measurement::{HashContext, Measurement, MEASUREMENTS_SLOT_NR, MEASUREMENTS_SLOT_RIM};
18use crate::realm::config::realm_config;
19use crate::realm::mm::address::GuestPhysAddr;
20use crate::realm::mm::rtt::RTT_PAGE_LEVEL;
21use crate::realm::rd::Rd;
22use crate::rec::context::{get_reg, set_reg};
23use crate::rec::{Rec, RmmRecAttestState};
24use crate::rmi;
25use crate::rmi::error::Error;
26use crate::rmi::rec::run::Run;
27use crate::rmi::rtt::validate_ipa;
28use crate::rsi::hostcall::{HostCall, HOST_CALL_NR_GPRS};
29use crate::rsi::ripas::{get_ripas_state, set_ripas_state};
30use crate::rsi::sealing::{realm_sealing_key, SEALING_KEY_SIZE};
31use crate::Monitor;
32use crate::{get_granule, get_granule_if};
33
34use safe_abstraction::raw_ptr::assume_safe;
35
36define_interface! {
37 command {
38 ABI_VERSION = 0xc400_0190,
39 FEATURES = 0xc400_0191,
40 MEASUREMENT_READ = 0xc400_0192,
41 MEASUREMENT_EXTEND = 0xc400_0193,
42 ATTEST_TOKEN_INIT = 0xc400_0194,
43 ATTEST_TOKEN_CONTINUE = 0xc400_0195,
44 REALM_CONFIG = 0xc400_0196,
45 IPA_STATE_SET = 0xc400_0197,
46 IPA_STATE_GET = 0xc400_0198,
47 HOST_CALL = 0xc400_0199,
48 SMCCC_VERSION = 0x8000_0000,
51 PSCI_VERSION = 0x8400_0000,
52 PSCI_CPU_SUSPEND = 0xC400_0001,
53 PSCI_CPU_OFF = 0x8400_0002,
54 PSCI_CPU_ON = 0xC400_0003,
55 PSCI_AFFINITY_INFO = 0xC400_0004,
56 PSCI_SYSTEM_OFF = 0x8400_0008,
57 PSCI_SYSTEM_RESET = 0x8400_0009,
58 PSCI_FEATURES = 0x8400_000A,
59 ISLET_REALM_SEALING_KEY = 0xC700_0191,
61 }
62}
63
64pub const SUCCESS: usize = 0;
65pub const ERROR_INPUT: usize = 1;
66pub const ERROR_STATE: usize = 2;
67pub const INCOMPLETE: usize = 3;
68
69pub const ABI_VERSION_MAJOR: usize = 1;
70pub const ABI_VERSION_MINOR: usize = 0;
71
72extern crate alloc;
73
74pub fn do_host_call(
75 _arg: &[usize],
76 ret: &mut [usize],
77 _rmm: &Monitor,
78 rec: &mut Rec<'_>,
79 run: &mut Run,
80) -> core::result::Result<(), Error> {
81 let rd_granule = get_granule_if!(rec.owner()?, GranuleState::RD)?;
82 let rd = rd_granule.content::<Rd>()?;
83
84 let ipa = get_reg(rec, 1).unwrap_or(0x0);
85
86 let struct_size = core::mem::size_of::<HostCall>();
87 if !ipa.is_multiple_of(struct_size)
88 || !rd.addr_in_par(ipa)
89 || ipa / GRANULE_SIZE != (ipa + struct_size - 1) / GRANULE_SIZE
90 {
91 set_reg(rec, 0, ERROR_INPUT)?;
92 ret[0] = rmi::SUCCESS_REC_ENTER;
93 return Ok(());
94 }
95
96 let pa = rd
97 .s2_table()
98 .lock()
99 .ipa_to_pa(
100 crate::realm::mm::address::GuestPhysAddr::from(ipa),
101 RTT_PAGE_LEVEL,
102 )
103 .ok_or(Error::RmiErrorInput)?;
104
105 let host_call_ptr: usize = pa.as_usize() + ipa % crate::config::PAGE_SIZE;
107 let mut host_call = assume_safe::<HostCall>(host_call_ptr)?;
108 let imm = host_call.imm();
109
110 if rec.host_call_pending() {
111 for i in 0..HOST_CALL_NR_GPRS {
112 let val = run.entry_gpr(i)?;
113 host_call.set_gpr(i, val)?
114 }
115 set_reg(rec, 0, SUCCESS)?;
116 rec.set_host_call_pending(false);
117 } else {
118 for i in 0..HOST_CALL_NR_GPRS {
119 let val = host_call.gpr(i)?;
120 run.set_gpr(i, val)?
121 }
122 run.set_imm(imm);
123 run.set_exit_reason(rmi::EXIT_HOST_CALL);
124 rec.set_host_call_pending(true);
125 }
126
127 trace!("HOST_CALL param: {:#X?}", *host_call);
128
129 ret[0] = rmi::SUCCESS;
130 Ok(())
131}
132
133fn get_token_part(
134 rd: &Rd,
135 context: &mut Rec<'_>,
136 size: usize,
137) -> core::result::Result<(Vec<u8>, usize), Error> {
138 let hash_algo = rd.hash_algo();
139 let measurements = rd.measurements;
140
141 let token = crate::rsi::attestation::get_token(
143 context.attest_challenge(),
144 &measurements,
145 rd.personalization_value(),
146 hash_algo,
147 );
148
149 let offset = context.attest_token_offset();
150 let part_size = core::cmp::min(size, token.len() - offset);
151 let part_end = offset + part_size;
152
153 context.set_attest_offset(part_end);
154
155 Ok((token[offset..part_end].to_vec(), token.len() - part_end))
156}
157
158pub fn set_event_handler(rsi: &mut RsiHandle) {
159 listen!(rsi, ATTEST_TOKEN_INIT, |_arg, ret, _rmm, rec, _| {
160 let mut challenge: [u8; 64] = [0; 64];
161
162 for i in 0..8 {
163 let challenge_part = get_reg(rec, i + 1)?;
164 let start_idx = i * 8;
165 let end_idx = start_idx + 8;
166 challenge[start_idx..end_idx].copy_from_slice(&challenge_part.to_le_bytes());
167 }
168
169 rec.set_attest_challenge(&challenge);
170 rec.set_attest_state(RmmRecAttestState::AttestInProgress);
171 rec.set_attest_offset(0);
172
173 set_reg(rec, 0, SUCCESS)?;
174 set_reg(rec, 1, attestation::MAX_CCA_TOKEN_SIZE)?;
175
176 ret[0] = rmi::SUCCESS_REC_ENTER;
177 Ok(())
178 });
179
180 listen!(rsi, ATTEST_TOKEN_CONTINUE, |_arg, ret, _rmm, rec, _| {
181 let rd_granule = get_granule_if!(rec.owner()?, GranuleState::RD)?;
182 let rd = rd_granule.content::<Rd>()?;
183
184 if rec.attest_state() != RmmRecAttestState::AttestInProgress {
185 warn!("Calling attest token continue without init");
186 set_reg(rec, 0, ERROR_STATE)?;
187 ret[0] = rmi::SUCCESS_REC_ENTER;
188 return Ok(());
189 }
190
191 let attest_ipa = get_reg(rec, 1)?;
192 if validate_ipa(&rd, attest_ipa).is_err() {
193 warn!("Wrong ipa passed {}", attest_ipa);
194 set_reg(rec, 0, ERROR_INPUT)?;
195 ret[0] = rmi::SUCCESS_REC_ENTER;
196 return Ok(());
197 }
198
199 let attest_pa: usize = rd
200 .s2_table()
201 .lock()
202 .ipa_to_pa(GuestPhysAddr::from(attest_ipa), RTT_PAGE_LEVEL)
203 .ok_or(Error::RmiErrorInput)?
204 .into();
205
206 let pa_offset = get_reg(rec, 2)?;
207 let buffer_size = get_reg(rec, 3)?;
208
209 let (_, overflowed) = pa_offset.overflowing_add(buffer_size);
210 if overflowed || pa_offset + buffer_size > GRANULE_SIZE {
211 warn!("Buffer addres region invalid");
212 set_reg(rec, 0, ERROR_INPUT)?;
213 ret[0] = rmi::SUCCESS_REC_ENTER;
214 return Ok(());
215 }
216
217 #[cfg(not(kani))]
218 {
220 let (token_part, token_left) = get_token_part(&rd, rec, buffer_size)?;
221
222 unsafe {
223 let pa_ptr = attest_pa as *mut u8;
224 core::ptr::copy(token_part.as_ptr(), pa_ptr.add(pa_offset), token_part.len());
225 }
226
227 if token_left == 0 {
228 set_reg(rec, 0, SUCCESS)?;
229 rec.set_attest_state(RmmRecAttestState::NoAttestInProgress);
230 } else {
231 set_reg(rec, 0, INCOMPLETE)?;
232 }
233
234 set_reg(rec, 1, token_part.len())?;
235 }
236
237 ret[0] = rmi::SUCCESS_REC_ENTER;
238 Ok(())
239 });
240
241 listen!(rsi, FEATURES, |_arg, ret, _rmm, rec, _| {
242 let _index = get_reg(rec, 1);
243
244 set_reg(rec, 0, SUCCESS)?;
245
246 set_reg(rec, 1, 0)?;
250
251 ret[0] = rmi::SUCCESS_REC_ENTER;
252 Ok(())
253 });
254
255 listen!(rsi, HOST_CALL, do_host_call);
256
257 listen!(rsi, ABI_VERSION, |_arg, ret, _rmm, rec, _| {
258 let req = get_reg(rec, 1)?;
259
260 let (req_major, req_minor) = version::decode_version(req);
261
262 if req_major != ABI_VERSION_MAJOR || req_minor != ABI_VERSION_MINOR {
263 warn!(
264 "Wrong unsupported version requested ({}, {})",
265 req_major, req_minor
266 );
267 set_reg(rec, 0, ERROR_INPUT)?;
268 ret[0] = rmi::SUCCESS_REC_ENTER;
269 return Ok(());
270 }
271
272 let lower = version::encode_version();
273 let higher = lower;
274
275 set_reg(rec, 0, SUCCESS)?;
276 set_reg(rec, 1, lower)?;
277 set_reg(rec, 2, higher)?;
278
279 trace!("RSI_ABI_VERSION: {:#X?} {:#X?}", lower, higher);
280 ret[0] = rmi::SUCCESS_REC_ENTER;
281 Ok(())
282 });
283
284 listen!(rsi, MEASUREMENT_READ, |_arg, ret, _rmm, rec, _| {
285 let rd_granule = get_granule_if!(rec.owner()?, GranuleState::RD)?;
286 let rd = rd_granule.content::<Rd>()?;
287 let mut measurement = Measurement::empty();
288 let index = get_reg(rec, 1)?;
289
290 if index >= MEASUREMENTS_SLOT_NR {
291 warn!("Wrong index passed: {}", index);
292 set_reg(rec, 0, ERROR_INPUT)?;
293 ret[0] = rmi::SUCCESS_REC_ENTER;
294 return Ok(());
295 }
296
297 #[cfg(not(kani))]
298 crate::rsi::measurement::read(&rd, index, &mut measurement)?;
300 set_reg(rec, 0, SUCCESS)?;
301 for (ind, chunk) in measurement
302 .as_slice()
303 .chunks_exact(core::mem::size_of::<usize>())
304 .enumerate()
305 {
306 let reg_value = usize::from_le_bytes(chunk.try_into().unwrap());
307 set_reg(rec, ind + 1, reg_value)?;
308 }
309
310 ret[0] = rmi::SUCCESS_REC_ENTER;
311 Ok(())
312 });
313
314 listen!(rsi, MEASUREMENT_EXTEND, |_arg, ret, _rmm, rec, _| {
315 let mut rd_granule = get_granule_if!(rec.owner()?, GranuleState::RD)?;
316 let mut rd = rd_granule.content_mut::<Rd>()?;
317
318 let index = get_reg(rec, 1)?;
319 let size = get_reg(rec, 2)?;
320 let mut buffer = [0u8; 64];
321
322 for i in 0..8 {
323 buffer[i * 8..i * 8 + 8].copy_from_slice(get_reg(rec, i + 3)?.to_le_bytes().as_slice());
324 }
325
326 if size > buffer.len() || index == MEASUREMENTS_SLOT_RIM || index >= MEASUREMENTS_SLOT_NR {
327 warn!(
328 "Wrong index or buffer size passed: idx: {}, size: {}",
329 index, size
330 );
331 set_reg(rec, 0, ERROR_INPUT)?;
332 ret[0] = rmi::SUCCESS_REC_ENTER;
333 return Ok(());
334 }
335
336 #[cfg(not(kani))]
337 HashContext::new(&mut rd)?.extend_measurement(&buffer[0..size], index)?;
339
340 set_reg(rec, 0, SUCCESS)?;
341 ret[0] = rmi::SUCCESS_REC_ENTER;
342 Ok(())
343 });
344
345 listen!(rsi, REALM_CONFIG, |_arg, ret, _rmm, rec, _| {
346 let ipa_bits = rec.ipa_bits()?;
347 let rd_granule = get_granule_if!(rec.owner()?, GranuleState::RD)?;
348 let rd = rd_granule.content::<Rd>()?;
349
350 let config_ipa = get_reg(rec, 1)?;
351 if validate_ipa(&rd, config_ipa).is_err() {
352 set_reg(rec, 0, ERROR_INPUT)?;
353 ret[0] = rmi::SUCCESS_REC_ENTER;
354 return Ok(());
355 }
356
357 realm_config(&rd, config_ipa, ipa_bits)?;
358
359 if set_reg(rec, 0, SUCCESS).is_err() {
360 warn!("Unable to set register 0. rec: {:?}", rec);
361 }
362 ret[0] = rmi::SUCCESS_REC_ENTER;
363 Ok(())
364 });
365
366 listen!(rsi, IPA_STATE_GET, get_ripas_state);
367 listen!(rsi, IPA_STATE_SET, set_ripas_state);
368
369 listen!(rsi, ISLET_REALM_SEALING_KEY, |_arg, ret, _rmm, rec, _| {
381 let flags = get_reg(rec, 1)?;
382 let svn = get_reg(rec, 2)?;
383 let mut buf = [0u8; SEALING_KEY_SIZE];
384
385 let rd_granule = get_granule_if!(rec.owner()?, GranuleState::RD)?;
386 let rd = rd_granule.content::<Rd>()?;
387
388 if realm_sealing_key(&rd, flags, svn, &mut buf).is_err() {
389 set_reg(rec, 0, ERROR_INPUT)?;
390 ret[0] = rmi::SUCCESS_REC_ENTER;
391 return Ok(());
392 }
393
394 for (ind, chunk) in buf.chunks_exact(core::mem::size_of::<usize>()).enumerate() {
395 let reg_value = usize::from_ne_bytes(chunk.try_into().unwrap());
396 set_reg(rec, ind + 1, reg_value)?;
397 }
398
399 unsafe {
402 core::ptr::write_bytes(buf.as_mut_ptr(), 0x0, SEALING_KEY_SIZE);
403 }
404
405 set_reg(rec, 0, SUCCESS)?;
406 ret[0] = rmi::SUCCESS_REC_ENTER;
407 Ok(())
408 });
409}