blob: a331580491969536fea9b14f59d3a0019aea28c6 [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;
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010014mod ffa_v1_1;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020015pub 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
Andrew Walbran1e1aef12024-11-25 16:17:32 +000050/// An integer couldn't be converted to a [`FuncId`] because it is not a recognised function.
51#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
52#[error("Unrecognised function ID {0} for FF-A")]
53pub struct UnrecognisedFunctionIdError(u32);
54
Balint Dobszay5bf492f2024-07-29 17:21:32 +020055/// FF-A v1.1: Function IDs
Andrew Walbran969b9252024-11-25 15:35:42 +000056#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Andrew Walbran1e1aef12024-11-25 16:17:32 +000057#[num_enum(error_type(name = UnrecognisedFunctionIdError, constructor = UnrecognisedFunctionIdError))]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020058#[repr(u32)]
59pub enum FuncId {
60 Error = 0x84000060,
61 Success32 = 0x84000061,
62 Success64 = 0xc4000061,
63 Interrupt = 0x84000062,
64 Version = 0x84000063,
65 Features = 0x84000064,
66 RxAcquire = 0x84000084,
67 RxRelease = 0x84000065,
68 RxTxMap32 = 0x84000066,
69 RxTxMap64 = 0xc4000066,
70 RxTxUnmap = 0x84000067,
71 PartitionInfoGet = 0x84000068,
72 IdGet = 0x84000069,
73 SpmIdGet = 0x84000085,
74 MsgWait = 0x8400006b,
75 Yield = 0x8400006c,
76 Run = 0x8400006d,
77 NormalWorldResume = 0x8400007c,
78 MsgSend2 = 0x84000086,
79 MsgSendDirectReq32 = 0x8400006f,
80 MsgSendDirectReq64 = 0xc400006f,
81 MsgSendDirectResp32 = 0x84000070,
82 MsgSendDirectResp64 = 0xc4000070,
83 MemDonate32 = 0x84000071,
84 MemDonate64 = 0xc4000071,
85 MemLend32 = 0x84000072,
86 MemLend64 = 0xc4000072,
87 MemShare32 = 0x84000073,
88 MemShare64 = 0xc4000073,
89 MemRetrieveReq32 = 0x84000074,
90 MemRetrieveReq64 = 0xc4000074,
91 MemRetrieveResp = 0x84000075,
92 MemRelinquish = 0x84000076,
93 MemReclaim = 0x84000077,
94 MemPermGet32 = 0x84000088,
95 MemPermGet64 = 0xc4000088,
96 MemPermSet32 = 0x84000089,
97 MemPermSet64 = 0xc4000089,
98 ConsoleLog32 = 0x8400008a,
99 ConsoleLog64 = 0xc400008a,
100}
101
102#[derive(Debug, Eq, PartialEq, Clone, Copy)]
103pub enum Interface {
104 Error {
105 target_info: u32,
106 error_code: Error,
107 },
108 Success {
109 target_info: u32,
110 result_regs: [u64; 6],
111 is_32bit: bool,
112 },
113 Interrupt {
114 endpoint_id: u32,
115 interrupt_id: u32,
116 },
117 Version {
118 input_version: u32,
119 },
120 VersionOut {
121 output_version: u32,
122 },
123 Features {
124 feat_id: u32,
125 input_properties: u32,
126 },
127 RxAcquire {
128 vm_id: u32,
129 },
130 RxRelease {
131 vm_id: u32,
132 },
133 RxTxMap {
134 tx_addr: u64,
135 rx_addr: u64,
136 page_cnt: u32,
137 is_32bit: bool,
138 },
139 RxTxUnmap {
140 id: u32,
141 },
142 PartitionInfoGet {
143 uuid: Uuid,
144 flags: u32,
145 },
146 IdGet,
147 SpmIdGet,
148 MsgWait,
149 Yield,
150 Run {
151 target_info: u32,
152 },
153 NormalWorldResume,
154 MsgSend2 {
155 sender_vm_id: u32,
156 flags: u32,
157 },
158 MsgSendDirectReq {
159 src_id: u16,
160 dst_id: u16,
161 flags: u32,
162 args: [u64; 5],
163 is_32bit: bool,
164 },
165 MsgSendDirectResp {
166 src_id: u16,
167 dst_id: u16,
168 flags: u32,
169 args: [u64; 5],
170 is_32bit: bool,
171 },
172 MemDonate {
173 total_len: u32,
174 frag_len: u32,
175 address: u64,
176 page_cnt: u32,
177 is_32bit: bool,
178 },
179 MemLend {
180 total_len: u32,
181 frag_len: u32,
182 address: u64,
183 page_cnt: u32,
184 is_32bit: bool,
185 },
186 MemShare {
187 total_len: u32,
188 frag_len: u32,
189 address: u64,
190 page_cnt: u32,
191 is_32bit: bool,
192 },
193 MemRetrieveReq {
194 total_len: u32,
195 frag_len: u32,
196 address: u64,
197 page_cnt: u32,
198 is_32bit: bool,
199 },
200 MemRetrieveResp {
201 total_len: u32,
202 frag_len: u32,
203 },
204 MemRelinquish,
205 MemReclaim {
206 handle: memory_management::Handle,
207 flags: u32,
208 },
209 MemPermGet {
210 base_addr: u64,
211 is_32bit: bool,
212 },
213 MemPermSet {
214 base_addr: u64,
215 page_cnt: u32,
216 mem_perm: u32,
217 is_32bit: bool,
218 },
219 ConsoleLog {
220 char_cnt: u32,
221 char_lists: [u64; 6],
222 is_32bit: bool,
223 },
224}
225
226impl TryFrom<[u64; 8]> for Interface {
Andrew Walbran1e1aef12024-11-25 16:17:32 +0000227 type Error = UnrecognisedFunctionIdError;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200228
Andrew Walbran1e1aef12024-11-25 16:17:32 +0000229 fn try_from(regs: [u64; 8]) -> Result<Self, UnrecognisedFunctionIdError> {
230 let fid = FuncId::try_from(regs[0] as u32)?;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200231
232 let msg = match fid {
233 FuncId::Error => Self::Error {
234 target_info: regs[1] as u32,
235 error_code: Error::try_from(regs[2] as i32).unwrap(),
236 },
237 FuncId::Success32 | FuncId::Success64 => {
238 let target_info = regs[1] as u32;
239 let mut result_regs = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
240 let mut is_32bit = false;
241
242 if fid == FuncId::Success32 {
243 result_regs[0] &= u32::MAX as u64;
244 result_regs[1] &= u32::MAX as u64;
245 result_regs[2] &= u32::MAX as u64;
246 result_regs[3] &= u32::MAX as u64;
247 result_regs[4] &= u32::MAX as u64;
248 result_regs[5] &= u32::MAX as u64;
249 is_32bit = true;
250 }
251
252 Self::Success {
253 target_info,
254 result_regs,
255 is_32bit,
256 }
257 }
258 FuncId::Interrupt => Self::Interrupt {
259 endpoint_id: regs[1] as u32,
260 interrupt_id: regs[2] as u32,
261 },
262 FuncId::Version => Self::Version {
263 input_version: regs[1] as u32,
264 },
265 FuncId::Features => Self::Features {
266 feat_id: regs[1] as u32,
267 input_properties: regs[2] as u32,
268 },
269 FuncId::RxAcquire => Self::RxAcquire {
270 vm_id: regs[1] as u32,
271 },
272 FuncId::RxRelease => Self::RxRelease {
273 vm_id: regs[1] as u32,
274 },
275 FuncId::RxTxMap32 | FuncId::RxTxMap64 => {
276 let mut tx_addr = regs[1];
277 let mut rx_addr = regs[2];
278 let page_cnt = regs[3] as u32;
279 let mut is_32bit = false;
280
281 if fid == FuncId::RxTxMap32 {
282 tx_addr &= u32::MAX as u64;
283 rx_addr &= u32::MAX as u64;
284 is_32bit = true;
285 }
286
287 Self::RxTxMap {
288 tx_addr,
289 rx_addr,
290 page_cnt,
291 is_32bit,
292 }
293 }
294 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u32 },
295 FuncId::PartitionInfoGet => {
296 let uuid_words = [
297 regs[1] as u32,
298 regs[2] as u32,
299 regs[3] as u32,
300 regs[4] as u32,
301 ];
302 let mut bytes: [u8; 16] = [0; 16];
303 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
304 bytes[i] = b;
305 }
306 Self::PartitionInfoGet {
307 uuid: Uuid::from_bytes(bytes),
308 flags: regs[5] as u32,
309 }
310 }
311 FuncId::IdGet => Self::IdGet,
312 FuncId::SpmIdGet => Self::SpmIdGet,
313 FuncId::MsgWait => Self::MsgWait,
314 FuncId::Yield => Self::Yield,
315 FuncId::Run => Self::Run {
316 target_info: regs[1] as u32,
317 },
318 FuncId::NormalWorldResume => Self::NormalWorldResume,
319 FuncId::MsgSend2 => Self::MsgSend2 {
320 sender_vm_id: regs[1] as u32,
321 flags: regs[2] as u32,
322 },
323 FuncId::MsgSendDirectReq32 | FuncId::MsgSendDirectReq64 => {
324 let src_id = (regs[1] >> 16) as u16;
325 let dst_id = regs[1] as u16;
326 let flags = regs[2] as u32;
327 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
328 let mut is_32bit = false;
329
330 if fid == FuncId::MsgSendDirectReq32 {
331 args[0] &= u32::MAX as u64;
332 args[1] &= u32::MAX as u64;
333 args[2] &= u32::MAX as u64;
334 args[3] &= u32::MAX as u64;
335 args[4] &= u32::MAX as u64;
336 is_32bit = true;
337 }
338
339 Self::MsgSendDirectReq {
340 src_id,
341 dst_id,
342 flags,
343 args,
344 is_32bit,
345 }
346 }
347 FuncId::MsgSendDirectResp32 | FuncId::MsgSendDirectResp64 => {
348 let src_id = (regs[1] >> 16) as u16;
349 let dst_id = regs[1] as u16;
350 let flags = regs[2] as u32;
351 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
352 let mut is_32bit = false;
353
354 if fid == FuncId::MsgSendDirectResp32 {
355 args[0] &= u32::MAX as u64;
356 args[1] &= u32::MAX as u64;
357 args[2] &= u32::MAX as u64;
358 args[3] &= u32::MAX as u64;
359 args[4] &= u32::MAX as u64;
360 is_32bit = true;
361 }
362
363 Self::MsgSendDirectResp {
364 src_id,
365 dst_id,
366 flags,
367 args,
368 is_32bit,
369 }
370 }
371 FuncId::MemDonate32 | FuncId::MemDonate64 => {
372 let total_len = regs[1] as u32;
373 let frag_len = regs[2] as u32;
374 let mut address = regs[3];
375 let page_cnt = regs[4] as u32;
376 let mut is_32bit = false;
377
378 if fid == FuncId::MemDonate32 {
379 address &= u32::MAX as u64;
380 is_32bit = true;
381 }
382
383 Self::MemDonate {
384 total_len,
385 frag_len,
386 address,
387 page_cnt,
388 is_32bit,
389 }
390 }
391 FuncId::MemLend32 | FuncId::MemLend64 => {
392 let total_len = regs[1] as u32;
393 let frag_len = regs[2] as u32;
394 let mut address = regs[3];
395 let page_cnt = regs[4] as u32;
396 let mut is_32bit = false;
397
398 if fid == FuncId::MemLend32 {
399 address &= u32::MAX as u64;
400 is_32bit = true;
401 }
402
403 Self::MemLend {
404 total_len,
405 frag_len,
406 address,
407 page_cnt,
408 is_32bit,
409 }
410 }
411 FuncId::MemShare32 | FuncId::MemShare64 => {
412 let total_len = regs[1] as u32;
413 let frag_len = regs[2] as u32;
414 let mut address = regs[3];
415 let page_cnt = regs[4] as u32;
416 let mut is_32bit = false;
417
418 if fid == FuncId::MemShare32 {
419 address &= u32::MAX as u64;
420 is_32bit = true;
421 }
422
423 Self::MemShare {
424 total_len,
425 frag_len,
426 address,
427 page_cnt,
428 is_32bit,
429 }
430 }
431 FuncId::MemRetrieveReq32 | FuncId::MemRetrieveReq64 => {
432 let total_len = regs[1] as u32;
433 let frag_len = regs[2] as u32;
434 let mut address = regs[3];
435 let page_cnt = regs[4] as u32;
436 let mut is_32bit = false;
437
438 if fid == FuncId::MemRetrieveReq32 {
439 address &= u32::MAX as u64;
440 is_32bit = true;
441 }
442
443 Self::MemRetrieveReq {
444 total_len,
445 frag_len,
446 address,
447 page_cnt,
448 is_32bit,
449 }
450 }
451 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
452 total_len: regs[1] as u32,
453 frag_len: regs[2] as u32,
454 },
455 FuncId::MemRelinquish => Self::MemRelinquish,
456 FuncId::MemReclaim => Self::MemReclaim {
457 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
458 flags: regs[3] as u32,
459 },
460 FuncId::MemPermGet32 | FuncId::MemPermGet64 => {
461 let mut base_addr = regs[1];
462 let mut is_32bit = false;
463
464 if fid == FuncId::MemPermGet32 {
465 base_addr &= u32::MAX as u64;
466 is_32bit = true;
467 }
468
469 Self::MemPermGet {
470 base_addr,
471 is_32bit,
472 }
473 }
474 FuncId::MemPermSet32 | FuncId::MemPermSet64 => {
475 let mut base_addr = regs[1];
476 let page_cnt = regs[2] as u32;
477 let mem_perm = regs[3] as u32;
478 let mut is_32bit = false;
479
480 if fid == FuncId::MemPermSet32 {
481 base_addr &= u32::MAX as u64;
482 is_32bit = true;
483 }
484
485 Self::MemPermSet {
486 base_addr,
487 page_cnt,
488 mem_perm,
489 is_32bit,
490 }
491 }
492 FuncId::ConsoleLog32 | FuncId::ConsoleLog64 => {
493 let char_cnt = regs[1] as u32;
494 let mut char_lists = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
495 let mut is_32bit = false;
496
497 if fid == FuncId::ConsoleLog32 {
498 char_lists[0] &= u32::MAX as u64;
499 char_lists[1] &= u32::MAX as u64;
500 char_lists[2] &= u32::MAX as u64;
501 char_lists[3] &= u32::MAX as u64;
502 char_lists[4] &= u32::MAX as u64;
503 char_lists[5] &= u32::MAX as u64;
504 is_32bit = true;
505 }
506
507 Self::ConsoleLog {
508 char_cnt,
509 char_lists,
510 is_32bit,
511 }
512 }
513 };
514
515 Ok(msg)
516 }
517}
518
519impl Interface {
Andrew Walbran0d315812024-11-25 15:36:36 +0000520 /// Returns the function ID for the call, if it has one.
521 pub fn function_id(&self) -> Option<FuncId> {
522 match self {
523 Interface::Error { .. } => Some(FuncId::Error),
524 Interface::Success {
525 is_32bit: false, ..
526 } => Some(FuncId::Success64),
527 Interface::Success { is_32bit: true, .. } => Some(FuncId::Success32),
528 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
529 Interface::Version { .. } => Some(FuncId::Version),
530 Interface::VersionOut { .. } => None,
531 Interface::Features { .. } => Some(FuncId::Features),
532 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
533 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
534 Interface::RxTxMap {
535 is_32bit: false, ..
536 } => Some(FuncId::RxTxMap64),
537 Interface::RxTxMap { is_32bit: true, .. } => Some(FuncId::RxTxMap32),
538 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
539 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
540 Interface::IdGet => Some(FuncId::IdGet),
541 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
542 Interface::MsgWait => Some(FuncId::MsgWait),
543 Interface::Yield => Some(FuncId::Yield),
544 Interface::Run { .. } => Some(FuncId::Run),
545 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
546 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
547 Interface::MsgSendDirectReq {
548 is_32bit: false, ..
549 } => Some(FuncId::MsgSendDirectReq64),
550 Interface::MsgSendDirectReq { is_32bit: true, .. } => Some(FuncId::MsgSendDirectReq32),
551 Interface::MsgSendDirectResp {
552 is_32bit: false, ..
553 } => Some(FuncId::MsgSendDirectResp64),
554 Interface::MsgSendDirectResp { is_32bit: true, .. } => {
555 Some(FuncId::MsgSendDirectResp32)
556 }
557 Interface::MemDonate {
558 is_32bit: false, ..
559 } => Some(FuncId::MemDonate64),
560 Interface::MemDonate { is_32bit: true, .. } => Some(FuncId::MemDonate32),
561 Interface::MemLend {
562 is_32bit: false, ..
563 } => Some(FuncId::MemLend64),
564 Interface::MemLend { is_32bit: true, .. } => Some(FuncId::MemLend32),
565 Interface::MemShare {
566 is_32bit: false, ..
567 } => Some(FuncId::MemShare64),
568 Interface::MemShare { is_32bit: true, .. } => Some(FuncId::MemShare32),
569 Interface::MemRetrieveReq {
570 is_32bit: false, ..
571 } => Some(FuncId::MemRetrieveReq64),
572 Interface::MemRetrieveReq { is_32bit: true, .. } => Some(FuncId::MemRetrieveReq32),
573 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
574 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
575 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
576 Interface::MemPermGet {
577 is_32bit: false, ..
578 } => Some(FuncId::MemPermGet64),
579 Interface::MemPermGet { is_32bit: true, .. } => Some(FuncId::MemPermGet32),
580 Interface::MemPermSet {
581 is_32bit: false, ..
582 } => Some(FuncId::MemPermSet64),
583 Interface::MemPermSet { is_32bit: true, .. } => Some(FuncId::MemPermSet32),
584 Interface::ConsoleLog {
585 is_32bit: false, ..
586 } => Some(FuncId::ConsoleLog64),
587 Interface::ConsoleLog { is_32bit: true, .. } => Some(FuncId::ConsoleLog32),
588 }
589 }
590
591 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
592 pub fn is_32bit(&self) -> bool {
593 match self {
594 Interface::Error { .. }
595 | Interface::Interrupt { .. }
596 | Interface::Version { .. }
597 | Interface::VersionOut { .. }
598 | Interface::Features { .. }
599 | Interface::RxAcquire { .. }
600 | Interface::RxRelease { .. }
601 | Interface::RxTxUnmap { .. }
602 | Interface::PartitionInfoGet { .. }
603 | Interface::IdGet
604 | Interface::SpmIdGet
605 | Interface::MsgWait
606 | Interface::Yield
607 | Interface::Run { .. }
608 | Interface::NormalWorldResume
609 | Interface::MsgSend2 { .. }
610 | Interface::MemRetrieveResp { .. }
611 | Interface::MemRelinquish
612 | Interface::MemReclaim { .. } => true,
613 Interface::Success { is_32bit, .. }
614 | Interface::RxTxMap { is_32bit, .. }
615 | Interface::MsgSendDirectReq { is_32bit, .. }
616 | Interface::MsgSendDirectResp { is_32bit, .. }
617 | Interface::MemDonate { is_32bit, .. }
618 | Interface::MemLend { is_32bit, .. }
619 | Interface::MemShare { is_32bit, .. }
620 | Interface::MemRetrieveReq { is_32bit, .. }
621 | Interface::MemPermGet { is_32bit, .. }
622 | Interface::MemPermSet { is_32bit, .. }
623 | Interface::ConsoleLog { is_32bit, .. } => *is_32bit,
624 }
625 }
626
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200627 pub fn copy_to_array(&self, a: &mut [u64; 8]) {
628 a.fill(0);
Andrew Walbran0d315812024-11-25 15:36:36 +0000629 if let Some(function_id) = self.function_id() {
630 a[0] = function_id as u64;
631 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200632
633 match *self {
634 Interface::Error {
635 target_info,
636 error_code,
637 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200638 a[1] = target_info as u64;
639 a[2] = error_code as u32 as u64;
640 }
641 Interface::Success {
642 target_info,
643 result_regs,
644 is_32bit,
645 } => {
646 a[1] = target_info as u64;
647 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200648 a[2] = result_regs[0] & u32::MAX as u64;
649 a[3] = result_regs[1] & u32::MAX as u64;
650 a[4] = result_regs[2] & u32::MAX as u64;
651 a[5] = result_regs[3] & u32::MAX as u64;
652 a[6] = result_regs[4] & u32::MAX as u64;
653 a[7] = result_regs[5] & u32::MAX as u64;
654 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200655 a[2] = result_regs[0];
656 a[3] = result_regs[1];
657 a[4] = result_regs[2];
658 a[5] = result_regs[3];
659 a[6] = result_regs[4];
660 a[7] = result_regs[5];
661 }
662 }
663 Interface::Interrupt {
664 endpoint_id,
665 interrupt_id,
666 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200667 a[1] = endpoint_id as u64;
668 a[2] = interrupt_id as u64;
669 }
670 Interface::Version { input_version } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200671 a[1] = input_version as u64;
672 }
673 Interface::VersionOut { output_version } => {
674 a[0] = output_version as u64;
675 }
676 Interface::Features {
677 feat_id,
678 input_properties,
679 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200680 a[1] = feat_id as u64;
681 a[2] = input_properties as u64;
682 }
683 Interface::RxAcquire { vm_id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200684 a[1] = vm_id as u64;
685 }
686 Interface::RxRelease { vm_id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200687 a[1] = vm_id as u64;
688 }
689 Interface::RxTxMap {
690 tx_addr,
691 rx_addr,
692 page_cnt,
693 is_32bit,
694 } => {
695 a[3] = page_cnt as u64;
696 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200697 a[1] = tx_addr & u32::MAX as u64;
698 a[2] = rx_addr & u32::MAX as u64;
699 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200700 a[1] = tx_addr;
701 a[2] = rx_addr;
702 }
703 }
704 Interface::RxTxUnmap { id } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200705 a[1] = id as u64;
706 }
707 Interface::PartitionInfoGet { uuid, flags } => {
708 let bytes = uuid.to_bytes_le();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200709 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as u64;
710 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64;
711 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as u64;
712 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]) as u64;
713 a[5] = flags as u64;
714 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000715 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200716 Interface::Run { target_info } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200717 a[1] = target_info as u64;
718 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000719 Interface::NormalWorldResume => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200720 Interface::MsgSend2 {
721 sender_vm_id,
722 flags,
723 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200724 a[1] = sender_vm_id as u64;
725 a[2] = flags as u64;
726 }
727 Interface::MsgSendDirectReq {
728 src_id,
729 dst_id,
730 flags,
731 args,
732 is_32bit,
733 } => {
734 a[1] = (src_id as u64) << 16 | dst_id as u64;
735 a[2] = flags as u64;
736 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200737 a[3] = args[0] & u32::MAX as u64;
738 a[4] = args[1] & u32::MAX as u64;
739 a[5] = args[2] & u32::MAX as u64;
740 a[6] = args[3] & u32::MAX as u64;
741 a[7] = args[4] & u32::MAX as u64;
742 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200743 a[3] = args[0];
744 a[4] = args[1];
745 a[5] = args[2];
746 a[6] = args[3];
747 a[7] = args[4];
748 }
749 }
750 Interface::MsgSendDirectResp {
751 src_id,
752 dst_id,
753 flags,
754 args,
755 is_32bit,
756 } => {
757 a[1] = (src_id as u64) << 16 | dst_id as u64;
758 a[2] = flags as u64;
759 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200760 a[3] = args[0] & u32::MAX as u64;
761 a[4] = args[1] & u32::MAX as u64;
762 a[5] = args[2] & u32::MAX as u64;
763 a[6] = args[3] & u32::MAX as u64;
764 a[7] = args[4] & u32::MAX as u64;
765 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200766 a[3] = args[0];
767 a[4] = args[1];
768 a[5] = args[2];
769 a[6] = args[3];
770 a[7] = args[4];
771 }
772 }
773 Interface::MemDonate {
774 total_len,
775 frag_len,
776 address,
777 page_cnt,
778 is_32bit,
779 } => {
780 a[1] = total_len as u64;
781 a[2] = frag_len as u64;
782 a[4] = page_cnt as u64;
783 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200784 a[3] = address & u32::MAX as u64;
785 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200786 a[3] = address;
787 }
788 }
789 Interface::MemLend {
790 total_len,
791 frag_len,
792 address,
793 page_cnt,
794 is_32bit,
795 } => {
796 a[1] = total_len as u64;
797 a[2] = frag_len as u64;
798 a[4] = page_cnt as u64;
799 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200800 a[3] = address & u32::MAX as u64;
801 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200802 a[3] = address;
803 }
804 }
805 Interface::MemShare {
806 total_len,
807 frag_len,
808 address,
809 page_cnt,
810 is_32bit,
811 } => {
812 a[1] = total_len as u64;
813 a[2] = frag_len as u64;
814 a[4] = page_cnt as u64;
815 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200816 a[3] = address & u32::MAX as u64;
817 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200818 a[3] = address;
819 }
820 }
821 Interface::MemRetrieveReq {
822 total_len,
823 frag_len,
824 address,
825 page_cnt,
826 is_32bit,
827 } => {
828 a[1] = total_len as u64;
829 a[2] = frag_len as u64;
830 a[4] = page_cnt as u64;
831 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200832 a[3] = address & u32::MAX as u64;
833 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200834 a[3] = address;
835 }
836 }
837 Interface::MemRetrieveResp {
838 total_len,
839 frag_len,
840 } => {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200841 a[1] = total_len as u64;
842 a[2] = frag_len as u64;
843 }
Andrew Walbran0d315812024-11-25 15:36:36 +0000844 Interface::MemRelinquish => {}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200845 Interface::MemReclaim { handle, flags } => {
846 let handle_regs: [u32; 2] = handle.into();
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200847 a[1] = handle_regs[0] as u64;
848 a[2] = handle_regs[1] as u64;
849 a[3] = flags as u64;
850 }
851 Interface::MemPermGet {
852 base_addr,
853 is_32bit,
854 } => {
855 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200856 a[1] = base_addr & u32::MAX as u64;
857 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200858 a[1] = base_addr;
859 }
860 }
861 Interface::MemPermSet {
862 base_addr,
863 page_cnt,
864 mem_perm,
865 is_32bit,
866 } => {
867 a[2] = page_cnt as u64;
868 a[3] = mem_perm as u64;
869
870 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200871 a[1] = base_addr & u32::MAX as u64;
872 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200873 a[1] = base_addr;
874 }
875 }
876 Interface::ConsoleLog {
877 char_cnt,
878 char_lists,
879 is_32bit,
880 } => {
881 a[1] = char_cnt as u64;
882 if is_32bit {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200883 a[2] = char_lists[0] & u32::MAX as u64;
884 a[3] = char_lists[1] & u32::MAX as u64;
885 a[4] = char_lists[2] & u32::MAX as u64;
886 a[5] = char_lists[3] & u32::MAX as u64;
887 a[6] = char_lists[4] & u32::MAX as u64;
888 a[7] = char_lists[5] & u32::MAX as u64;
889 } else {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200890 a[2] = char_lists[0];
891 a[3] = char_lists[1];
892 a[4] = char_lists[2];
893 a[5] = char_lists[3];
894 a[6] = char_lists[4];
895 a[7] = char_lists[5];
896 }
897 }
898 }
899 }
900
901 /// Helper function to create an FFA_SUCCESS interface without any arguments
902 pub fn success32_noargs() -> Self {
903 Self::Success {
904 target_info: 0,
905 result_regs: [0, 0, 0, 0, 0, 0],
906 is_32bit: true,
907 }
908 }
909}
910
Andrew Walbran19970ba2024-11-25 15:35:00 +0000911#[derive(Clone, Copy, Eq, PartialEq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200912pub struct Version(pub u16, pub u16);
913
914impl From<u32> for Version {
915 fn from(val: u32) -> Self {
916 Self((val >> 16) as u16, val as u16)
917 }
918}
919
920impl From<Version> for u32 {
921 fn from(v: Version) -> Self {
922 (v.0 as u32) << 16 | v.1 as u32
923 }
924}
925
Andrew Walbran19970ba2024-11-25 15:35:00 +0000926impl Display for Version {
927 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
928 write!(f, "{}.{}", self.0, self.1)
929 }
930}
931
932impl Debug for Version {
933 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
934 Display::fmt(self, f)
935 }
936}
937
Balint Dobszayc8802492025-01-15 18:11:39 +0100938pub const CONSOLE_LOG_32_MAX_MSG_LEN: usize = 24;
939pub const CONSOLE_LOG_64_MAX_MSG_LEN: usize = 48;
940
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200941pub fn parse_console_log(
942 char_cnt: u32,
943 char_lists: &[u64; 6],
944 is_32bit: bool,
Balint Dobszayc8802492025-01-15 18:11:39 +0100945 log_bytes: &mut [u8],
946) -> Result<(), Error> {
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200947 const CHAR_COUNT_MASK: u32 = 0xff;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200948
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200949 let char_count = (char_cnt & CHAR_COUNT_MASK) as usize;
950 let (max_length, reg_size) = if is_32bit {
Balint Dobszayc8802492025-01-15 18:11:39 +0100951 (CONSOLE_LOG_32_MAX_MSG_LEN, 4)
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200952 } else {
Balint Dobszayc8802492025-01-15 18:11:39 +0100953 (CONSOLE_LOG_64_MAX_MSG_LEN, 8)
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200954 };
955
956 if char_count < 1 || char_count > max_length {
957 return Err(Error::InvalidParameters);
958 }
959
960 for i in 0..=5 {
Balint Dobszayc8802492025-01-15 18:11:39 +0100961 log_bytes[reg_size * i..reg_size * (i + 1)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200962 .copy_from_slice(&char_lists[i].to_le_bytes()[0..reg_size]);
963 }
964
Balint Dobszayc8802492025-01-15 18:11:39 +0100965 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200966}