blob: f9699aaea64ada8fb232d7440457b729ded39aa3 [file] [log] [blame]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![cfg_attr(not(test), no_std)]
5
6extern crate alloc;
7
Andrew Walbran19970ba2024-11-25 15:35:00 +00008use core::fmt::{self, Debug, Display, Formatter};
Andrew Walbran44029a02024-11-25 15:34:31 +00009use num_enum::{IntoPrimitive, TryFromPrimitive};
10use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020011use uuid::Uuid;
12
13pub mod boot_info;
14pub mod memory_management;
15pub mod partition_info;
16
17pub const FFA_PAGE_SIZE: usize = 4096;
18
19#[derive(PartialEq, Clone, Copy)]
20pub enum Instance {
21 SecurePhysical,
22 SecureVirtual(u16),
23}
24
25/// FF-A v1.1, Table 12.2: Error status codes
Andrew Walbran44029a02024-11-25 15:34:31 +000026#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020027#[repr(i32)]
28pub enum Error {
Andrew Walbran44029a02024-11-25 15:34:31 +000029 #[error("Not supported")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020030 NotSupported = -1,
Andrew Walbran44029a02024-11-25 15:34:31 +000031 #[error("Invalid parameters")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020032 InvalidParameters = -2,
Andrew Walbran44029a02024-11-25 15:34:31 +000033 #[error("No memory")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020034 NoMemory = -3,
Andrew Walbran44029a02024-11-25 15:34:31 +000035 #[error("Busy")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020036 Busy = -4,
Andrew Walbran44029a02024-11-25 15:34:31 +000037 #[error("Interrupted")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020038 Interrupted = -5,
Andrew Walbran44029a02024-11-25 15:34:31 +000039 #[error("Denied")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020040 Denied = -6,
Andrew Walbran44029a02024-11-25 15:34:31 +000041 #[error("Retry")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020042 Retry = -7,
Andrew Walbran44029a02024-11-25 15:34:31 +000043 #[error("Aborted")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020044 Aborted = -8,
Andrew Walbran44029a02024-11-25 15:34:31 +000045 #[error("No data")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020046 NoData = -9,
47}
48
Andrew Walbran1e1aef12024-11-25 16:17:32 +000049/// An integer couldn't be converted to a [`FuncId`] because it is not a recognised function.
50#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
51#[error("Unrecognised function ID {0} for FF-A")]
52pub struct UnrecognisedFunctionIdError(u32);
53
Balint Dobszay5bf492f2024-07-29 17:21:32 +020054/// FF-A v1.1: Function IDs
Andrew Walbran969b9252024-11-25 15:35:42 +000055#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Andrew Walbran1e1aef12024-11-25 16:17:32 +000056#[num_enum(error_type(name = UnrecognisedFunctionIdError, constructor = UnrecognisedFunctionIdError))]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020057#[repr(u32)]
58pub enum FuncId {
59 Error = 0x84000060,
60 Success32 = 0x84000061,
61 Success64 = 0xc4000061,
62 Interrupt = 0x84000062,
63 Version = 0x84000063,
64 Features = 0x84000064,
65 RxAcquire = 0x84000084,
66 RxRelease = 0x84000065,
67 RxTxMap32 = 0x84000066,
68 RxTxMap64 = 0xc4000066,
69 RxTxUnmap = 0x84000067,
70 PartitionInfoGet = 0x84000068,
71 IdGet = 0x84000069,
72 SpmIdGet = 0x84000085,
73 MsgWait = 0x8400006b,
74 Yield = 0x8400006c,
75 Run = 0x8400006d,
76 NormalWorldResume = 0x8400007c,
77 MsgSend2 = 0x84000086,
78 MsgSendDirectReq32 = 0x8400006f,
79 MsgSendDirectReq64 = 0xc400006f,
80 MsgSendDirectResp32 = 0x84000070,
81 MsgSendDirectResp64 = 0xc4000070,
82 MemDonate32 = 0x84000071,
83 MemDonate64 = 0xc4000071,
84 MemLend32 = 0x84000072,
85 MemLend64 = 0xc4000072,
86 MemShare32 = 0x84000073,
87 MemShare64 = 0xc4000073,
88 MemRetrieveReq32 = 0x84000074,
89 MemRetrieveReq64 = 0xc4000074,
90 MemRetrieveResp = 0x84000075,
91 MemRelinquish = 0x84000076,
92 MemReclaim = 0x84000077,
93 MemPermGet32 = 0x84000088,
94 MemPermGet64 = 0xc4000088,
95 MemPermSet32 = 0x84000089,
96 MemPermSet64 = 0xc4000089,
97 ConsoleLog32 = 0x8400008a,
98 ConsoleLog64 = 0xc400008a,
99}
100
101#[derive(Debug, Eq, PartialEq, Clone, Copy)]
102pub enum Interface {
103 Error {
104 target_info: u32,
105 error_code: Error,
106 },
107 Success {
108 target_info: u32,
109 result_regs: [u64; 6],
110 is_32bit: bool,
111 },
112 Interrupt {
113 endpoint_id: u32,
114 interrupt_id: u32,
115 },
116 Version {
117 input_version: u32,
118 },
119 VersionOut {
120 output_version: u32,
121 },
122 Features {
123 feat_id: u32,
124 input_properties: u32,
125 },
126 RxAcquire {
127 vm_id: u32,
128 },
129 RxRelease {
130 vm_id: u32,
131 },
132 RxTxMap {
133 tx_addr: u64,
134 rx_addr: u64,
135 page_cnt: u32,
136 is_32bit: bool,
137 },
138 RxTxUnmap {
139 id: u32,
140 },
141 PartitionInfoGet {
142 uuid: Uuid,
143 flags: u32,
144 },
145 IdGet,
146 SpmIdGet,
147 MsgWait,
148 Yield,
149 Run {
150 target_info: u32,
151 },
152 NormalWorldResume,
153 MsgSend2 {
154 sender_vm_id: u32,
155 flags: u32,
156 },
157 MsgSendDirectReq {
158 src_id: u16,
159 dst_id: u16,
160 flags: u32,
161 args: [u64; 5],
162 is_32bit: bool,
163 },
164 MsgSendDirectResp {
165 src_id: u16,
166 dst_id: u16,
167 flags: u32,
168 args: [u64; 5],
169 is_32bit: bool,
170 },
171 MemDonate {
172 total_len: u32,
173 frag_len: u32,
174 address: u64,
175 page_cnt: u32,
176 is_32bit: bool,
177 },
178 MemLend {
179 total_len: u32,
180 frag_len: u32,
181 address: u64,
182 page_cnt: u32,
183 is_32bit: bool,
184 },
185 MemShare {
186 total_len: u32,
187 frag_len: u32,
188 address: u64,
189 page_cnt: u32,
190 is_32bit: bool,
191 },
192 MemRetrieveReq {
193 total_len: u32,
194 frag_len: u32,
195 address: u64,
196 page_cnt: u32,
197 is_32bit: bool,
198 },
199 MemRetrieveResp {
200 total_len: u32,
201 frag_len: u32,
202 },
203 MemRelinquish,
204 MemReclaim {
205 handle: memory_management::Handle,
206 flags: u32,
207 },
208 MemPermGet {
209 base_addr: u64,
210 is_32bit: bool,
211 },
212 MemPermSet {
213 base_addr: u64,
214 page_cnt: u32,
215 mem_perm: u32,
216 is_32bit: bool,
217 },
218 ConsoleLog {
219 char_cnt: u32,
220 char_lists: [u64; 6],
221 is_32bit: bool,
222 },
223}
224
225impl TryFrom<[u64; 8]> for Interface {
Andrew Walbran1e1aef12024-11-25 16:17:32 +0000226 type Error = UnrecognisedFunctionIdError;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200227
Andrew Walbran1e1aef12024-11-25 16:17:32 +0000228 fn try_from(regs: [u64; 8]) -> Result<Self, UnrecognisedFunctionIdError> {
229 let fid = FuncId::try_from(regs[0] as u32)?;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200230
231 let msg = match fid {
232 FuncId::Error => Self::Error {
233 target_info: regs[1] as u32,
234 error_code: Error::try_from(regs[2] as i32).unwrap(),
235 },
236 FuncId::Success32 | FuncId::Success64 => {
237 let target_info = regs[1] as u32;
238 let mut result_regs = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
239 let mut is_32bit = false;
240
241 if fid == FuncId::Success32 {
242 result_regs[0] &= u32::MAX as u64;
243 result_regs[1] &= u32::MAX as u64;
244 result_regs[2] &= u32::MAX as u64;
245 result_regs[3] &= u32::MAX as u64;
246 result_regs[4] &= u32::MAX as u64;
247 result_regs[5] &= u32::MAX as u64;
248 is_32bit = true;
249 }
250
251 Self::Success {
252 target_info,
253 result_regs,
254 is_32bit,
255 }
256 }
257 FuncId::Interrupt => Self::Interrupt {
258 endpoint_id: regs[1] as u32,
259 interrupt_id: regs[2] as u32,
260 },
261 FuncId::Version => Self::Version {
262 input_version: regs[1] as u32,
263 },
264 FuncId::Features => Self::Features {
265 feat_id: regs[1] as u32,
266 input_properties: regs[2] as u32,
267 },
268 FuncId::RxAcquire => Self::RxAcquire {
269 vm_id: regs[1] as u32,
270 },
271 FuncId::RxRelease => Self::RxRelease {
272 vm_id: regs[1] as u32,
273 },
274 FuncId::RxTxMap32 | FuncId::RxTxMap64 => {
275 let mut tx_addr = regs[1];
276 let mut rx_addr = regs[2];
277 let page_cnt = regs[3] as u32;
278 let mut is_32bit = false;
279
280 if fid == FuncId::RxTxMap32 {
281 tx_addr &= u32::MAX as u64;
282 rx_addr &= u32::MAX as u64;
283 is_32bit = true;
284 }
285
286 Self::RxTxMap {
287 tx_addr,
288 rx_addr,
289 page_cnt,
290 is_32bit,
291 }
292 }
293 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u32 },
294 FuncId::PartitionInfoGet => {
295 let uuid_words = [
296 regs[1] as u32,
297 regs[2] as u32,
298 regs[3] as u32,
299 regs[4] as u32,
300 ];
301 let mut bytes: [u8; 16] = [0; 16];
302 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
303 bytes[i] = b;
304 }
305 Self::PartitionInfoGet {
306 uuid: Uuid::from_bytes(bytes),
307 flags: regs[5] as u32,
308 }
309 }
310 FuncId::IdGet => Self::IdGet,
311 FuncId::SpmIdGet => Self::SpmIdGet,
312 FuncId::MsgWait => Self::MsgWait,
313 FuncId::Yield => Self::Yield,
314 FuncId::Run => Self::Run {
315 target_info: regs[1] as u32,
316 },
317 FuncId::NormalWorldResume => Self::NormalWorldResume,
318 FuncId::MsgSend2 => Self::MsgSend2 {
319 sender_vm_id: regs[1] as u32,
320 flags: regs[2] as u32,
321 },
322 FuncId::MsgSendDirectReq32 | FuncId::MsgSendDirectReq64 => {
323 let src_id = (regs[1] >> 16) as u16;
324 let dst_id = regs[1] as u16;
325 let flags = regs[2] as u32;
326 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
327 let mut is_32bit = false;
328
329 if fid == FuncId::MsgSendDirectReq32 {
330 args[0] &= u32::MAX as u64;
331 args[1] &= u32::MAX as u64;
332 args[2] &= u32::MAX as u64;
333 args[3] &= u32::MAX as u64;
334 args[4] &= u32::MAX as u64;
335 is_32bit = true;
336 }
337
338 Self::MsgSendDirectReq {
339 src_id,
340 dst_id,
341 flags,
342 args,
343 is_32bit,
344 }
345 }
346 FuncId::MsgSendDirectResp32 | FuncId::MsgSendDirectResp64 => {
347 let src_id = (regs[1] >> 16) as u16;
348 let dst_id = regs[1] as u16;
349 let flags = regs[2] as u32;
350 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
351 let mut is_32bit = false;
352
353 if fid == FuncId::MsgSendDirectResp32 {
354 args[0] &= u32::MAX as u64;
355 args[1] &= u32::MAX as u64;
356 args[2] &= u32::MAX as u64;
357 args[3] &= u32::MAX as u64;
358 args[4] &= u32::MAX as u64;
359 is_32bit = true;
360 }
361
362 Self::MsgSendDirectResp {
363 src_id,
364 dst_id,
365 flags,
366 args,
367 is_32bit,
368 }
369 }
370 FuncId::MemDonate32 | FuncId::MemDonate64 => {
371 let total_len = regs[1] as u32;
372 let frag_len = regs[2] as u32;
373 let mut address = regs[3];
374 let page_cnt = regs[4] as u32;
375 let mut is_32bit = false;
376
377 if fid == FuncId::MemDonate32 {
378 address &= u32::MAX as u64;
379 is_32bit = true;
380 }
381
382 Self::MemDonate {
383 total_len,
384 frag_len,
385 address,
386 page_cnt,
387 is_32bit,
388 }
389 }
390 FuncId::MemLend32 | FuncId::MemLend64 => {
391 let total_len = regs[1] as u32;
392 let frag_len = regs[2] as u32;
393 let mut address = regs[3];
394 let page_cnt = regs[4] as u32;
395 let mut is_32bit = false;
396
397 if fid == FuncId::MemLend32 {
398 address &= u32::MAX as u64;
399 is_32bit = true;
400 }
401
402 Self::MemLend {
403 total_len,
404 frag_len,
405 address,
406 page_cnt,
407 is_32bit,
408 }
409 }
410 FuncId::MemShare32 | FuncId::MemShare64 => {
411 let total_len = regs[1] as u32;
412 let frag_len = regs[2] as u32;
413 let mut address = regs[3];
414 let page_cnt = regs[4] as u32;
415 let mut is_32bit = false;
416
417 if fid == FuncId::MemShare32 {
418 address &= u32::MAX as u64;
419 is_32bit = true;
420 }
421
422 Self::MemShare {
423 total_len,
424 frag_len,
425 address,
426 page_cnt,
427 is_32bit,
428 }
429 }
430 FuncId::MemRetrieveReq32 | FuncId::MemRetrieveReq64 => {
431 let total_len = regs[1] as u32;
432 let frag_len = regs[2] as u32;
433 let mut address = regs[3];
434 let page_cnt = regs[4] as u32;
435 let mut is_32bit = false;
436
437 if fid == FuncId::MemRetrieveReq32 {
438 address &= u32::MAX as u64;
439 is_32bit = true;
440 }
441
442 Self::MemRetrieveReq {
443 total_len,
444 frag_len,
445 address,
446 page_cnt,
447 is_32bit,
448 }
449 }
450 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
451 total_len: regs[1] as u32,
452 frag_len: regs[2] as u32,
453 },
454 FuncId::MemRelinquish => Self::MemRelinquish,
455 FuncId::MemReclaim => Self::MemReclaim {
456 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
457 flags: regs[3] as u32,
458 },
459 FuncId::MemPermGet32 | FuncId::MemPermGet64 => {
460 let mut base_addr = regs[1];
461 let mut is_32bit = false;
462
463 if fid == FuncId::MemPermGet32 {
464 base_addr &= u32::MAX as u64;
465 is_32bit = true;
466 }
467
468 Self::MemPermGet {
469 base_addr,
470 is_32bit,
471 }
472 }
473 FuncId::MemPermSet32 | FuncId::MemPermSet64 => {
474 let mut base_addr = regs[1];
475 let page_cnt = regs[2] as u32;
476 let mem_perm = regs[3] as u32;
477 let mut is_32bit = false;
478
479 if fid == FuncId::MemPermSet32 {
480 base_addr &= u32::MAX as u64;
481 is_32bit = true;
482 }
483
484 Self::MemPermSet {
485 base_addr,
486 page_cnt,
487 mem_perm,
488 is_32bit,
489 }
490 }
491 FuncId::ConsoleLog32 | FuncId::ConsoleLog64 => {
492 let char_cnt = regs[1] as u32;
493 let mut char_lists = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
494 let mut is_32bit = false;
495
496 if fid == FuncId::ConsoleLog32 {
497 char_lists[0] &= u32::MAX as u64;
498 char_lists[1] &= u32::MAX as u64;
499 char_lists[2] &= u32::MAX as u64;
500 char_lists[3] &= u32::MAX as u64;
501 char_lists[4] &= u32::MAX as u64;
502 char_lists[5] &= u32::MAX as u64;
503 is_32bit = true;
504 }
505
506 Self::ConsoleLog {
507 char_cnt,
508 char_lists,
509 is_32bit,
510 }
511 }
512 };
513
514 Ok(msg)
515 }
516}
517
518impl Interface {
Andrew Walbran0d315812024-11-25 15:36:36 +0000519 /// Returns the function ID for the call, if it has one.
520 pub fn function_id(&self) -> Option<FuncId> {
521 match self {
522 Interface::Error { .. } => Some(FuncId::Error),
523 Interface::Success {
524 is_32bit: false, ..
525 } => Some(FuncId::Success64),
526 Interface::Success { is_32bit: true, .. } => Some(FuncId::Success32),
527 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
528 Interface::Version { .. } => Some(FuncId::Version),
529 Interface::VersionOut { .. } => None,
530 Interface::Features { .. } => Some(FuncId::Features),
531 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
532 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
533 Interface::RxTxMap {
534 is_32bit: false, ..
535 } => Some(FuncId::RxTxMap64),
536 Interface::RxTxMap { is_32bit: true, .. } => Some(FuncId::RxTxMap32),
537 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
538 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
539 Interface::IdGet => Some(FuncId::IdGet),
540 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
541 Interface::MsgWait => Some(FuncId::MsgWait),
542 Interface::Yield => Some(FuncId::Yield),
543 Interface::Run { .. } => Some(FuncId::Run),
544 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
545 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
546 Interface::MsgSendDirectReq {
547 is_32bit: false, ..
548 } => Some(FuncId::MsgSendDirectReq64),
549 Interface::MsgSendDirectReq { is_32bit: true, .. } => Some(FuncId::MsgSendDirectReq32),
550 Interface::MsgSendDirectResp {
551 is_32bit: false, ..
552 } => Some(FuncId::MsgSendDirectResp64),
553 Interface::MsgSendDirectResp { is_32bit: true, .. } => {
554 Some(FuncId::MsgSendDirectResp32)
555 }
556 Interface::MemDonate {
557 is_32bit: false, ..
558 } => Some(FuncId::MemDonate64),
559 Interface::MemDonate { is_32bit: true, .. } => Some(FuncId::MemDonate32),
560 Interface::MemLend {
561 is_32bit: false, ..
562 } => Some(FuncId::MemLend64),
563 Interface::MemLend { is_32bit: true, .. } => Some(FuncId::MemLend32),
564 Interface::MemShare {
565 is_32bit: false, ..
566 } => Some(FuncId::MemShare64),
567 Interface::MemShare { is_32bit: true, .. } => Some(FuncId::MemShare32),
568 Interface::MemRetrieveReq {
569 is_32bit: false, ..
570 } => Some(FuncId::MemRetrieveReq64),
571 Interface::MemRetrieveReq { is_32bit: true, .. } => Some(FuncId::MemRetrieveReq32),
572 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
573 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
574 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
575 Interface::MemPermGet {
576 is_32bit: false, ..
577 } => Some(FuncId::MemPermGet64),
578 Interface::MemPermGet { is_32bit: true, .. } => Some(FuncId::MemPermGet32),
579 Interface::MemPermSet {
580 is_32bit: false, ..
581 } => Some(FuncId::MemPermSet64),
582 Interface::MemPermSet { is_32bit: true, .. } => Some(FuncId::MemPermSet32),
583 Interface::ConsoleLog {
584 is_32bit: false, ..
585 } => Some(FuncId::ConsoleLog64),
586 Interface::ConsoleLog { is_32bit: true, .. } => Some(FuncId::ConsoleLog32),
587 }
588 }
589
590 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
591 pub fn is_32bit(&self) -> bool {
592 match self {
593 Interface::Error { .. }
594 | Interface::Interrupt { .. }
595 | Interface::Version { .. }
596 | Interface::VersionOut { .. }
597 | Interface::Features { .. }
598 | Interface::RxAcquire { .. }
599 | Interface::RxRelease { .. }
600 | Interface::RxTxUnmap { .. }
601 | Interface::PartitionInfoGet { .. }
602 | Interface::IdGet
603 | Interface::SpmIdGet
604 | Interface::MsgWait
605 | Interface::Yield
606 | Interface::Run { .. }
607 | Interface::NormalWorldResume
608 | Interface::MsgSend2 { .. }
609 | Interface::MemRetrieveResp { .. }
610 | Interface::MemRelinquish
611 | Interface::MemReclaim { .. } => true,
612 Interface::Success { is_32bit, .. }
613 | Interface::RxTxMap { is_32bit, .. }
614 | Interface::MsgSendDirectReq { is_32bit, .. }
615 | Interface::MsgSendDirectResp { is_32bit, .. }
616 | Interface::MemDonate { is_32bit, .. }
617 | Interface::MemLend { is_32bit, .. }
618 | Interface::MemShare { is_32bit, .. }
619 | Interface::MemRetrieveReq { is_32bit, .. }
620 | Interface::MemPermGet { is_32bit, .. }
621 | Interface::MemPermSet { is_32bit, .. }
622 | Interface::ConsoleLog { is_32bit, .. } => *is_32bit,
623 }
624 }
625
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200626 pub fn copy_to_array(&self, a: &mut [u64; 8]) {
627 a.fill(0);
Andrew Walbran0d315812024-11-25 15:36:36 +0000628 if let Some(function_id) = self.function_id() {
629 a[0] = function_id as u64;
630 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200631
632 match *self {
633 Interface::Error {
634 target_info,
635 error_code,
636 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200637 a[1] = target_info as u64;
638 a[2] = error_code as u32 as u64;
639 }
640 Interface::Success {
641 target_info,
642 result_regs,
643 is_32bit,
644 } => {
645 a[1] = target_info as u64;
646 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200647 a[2] = result_regs[0] & u32::MAX as u64;
648 a[3] = result_regs[1] & u32::MAX as u64;
649 a[4] = result_regs[2] & u32::MAX as u64;
650 a[5] = result_regs[3] & u32::MAX as u64;
651 a[6] = result_regs[4] & u32::MAX as u64;
652 a[7] = result_regs[5] & u32::MAX as u64;
653 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200654 a[2] = result_regs[0];
655 a[3] = result_regs[1];
656 a[4] = result_regs[2];
657 a[5] = result_regs[3];
658 a[6] = result_regs[4];
659 a[7] = result_regs[5];
660 }
661 }
662 Interface::Interrupt {
663 endpoint_id,
664 interrupt_id,
665 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200666 a[1] = endpoint_id as u64;
667 a[2] = interrupt_id as u64;
668 }
669 Interface::Version { input_version } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200670 a[1] = input_version as u64;
671 }
672 Interface::VersionOut { output_version } => {
673 a[0] = output_version as u64;
674 }
675 Interface::Features {
676 feat_id,
677 input_properties,
678 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200679 a[1] = feat_id as u64;
680 a[2] = input_properties as u64;
681 }
682 Interface::RxAcquire { vm_id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200683 a[1] = vm_id as u64;
684 }
685 Interface::RxRelease { vm_id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200686 a[1] = vm_id as u64;
687 }
688 Interface::RxTxMap {
689 tx_addr,
690 rx_addr,
691 page_cnt,
692 is_32bit,
693 } => {
694 a[3] = page_cnt as u64;
695 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200696 a[1] = tx_addr & u32::MAX as u64;
697 a[2] = rx_addr & u32::MAX as u64;
698 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200699 a[1] = tx_addr;
700 a[2] = rx_addr;
701 }
702 }
703 Interface::RxTxUnmap { id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200704 a[1] = id as u64;
705 }
706 Interface::PartitionInfoGet { uuid, flags } => {
707 let bytes = uuid.to_bytes_le();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200708 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as u64;
709 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64;
710 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as u64;
711 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]) as u64;
712 a[5] = flags as u64;
713 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000714 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200715 Interface::Run { target_info } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200716 a[1] = target_info as u64;
717 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000718 Interface::NormalWorldResume => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200719 Interface::MsgSend2 {
720 sender_vm_id,
721 flags,
722 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200723 a[1] = sender_vm_id as u64;
724 a[2] = flags as u64;
725 }
726 Interface::MsgSendDirectReq {
727 src_id,
728 dst_id,
729 flags,
730 args,
731 is_32bit,
732 } => {
733 a[1] = (src_id as u64) << 16 | dst_id as u64;
734 a[2] = flags as u64;
735 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200736 a[3] = args[0] & u32::MAX as u64;
737 a[4] = args[1] & u32::MAX as u64;
738 a[5] = args[2] & u32::MAX as u64;
739 a[6] = args[3] & u32::MAX as u64;
740 a[7] = args[4] & u32::MAX as u64;
741 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200742 a[3] = args[0];
743 a[4] = args[1];
744 a[5] = args[2];
745 a[6] = args[3];
746 a[7] = args[4];
747 }
748 }
749 Interface::MsgSendDirectResp {
750 src_id,
751 dst_id,
752 flags,
753 args,
754 is_32bit,
755 } => {
756 a[1] = (src_id as u64) << 16 | dst_id as u64;
757 a[2] = flags as u64;
758 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200759 a[3] = args[0] & u32::MAX as u64;
760 a[4] = args[1] & u32::MAX as u64;
761 a[5] = args[2] & u32::MAX as u64;
762 a[6] = args[3] & u32::MAX as u64;
763 a[7] = args[4] & u32::MAX as u64;
764 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200765 a[3] = args[0];
766 a[4] = args[1];
767 a[5] = args[2];
768 a[6] = args[3];
769 a[7] = args[4];
770 }
771 }
772 Interface::MemDonate {
773 total_len,
774 frag_len,
775 address,
776 page_cnt,
777 is_32bit,
778 } => {
779 a[1] = total_len as u64;
780 a[2] = frag_len as u64;
781 a[4] = page_cnt as u64;
782 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200783 a[3] = address & u32::MAX as u64;
784 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200785 a[3] = address;
786 }
787 }
788 Interface::MemLend {
789 total_len,
790 frag_len,
791 address,
792 page_cnt,
793 is_32bit,
794 } => {
795 a[1] = total_len as u64;
796 a[2] = frag_len as u64;
797 a[4] = page_cnt as u64;
798 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200799 a[3] = address & u32::MAX as u64;
800 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200801 a[3] = address;
802 }
803 }
804 Interface::MemShare {
805 total_len,
806 frag_len,
807 address,
808 page_cnt,
809 is_32bit,
810 } => {
811 a[1] = total_len as u64;
812 a[2] = frag_len as u64;
813 a[4] = page_cnt as u64;
814 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200815 a[3] = address & u32::MAX as u64;
816 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200817 a[3] = address;
818 }
819 }
820 Interface::MemRetrieveReq {
821 total_len,
822 frag_len,
823 address,
824 page_cnt,
825 is_32bit,
826 } => {
827 a[1] = total_len as u64;
828 a[2] = frag_len as u64;
829 a[4] = page_cnt as u64;
830 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200831 a[3] = address & u32::MAX as u64;
832 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200833 a[3] = address;
834 }
835 }
836 Interface::MemRetrieveResp {
837 total_len,
838 frag_len,
839 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200840 a[1] = total_len as u64;
841 a[2] = frag_len as u64;
842 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000843 Interface::MemRelinquish => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200844 Interface::MemReclaim { handle, flags } => {
845 let handle_regs: [u32; 2] = handle.into();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200846 a[1] = handle_regs[0] as u64;
847 a[2] = handle_regs[1] as u64;
848 a[3] = flags as u64;
849 }
850 Interface::MemPermGet {
851 base_addr,
852 is_32bit,
853 } => {
854 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200855 a[1] = base_addr & u32::MAX as u64;
856 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200857 a[1] = base_addr;
858 }
859 }
860 Interface::MemPermSet {
861 base_addr,
862 page_cnt,
863 mem_perm,
864 is_32bit,
865 } => {
866 a[2] = page_cnt as u64;
867 a[3] = mem_perm as u64;
868
869 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200870 a[1] = base_addr & u32::MAX as u64;
871 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200872 a[1] = base_addr;
873 }
874 }
875 Interface::ConsoleLog {
876 char_cnt,
877 char_lists,
878 is_32bit,
879 } => {
880 a[1] = char_cnt as u64;
881 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200882 a[2] = char_lists[0] & u32::MAX as u64;
883 a[3] = char_lists[1] & u32::MAX as u64;
884 a[4] = char_lists[2] & u32::MAX as u64;
885 a[5] = char_lists[3] & u32::MAX as u64;
886 a[6] = char_lists[4] & u32::MAX as u64;
887 a[7] = char_lists[5] & u32::MAX as u64;
888 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200889 a[2] = char_lists[0];
890 a[3] = char_lists[1];
891 a[4] = char_lists[2];
892 a[5] = char_lists[3];
893 a[6] = char_lists[4];
894 a[7] = char_lists[5];
895 }
896 }
897 }
898 }
899
900 /// Helper function to create an FFA_SUCCESS interface without any arguments
901 pub fn success32_noargs() -> Self {
902 Self::Success {
903 target_info: 0,
904 result_regs: [0, 0, 0, 0, 0, 0],
905 is_32bit: true,
906 }
907 }
908}
909
Andrew Walbran19970ba2024-11-25 15:35:00 +0000910#[derive(Clone, Copy, Eq, PartialEq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200911pub struct Version(pub u16, pub u16);
912
913impl From<u32> for Version {
914 fn from(val: u32) -> Self {
915 Self((val >> 16) as u16, val as u16)
916 }
917}
918
919impl From<Version> for u32 {
920 fn from(v: Version) -> Self {
921 (v.0 as u32) << 16 | v.1 as u32
922 }
923}
924
Andrew Walbran19970ba2024-11-25 15:35:00 +0000925impl Display for Version {
926 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
927 write!(f, "{}.{}", self.0, self.1)
928 }
929}
930
931impl Debug for Version {
932 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
933 Display::fmt(self, f)
934 }
935}
936
Balint Dobszayc8802492025-01-15 18:11:39 +0100937pub const CONSOLE_LOG_32_MAX_MSG_LEN: usize = 24;
938pub const CONSOLE_LOG_64_MAX_MSG_LEN: usize = 48;
939
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200940pub fn parse_console_log(
941 char_cnt: u32,
942 char_lists: &[u64; 6],
943 is_32bit: bool,
Balint Dobszayc8802492025-01-15 18:11:39 +0100944 log_bytes: &mut [u8],
945) -> Result<(), Error> {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200946 const CHAR_COUNT_MASK: u32 = 0xff;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200947
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200948 let char_count = (char_cnt & CHAR_COUNT_MASK) as usize;
949 let (max_length, reg_size) = if is_32bit {
Balint Dobszayc8802492025-01-15 18:11:39 +0100950 (CONSOLE_LOG_32_MAX_MSG_LEN, 4)
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200951 } else {
Balint Dobszayc8802492025-01-15 18:11:39 +0100952 (CONSOLE_LOG_64_MAX_MSG_LEN, 8)
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200953 };
954
955 if char_count < 1 || char_count > max_length {
956 return Err(Error::InvalidParameters);
957 }
958
959 for i in 0..=5 {
Balint Dobszayc8802492025-01-15 18:11:39 +0100960 log_bytes[reg_size * i..reg_size * (i + 1)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200961 .copy_from_slice(&char_lists[i].to_le_bytes()[0..reg_size]);
962 }
963
Balint Dobszayc8802492025-01-15 18:11:39 +0100964 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200965}