blob: 8865d61c9a324a403aca80f3ed95af3c0c08cd0e [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
8use alloc::string::String;
Andrew Walbran19970ba2024-11-25 15:35:00 +00009use core::fmt::{self, Debug, Display, Formatter};
Andrew Walbran44029a02024-11-25 15:34:31 +000010use num_enum::{IntoPrimitive, TryFromPrimitive};
11use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020012use uuid::Uuid;
13
14pub mod boot_info;
15pub mod memory_management;
16pub mod partition_info;
17
18pub const FFA_PAGE_SIZE: usize = 4096;
19
20#[derive(PartialEq, Clone, Copy)]
21pub enum Instance {
22 SecurePhysical,
23 SecureVirtual(u16),
24}
25
26/// FF-A v1.1, Table 12.2: Error status codes
Andrew Walbran44029a02024-11-25 15:34:31 +000027#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020028#[repr(i32)]
29pub enum Error {
Andrew Walbran44029a02024-11-25 15:34:31 +000030 #[error("Not supported")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020031 NotSupported = -1,
Andrew Walbran44029a02024-11-25 15:34:31 +000032 #[error("Invalid parameters")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020033 InvalidParameters = -2,
Andrew Walbran44029a02024-11-25 15:34:31 +000034 #[error("No memory")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020035 NoMemory = -3,
Andrew Walbran44029a02024-11-25 15:34:31 +000036 #[error("Busy")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020037 Busy = -4,
Andrew Walbran44029a02024-11-25 15:34:31 +000038 #[error("Interrupted")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020039 Interrupted = -5,
Andrew Walbran44029a02024-11-25 15:34:31 +000040 #[error("Denied")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020041 Denied = -6,
Andrew Walbran44029a02024-11-25 15:34:31 +000042 #[error("Retry")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020043 Retry = -7,
Andrew Walbran44029a02024-11-25 15:34:31 +000044 #[error("Aborted")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020045 Aborted = -8,
Andrew Walbran44029a02024-11-25 15:34:31 +000046 #[error("No data")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020047 NoData = -9,
48}
49
50/// FF-A v1.1: Function IDs
Andrew Walbran969b9252024-11-25 15:35:42 +000051#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020052#[repr(u32)]
53pub enum FuncId {
54 Error = 0x84000060,
55 Success32 = 0x84000061,
56 Success64 = 0xc4000061,
57 Interrupt = 0x84000062,
58 Version = 0x84000063,
59 Features = 0x84000064,
60 RxAcquire = 0x84000084,
61 RxRelease = 0x84000065,
62 RxTxMap32 = 0x84000066,
63 RxTxMap64 = 0xc4000066,
64 RxTxUnmap = 0x84000067,
65 PartitionInfoGet = 0x84000068,
66 IdGet = 0x84000069,
67 SpmIdGet = 0x84000085,
68 MsgWait = 0x8400006b,
69 Yield = 0x8400006c,
70 Run = 0x8400006d,
71 NormalWorldResume = 0x8400007c,
72 MsgSend2 = 0x84000086,
73 MsgSendDirectReq32 = 0x8400006f,
74 MsgSendDirectReq64 = 0xc400006f,
75 MsgSendDirectResp32 = 0x84000070,
76 MsgSendDirectResp64 = 0xc4000070,
77 MemDonate32 = 0x84000071,
78 MemDonate64 = 0xc4000071,
79 MemLend32 = 0x84000072,
80 MemLend64 = 0xc4000072,
81 MemShare32 = 0x84000073,
82 MemShare64 = 0xc4000073,
83 MemRetrieveReq32 = 0x84000074,
84 MemRetrieveReq64 = 0xc4000074,
85 MemRetrieveResp = 0x84000075,
86 MemRelinquish = 0x84000076,
87 MemReclaim = 0x84000077,
88 MemPermGet32 = 0x84000088,
89 MemPermGet64 = 0xc4000088,
90 MemPermSet32 = 0x84000089,
91 MemPermSet64 = 0xc4000089,
92 ConsoleLog32 = 0x8400008a,
93 ConsoleLog64 = 0xc400008a,
94}
95
96#[derive(Debug, Eq, PartialEq, Clone, Copy)]
97pub enum Interface {
98 Error {
99 target_info: u32,
100 error_code: Error,
101 },
102 Success {
103 target_info: u32,
104 result_regs: [u64; 6],
105 is_32bit: bool,
106 },
107 Interrupt {
108 endpoint_id: u32,
109 interrupt_id: u32,
110 },
111 Version {
112 input_version: u32,
113 },
114 VersionOut {
115 output_version: u32,
116 },
117 Features {
118 feat_id: u32,
119 input_properties: u32,
120 },
121 RxAcquire {
122 vm_id: u32,
123 },
124 RxRelease {
125 vm_id: u32,
126 },
127 RxTxMap {
128 tx_addr: u64,
129 rx_addr: u64,
130 page_cnt: u32,
131 is_32bit: bool,
132 },
133 RxTxUnmap {
134 id: u32,
135 },
136 PartitionInfoGet {
137 uuid: Uuid,
138 flags: u32,
139 },
140 IdGet,
141 SpmIdGet,
142 MsgWait,
143 Yield,
144 Run {
145 target_info: u32,
146 },
147 NormalWorldResume,
148 MsgSend2 {
149 sender_vm_id: u32,
150 flags: u32,
151 },
152 MsgSendDirectReq {
153 src_id: u16,
154 dst_id: u16,
155 flags: u32,
156 args: [u64; 5],
157 is_32bit: bool,
158 },
159 MsgSendDirectResp {
160 src_id: u16,
161 dst_id: u16,
162 flags: u32,
163 args: [u64; 5],
164 is_32bit: bool,
165 },
166 MemDonate {
167 total_len: u32,
168 frag_len: u32,
169 address: u64,
170 page_cnt: u32,
171 is_32bit: bool,
172 },
173 MemLend {
174 total_len: u32,
175 frag_len: u32,
176 address: u64,
177 page_cnt: u32,
178 is_32bit: bool,
179 },
180 MemShare {
181 total_len: u32,
182 frag_len: u32,
183 address: u64,
184 page_cnt: u32,
185 is_32bit: bool,
186 },
187 MemRetrieveReq {
188 total_len: u32,
189 frag_len: u32,
190 address: u64,
191 page_cnt: u32,
192 is_32bit: bool,
193 },
194 MemRetrieveResp {
195 total_len: u32,
196 frag_len: u32,
197 },
198 MemRelinquish,
199 MemReclaim {
200 handle: memory_management::Handle,
201 flags: u32,
202 },
203 MemPermGet {
204 base_addr: u64,
205 is_32bit: bool,
206 },
207 MemPermSet {
208 base_addr: u64,
209 page_cnt: u32,
210 mem_perm: u32,
211 is_32bit: bool,
212 },
213 ConsoleLog {
214 char_cnt: u32,
215 char_lists: [u64; 6],
216 is_32bit: bool,
217 },
218}
219
220impl TryFrom<[u64; 8]> for Interface {
221 type Error = ();
222
223 fn try_from(regs: [u64; 8]) -> Result<Self, ()> {
224 let fid = FuncId::try_from(regs[0] as u32).unwrap();
225
226 let msg = match fid {
227 FuncId::Error => Self::Error {
228 target_info: regs[1] as u32,
229 error_code: Error::try_from(regs[2] as i32).unwrap(),
230 },
231 FuncId::Success32 | FuncId::Success64 => {
232 let target_info = regs[1] as u32;
233 let mut result_regs = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
234 let mut is_32bit = false;
235
236 if fid == FuncId::Success32 {
237 result_regs[0] &= u32::MAX as u64;
238 result_regs[1] &= u32::MAX as u64;
239 result_regs[2] &= u32::MAX as u64;
240 result_regs[3] &= u32::MAX as u64;
241 result_regs[4] &= u32::MAX as u64;
242 result_regs[5] &= u32::MAX as u64;
243 is_32bit = true;
244 }
245
246 Self::Success {
247 target_info,
248 result_regs,
249 is_32bit,
250 }
251 }
252 FuncId::Interrupt => Self::Interrupt {
253 endpoint_id: regs[1] as u32,
254 interrupt_id: regs[2] as u32,
255 },
256 FuncId::Version => Self::Version {
257 input_version: regs[1] as u32,
258 },
259 FuncId::Features => Self::Features {
260 feat_id: regs[1] as u32,
261 input_properties: regs[2] as u32,
262 },
263 FuncId::RxAcquire => Self::RxAcquire {
264 vm_id: regs[1] as u32,
265 },
266 FuncId::RxRelease => Self::RxRelease {
267 vm_id: regs[1] as u32,
268 },
269 FuncId::RxTxMap32 | FuncId::RxTxMap64 => {
270 let mut tx_addr = regs[1];
271 let mut rx_addr = regs[2];
272 let page_cnt = regs[3] as u32;
273 let mut is_32bit = false;
274
275 if fid == FuncId::RxTxMap32 {
276 tx_addr &= u32::MAX as u64;
277 rx_addr &= u32::MAX as u64;
278 is_32bit = true;
279 }
280
281 Self::RxTxMap {
282 tx_addr,
283 rx_addr,
284 page_cnt,
285 is_32bit,
286 }
287 }
288 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u32 },
289 FuncId::PartitionInfoGet => {
290 let uuid_words = [
291 regs[1] as u32,
292 regs[2] as u32,
293 regs[3] as u32,
294 regs[4] as u32,
295 ];
296 let mut bytes: [u8; 16] = [0; 16];
297 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
298 bytes[i] = b;
299 }
300 Self::PartitionInfoGet {
301 uuid: Uuid::from_bytes(bytes),
302 flags: regs[5] as u32,
303 }
304 }
305 FuncId::IdGet => Self::IdGet,
306 FuncId::SpmIdGet => Self::SpmIdGet,
307 FuncId::MsgWait => Self::MsgWait,
308 FuncId::Yield => Self::Yield,
309 FuncId::Run => Self::Run {
310 target_info: regs[1] as u32,
311 },
312 FuncId::NormalWorldResume => Self::NormalWorldResume,
313 FuncId::MsgSend2 => Self::MsgSend2 {
314 sender_vm_id: regs[1] as u32,
315 flags: regs[2] as u32,
316 },
317 FuncId::MsgSendDirectReq32 | FuncId::MsgSendDirectReq64 => {
318 let src_id = (regs[1] >> 16) as u16;
319 let dst_id = regs[1] as u16;
320 let flags = regs[2] as u32;
321 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
322 let mut is_32bit = false;
323
324 if fid == FuncId::MsgSendDirectReq32 {
325 args[0] &= u32::MAX as u64;
326 args[1] &= u32::MAX as u64;
327 args[2] &= u32::MAX as u64;
328 args[3] &= u32::MAX as u64;
329 args[4] &= u32::MAX as u64;
330 is_32bit = true;
331 }
332
333 Self::MsgSendDirectReq {
334 src_id,
335 dst_id,
336 flags,
337 args,
338 is_32bit,
339 }
340 }
341 FuncId::MsgSendDirectResp32 | FuncId::MsgSendDirectResp64 => {
342 let src_id = (regs[1] >> 16) as u16;
343 let dst_id = regs[1] as u16;
344 let flags = regs[2] as u32;
345 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
346 let mut is_32bit = false;
347
348 if fid == FuncId::MsgSendDirectResp32 {
349 args[0] &= u32::MAX as u64;
350 args[1] &= u32::MAX as u64;
351 args[2] &= u32::MAX as u64;
352 args[3] &= u32::MAX as u64;
353 args[4] &= u32::MAX as u64;
354 is_32bit = true;
355 }
356
357 Self::MsgSendDirectResp {
358 src_id,
359 dst_id,
360 flags,
361 args,
362 is_32bit,
363 }
364 }
365 FuncId::MemDonate32 | FuncId::MemDonate64 => {
366 let total_len = regs[1] as u32;
367 let frag_len = regs[2] as u32;
368 let mut address = regs[3];
369 let page_cnt = regs[4] as u32;
370 let mut is_32bit = false;
371
372 if fid == FuncId::MemDonate32 {
373 address &= u32::MAX as u64;
374 is_32bit = true;
375 }
376
377 Self::MemDonate {
378 total_len,
379 frag_len,
380 address,
381 page_cnt,
382 is_32bit,
383 }
384 }
385 FuncId::MemLend32 | FuncId::MemLend64 => {
386 let total_len = regs[1] as u32;
387 let frag_len = regs[2] as u32;
388 let mut address = regs[3];
389 let page_cnt = regs[4] as u32;
390 let mut is_32bit = false;
391
392 if fid == FuncId::MemLend32 {
393 address &= u32::MAX as u64;
394 is_32bit = true;
395 }
396
397 Self::MemLend {
398 total_len,
399 frag_len,
400 address,
401 page_cnt,
402 is_32bit,
403 }
404 }
405 FuncId::MemShare32 | FuncId::MemShare64 => {
406 let total_len = regs[1] as u32;
407 let frag_len = regs[2] as u32;
408 let mut address = regs[3];
409 let page_cnt = regs[4] as u32;
410 let mut is_32bit = false;
411
412 if fid == FuncId::MemShare32 {
413 address &= u32::MAX as u64;
414 is_32bit = true;
415 }
416
417 Self::MemShare {
418 total_len,
419 frag_len,
420 address,
421 page_cnt,
422 is_32bit,
423 }
424 }
425 FuncId::MemRetrieveReq32 | FuncId::MemRetrieveReq64 => {
426 let total_len = regs[1] as u32;
427 let frag_len = regs[2] as u32;
428 let mut address = regs[3];
429 let page_cnt = regs[4] as u32;
430 let mut is_32bit = false;
431
432 if fid == FuncId::MemRetrieveReq32 {
433 address &= u32::MAX as u64;
434 is_32bit = true;
435 }
436
437 Self::MemRetrieveReq {
438 total_len,
439 frag_len,
440 address,
441 page_cnt,
442 is_32bit,
443 }
444 }
445 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
446 total_len: regs[1] as u32,
447 frag_len: regs[2] as u32,
448 },
449 FuncId::MemRelinquish => Self::MemRelinquish,
450 FuncId::MemReclaim => Self::MemReclaim {
451 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
452 flags: regs[3] as u32,
453 },
454 FuncId::MemPermGet32 | FuncId::MemPermGet64 => {
455 let mut base_addr = regs[1];
456 let mut is_32bit = false;
457
458 if fid == FuncId::MemPermGet32 {
459 base_addr &= u32::MAX as u64;
460 is_32bit = true;
461 }
462
463 Self::MemPermGet {
464 base_addr,
465 is_32bit,
466 }
467 }
468 FuncId::MemPermSet32 | FuncId::MemPermSet64 => {
469 let mut base_addr = regs[1];
470 let page_cnt = regs[2] as u32;
471 let mem_perm = regs[3] as u32;
472 let mut is_32bit = false;
473
474 if fid == FuncId::MemPermSet32 {
475 base_addr &= u32::MAX as u64;
476 is_32bit = true;
477 }
478
479 Self::MemPermSet {
480 base_addr,
481 page_cnt,
482 mem_perm,
483 is_32bit,
484 }
485 }
486 FuncId::ConsoleLog32 | FuncId::ConsoleLog64 => {
487 let char_cnt = regs[1] as u32;
488 let mut char_lists = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
489 let mut is_32bit = false;
490
491 if fid == FuncId::ConsoleLog32 {
492 char_lists[0] &= u32::MAX as u64;
493 char_lists[1] &= u32::MAX as u64;
494 char_lists[2] &= u32::MAX as u64;
495 char_lists[3] &= u32::MAX as u64;
496 char_lists[4] &= u32::MAX as u64;
497 char_lists[5] &= u32::MAX as u64;
498 is_32bit = true;
499 }
500
501 Self::ConsoleLog {
502 char_cnt,
503 char_lists,
504 is_32bit,
505 }
506 }
507 };
508
509 Ok(msg)
510 }
511}
512
513impl Interface {
Andrew Walbran0d315812024-11-25 15:36:36 +0000514 /// Returns the function ID for the call, if it has one.
515 pub fn function_id(&self) -> Option<FuncId> {
516 match self {
517 Interface::Error { .. } => Some(FuncId::Error),
518 Interface::Success {
519 is_32bit: false, ..
520 } => Some(FuncId::Success64),
521 Interface::Success { is_32bit: true, .. } => Some(FuncId::Success32),
522 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
523 Interface::Version { .. } => Some(FuncId::Version),
524 Interface::VersionOut { .. } => None,
525 Interface::Features { .. } => Some(FuncId::Features),
526 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
527 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
528 Interface::RxTxMap {
529 is_32bit: false, ..
530 } => Some(FuncId::RxTxMap64),
531 Interface::RxTxMap { is_32bit: true, .. } => Some(FuncId::RxTxMap32),
532 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
533 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
534 Interface::IdGet => Some(FuncId::IdGet),
535 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
536 Interface::MsgWait => Some(FuncId::MsgWait),
537 Interface::Yield => Some(FuncId::Yield),
538 Interface::Run { .. } => Some(FuncId::Run),
539 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
540 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
541 Interface::MsgSendDirectReq {
542 is_32bit: false, ..
543 } => Some(FuncId::MsgSendDirectReq64),
544 Interface::MsgSendDirectReq { is_32bit: true, .. } => Some(FuncId::MsgSendDirectReq32),
545 Interface::MsgSendDirectResp {
546 is_32bit: false, ..
547 } => Some(FuncId::MsgSendDirectResp64),
548 Interface::MsgSendDirectResp { is_32bit: true, .. } => {
549 Some(FuncId::MsgSendDirectResp32)
550 }
551 Interface::MemDonate {
552 is_32bit: false, ..
553 } => Some(FuncId::MemDonate64),
554 Interface::MemDonate { is_32bit: true, .. } => Some(FuncId::MemDonate32),
555 Interface::MemLend {
556 is_32bit: false, ..
557 } => Some(FuncId::MemLend64),
558 Interface::MemLend { is_32bit: true, .. } => Some(FuncId::MemLend32),
559 Interface::MemShare {
560 is_32bit: false, ..
561 } => Some(FuncId::MemShare64),
562 Interface::MemShare { is_32bit: true, .. } => Some(FuncId::MemShare32),
563 Interface::MemRetrieveReq {
564 is_32bit: false, ..
565 } => Some(FuncId::MemRetrieveReq64),
566 Interface::MemRetrieveReq { is_32bit: true, .. } => Some(FuncId::MemRetrieveReq32),
567 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
568 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
569 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
570 Interface::MemPermGet {
571 is_32bit: false, ..
572 } => Some(FuncId::MemPermGet64),
573 Interface::MemPermGet { is_32bit: true, .. } => Some(FuncId::MemPermGet32),
574 Interface::MemPermSet {
575 is_32bit: false, ..
576 } => Some(FuncId::MemPermSet64),
577 Interface::MemPermSet { is_32bit: true, .. } => Some(FuncId::MemPermSet32),
578 Interface::ConsoleLog {
579 is_32bit: false, ..
580 } => Some(FuncId::ConsoleLog64),
581 Interface::ConsoleLog { is_32bit: true, .. } => Some(FuncId::ConsoleLog32),
582 }
583 }
584
585 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
586 pub fn is_32bit(&self) -> bool {
587 match self {
588 Interface::Error { .. }
589 | Interface::Interrupt { .. }
590 | Interface::Version { .. }
591 | Interface::VersionOut { .. }
592 | Interface::Features { .. }
593 | Interface::RxAcquire { .. }
594 | Interface::RxRelease { .. }
595 | Interface::RxTxUnmap { .. }
596 | Interface::PartitionInfoGet { .. }
597 | Interface::IdGet
598 | Interface::SpmIdGet
599 | Interface::MsgWait
600 | Interface::Yield
601 | Interface::Run { .. }
602 | Interface::NormalWorldResume
603 | Interface::MsgSend2 { .. }
604 | Interface::MemRetrieveResp { .. }
605 | Interface::MemRelinquish
606 | Interface::MemReclaim { .. } => true,
607 Interface::Success { is_32bit, .. }
608 | Interface::RxTxMap { is_32bit, .. }
609 | Interface::MsgSendDirectReq { is_32bit, .. }
610 | Interface::MsgSendDirectResp { is_32bit, .. }
611 | Interface::MemDonate { is_32bit, .. }
612 | Interface::MemLend { is_32bit, .. }
613 | Interface::MemShare { is_32bit, .. }
614 | Interface::MemRetrieveReq { is_32bit, .. }
615 | Interface::MemPermGet { is_32bit, .. }
616 | Interface::MemPermSet { is_32bit, .. }
617 | Interface::ConsoleLog { is_32bit, .. } => *is_32bit,
618 }
619 }
620
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200621 pub fn copy_to_array(&self, a: &mut [u64; 8]) {
622 a.fill(0);
Andrew Walbran0d315812024-11-25 15:36:36 +0000623 if let Some(function_id) = self.function_id() {
624 a[0] = function_id as u64;
625 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200626
627 match *self {
628 Interface::Error {
629 target_info,
630 error_code,
631 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200632 a[1] = target_info as u64;
633 a[2] = error_code as u32 as u64;
634 }
635 Interface::Success {
636 target_info,
637 result_regs,
638 is_32bit,
639 } => {
640 a[1] = target_info as u64;
641 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200642 a[2] = result_regs[0] & u32::MAX as u64;
643 a[3] = result_regs[1] & u32::MAX as u64;
644 a[4] = result_regs[2] & u32::MAX as u64;
645 a[5] = result_regs[3] & u32::MAX as u64;
646 a[6] = result_regs[4] & u32::MAX as u64;
647 a[7] = result_regs[5] & u32::MAX as u64;
648 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200649 a[2] = result_regs[0];
650 a[3] = result_regs[1];
651 a[4] = result_regs[2];
652 a[5] = result_regs[3];
653 a[6] = result_regs[4];
654 a[7] = result_regs[5];
655 }
656 }
657 Interface::Interrupt {
658 endpoint_id,
659 interrupt_id,
660 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200661 a[1] = endpoint_id as u64;
662 a[2] = interrupt_id as u64;
663 }
664 Interface::Version { input_version } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200665 a[1] = input_version as u64;
666 }
667 Interface::VersionOut { output_version } => {
668 a[0] = output_version as u64;
669 }
670 Interface::Features {
671 feat_id,
672 input_properties,
673 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200674 a[1] = feat_id as u64;
675 a[2] = input_properties as u64;
676 }
677 Interface::RxAcquire { vm_id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200678 a[1] = vm_id as u64;
679 }
680 Interface::RxRelease { vm_id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200681 a[1] = vm_id as u64;
682 }
683 Interface::RxTxMap {
684 tx_addr,
685 rx_addr,
686 page_cnt,
687 is_32bit,
688 } => {
689 a[3] = page_cnt as u64;
690 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200691 a[1] = tx_addr & u32::MAX as u64;
692 a[2] = rx_addr & u32::MAX as u64;
693 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200694 a[1] = tx_addr;
695 a[2] = rx_addr;
696 }
697 }
698 Interface::RxTxUnmap { id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200699 a[1] = id as u64;
700 }
701 Interface::PartitionInfoGet { uuid, flags } => {
702 let bytes = uuid.to_bytes_le();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200703 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as u64;
704 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64;
705 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as u64;
706 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]) as u64;
707 a[5] = flags as u64;
708 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000709 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200710 Interface::Run { target_info } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200711 a[1] = target_info as u64;
712 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000713 Interface::NormalWorldResume => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200714 Interface::MsgSend2 {
715 sender_vm_id,
716 flags,
717 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200718 a[1] = sender_vm_id as u64;
719 a[2] = flags as u64;
720 }
721 Interface::MsgSendDirectReq {
722 src_id,
723 dst_id,
724 flags,
725 args,
726 is_32bit,
727 } => {
728 a[1] = (src_id as u64) << 16 | dst_id as u64;
729 a[2] = flags as u64;
730 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200731 a[3] = args[0] & u32::MAX as u64;
732 a[4] = args[1] & u32::MAX as u64;
733 a[5] = args[2] & u32::MAX as u64;
734 a[6] = args[3] & u32::MAX as u64;
735 a[7] = args[4] & u32::MAX as u64;
736 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200737 a[3] = args[0];
738 a[4] = args[1];
739 a[5] = args[2];
740 a[6] = args[3];
741 a[7] = args[4];
742 }
743 }
744 Interface::MsgSendDirectResp {
745 src_id,
746 dst_id,
747 flags,
748 args,
749 is_32bit,
750 } => {
751 a[1] = (src_id as u64) << 16 | dst_id as u64;
752 a[2] = flags as u64;
753 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200754 a[3] = args[0] & u32::MAX as u64;
755 a[4] = args[1] & u32::MAX as u64;
756 a[5] = args[2] & u32::MAX as u64;
757 a[6] = args[3] & u32::MAX as u64;
758 a[7] = args[4] & u32::MAX as u64;
759 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200760 a[3] = args[0];
761 a[4] = args[1];
762 a[5] = args[2];
763 a[6] = args[3];
764 a[7] = args[4];
765 }
766 }
767 Interface::MemDonate {
768 total_len,
769 frag_len,
770 address,
771 page_cnt,
772 is_32bit,
773 } => {
774 a[1] = total_len as u64;
775 a[2] = frag_len as u64;
776 a[4] = page_cnt as u64;
777 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200778 a[3] = address & u32::MAX as u64;
779 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200780 a[3] = address;
781 }
782 }
783 Interface::MemLend {
784 total_len,
785 frag_len,
786 address,
787 page_cnt,
788 is_32bit,
789 } => {
790 a[1] = total_len as u64;
791 a[2] = frag_len as u64;
792 a[4] = page_cnt as u64;
793 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200794 a[3] = address & u32::MAX as u64;
795 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200796 a[3] = address;
797 }
798 }
799 Interface::MemShare {
800 total_len,
801 frag_len,
802 address,
803 page_cnt,
804 is_32bit,
805 } => {
806 a[1] = total_len as u64;
807 a[2] = frag_len as u64;
808 a[4] = page_cnt as u64;
809 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200810 a[3] = address & u32::MAX as u64;
811 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200812 a[3] = address;
813 }
814 }
815 Interface::MemRetrieveReq {
816 total_len,
817 frag_len,
818 address,
819 page_cnt,
820 is_32bit,
821 } => {
822 a[1] = total_len as u64;
823 a[2] = frag_len as u64;
824 a[4] = page_cnt as u64;
825 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200826 a[3] = address & u32::MAX as u64;
827 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200828 a[3] = address;
829 }
830 }
831 Interface::MemRetrieveResp {
832 total_len,
833 frag_len,
834 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200835 a[1] = total_len as u64;
836 a[2] = frag_len as u64;
837 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000838 Interface::MemRelinquish => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200839 Interface::MemReclaim { handle, flags } => {
840 let handle_regs: [u32; 2] = handle.into();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200841 a[1] = handle_regs[0] as u64;
842 a[2] = handle_regs[1] as u64;
843 a[3] = flags as u64;
844 }
845 Interface::MemPermGet {
846 base_addr,
847 is_32bit,
848 } => {
849 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200850 a[1] = base_addr & u32::MAX as u64;
851 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200852 a[1] = base_addr;
853 }
854 }
855 Interface::MemPermSet {
856 base_addr,
857 page_cnt,
858 mem_perm,
859 is_32bit,
860 } => {
861 a[2] = page_cnt as u64;
862 a[3] = mem_perm as u64;
863
864 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200865 a[1] = base_addr & u32::MAX as u64;
866 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200867 a[1] = base_addr;
868 }
869 }
870 Interface::ConsoleLog {
871 char_cnt,
872 char_lists,
873 is_32bit,
874 } => {
875 a[1] = char_cnt as u64;
876 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200877 a[2] = char_lists[0] & u32::MAX as u64;
878 a[3] = char_lists[1] & u32::MAX as u64;
879 a[4] = char_lists[2] & u32::MAX as u64;
880 a[5] = char_lists[3] & u32::MAX as u64;
881 a[6] = char_lists[4] & u32::MAX as u64;
882 a[7] = char_lists[5] & u32::MAX as u64;
883 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200884 a[2] = char_lists[0];
885 a[3] = char_lists[1];
886 a[4] = char_lists[2];
887 a[5] = char_lists[3];
888 a[6] = char_lists[4];
889 a[7] = char_lists[5];
890 }
891 }
892 }
893 }
894
895 /// Helper function to create an FFA_SUCCESS interface without any arguments
896 pub fn success32_noargs() -> Self {
897 Self::Success {
898 target_info: 0,
899 result_regs: [0, 0, 0, 0, 0, 0],
900 is_32bit: true,
901 }
902 }
903}
904
Andrew Walbran19970ba2024-11-25 15:35:00 +0000905#[derive(Clone, Copy, Eq, PartialEq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200906pub struct Version(pub u16, pub u16);
907
908impl From<u32> for Version {
909 fn from(val: u32) -> Self {
910 Self((val >> 16) as u16, val as u16)
911 }
912}
913
914impl From<Version> for u32 {
915 fn from(v: Version) -> Self {
916 (v.0 as u32) << 16 | v.1 as u32
917 }
918}
919
Andrew Walbran19970ba2024-11-25 15:35:00 +0000920impl Display for Version {
921 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
922 write!(f, "{}.{}", self.0, self.1)
923 }
924}
925
926impl Debug for Version {
927 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
928 Display::fmt(self, f)
929 }
930}
931
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200932pub fn parse_console_log(
933 char_cnt: u32,
934 char_lists: &[u64; 6],
935 is_32bit: bool,
936) -> Result<String, Error> {
937 const CHAR_COUNT_MASK: u32 = 0xff;
938 const LOG_32_MAX_MSG_LEN: usize = 24;
939 const LOG_64_MAX_MSG_LEN: usize = 48;
940
941 let mut msg_bytes = [0u8; LOG_64_MAX_MSG_LEN + 1];
942 let char_count = (char_cnt & CHAR_COUNT_MASK) as usize;
943 let (max_length, reg_size) = if is_32bit {
944 (LOG_32_MAX_MSG_LEN, 4)
945 } else {
946 (LOG_64_MAX_MSG_LEN, 8)
947 };
948
949 if char_count < 1 || char_count > max_length {
950 return Err(Error::InvalidParameters);
951 }
952
953 for i in 0..=5 {
954 msg_bytes[reg_size * i..reg_size * (i + 1)]
955 .copy_from_slice(&char_lists[i].to_le_bytes()[0..reg_size]);
956 }
957
958 String::from_utf8(msg_bytes.to_vec()).map_err(|_| Error::InvalidParameters)
959}