blob: 53c1cb8374578430e716c0b25421a3a5bbcd45e2 [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)]
Balint Dobszaya5846852025-02-26 15:38:53 +01005#![deny(clippy::undocumented_unsafe_blocks)]
6#![deny(unsafe_op_in_unsafe_fn)]
7#![doc = include_str!("../README.md")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02008
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;
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010015mod ffa_v1_1;
Balint Dobszayde0dc802025-02-28 14:16:52 +010016mod ffa_v1_2;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020017pub mod memory_management;
18pub mod partition_info;
19
Balint Dobszaya5846852025-02-26 15:38:53 +010020/// Constant for 4K page size. On many occasions the FF-A spec defines memory size as count of 4K
21/// pages, regardless of the current translation granule.
Balint Dobszay3aad9572025-01-17 16:54:11 +010022pub const FFA_PAGE_SIZE_4K: usize = 4096;
23
Balint Dobszaya5846852025-02-26 15:38:53 +010024/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
25/// with the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +010026#[derive(Debug, Error)]
27pub enum Error {
28 #[error("Unrecognised FF-A function ID {0}")]
29 UnrecognisedFunctionId(u32),
30 #[error("Unrecognised FF-A feature ID {0}")]
31 UnrecognisedFeatureId(u8),
32 #[error("Unrecognised FF-A error code {0}")]
33 UnrecognisedErrorCode(i32),
34}
35
36impl From<Error> for FfaError {
37 fn from(value: Error) -> Self {
38 match value {
39 Error::UnrecognisedFunctionId(_) | Error::UnrecognisedFeatureId(_) => {
40 Self::NotSupported
41 }
42 Error::UnrecognisedErrorCode(_) => Self::InvalidParameters,
43 }
44 }
45}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020046
Balint Dobszaya5846852025-02-26 15:38:53 +010047/// An FF-A instance is a valid combination of two FF-A components at an exception level boundary.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020048#[derive(PartialEq, Clone, Copy)]
49pub enum Instance {
Balint Dobszaya5846852025-02-26 15:38:53 +010050 /// The instance between the SPMC and SPMD.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020051 SecurePhysical,
Balint Dobszaya5846852025-02-26 15:38:53 +010052 /// The instance between the SPMC and a physical SP (contains the SP's endpoint ID).
Balint Dobszay5bf492f2024-07-29 17:21:32 +020053 SecureVirtual(u16),
54}
55
Balint Dobszaya5846852025-02-26 15:38:53 +010056/// Function IDs of the various FF-A interfaces.
Andrew Walbran969b9252024-11-25 15:35:42 +000057#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay3aad9572025-01-17 16:54:11 +010058#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFunctionId))]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020059#[repr(u32)]
60pub enum FuncId {
61 Error = 0x84000060,
62 Success32 = 0x84000061,
63 Success64 = 0xc4000061,
64 Interrupt = 0x84000062,
65 Version = 0x84000063,
66 Features = 0x84000064,
67 RxAcquire = 0x84000084,
68 RxRelease = 0x84000065,
69 RxTxMap32 = 0x84000066,
70 RxTxMap64 = 0xc4000066,
71 RxTxUnmap = 0x84000067,
72 PartitionInfoGet = 0x84000068,
73 IdGet = 0x84000069,
74 SpmIdGet = 0x84000085,
75 MsgWait = 0x8400006b,
76 Yield = 0x8400006c,
77 Run = 0x8400006d,
78 NormalWorldResume = 0x8400007c,
79 MsgSend2 = 0x84000086,
80 MsgSendDirectReq32 = 0x8400006f,
81 MsgSendDirectReq64 = 0xc400006f,
Balint Dobszayde0dc802025-02-28 14:16:52 +010082 MsgSendDirectReq64_2 = 0xc400008d,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020083 MsgSendDirectResp32 = 0x84000070,
84 MsgSendDirectResp64 = 0xc4000070,
Balint Dobszayde0dc802025-02-28 14:16:52 +010085 MsgSendDirectResp64_2 = 0xc400008e,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020086 MemDonate32 = 0x84000071,
87 MemDonate64 = 0xc4000071,
88 MemLend32 = 0x84000072,
89 MemLend64 = 0xc4000072,
90 MemShare32 = 0x84000073,
91 MemShare64 = 0xc4000073,
92 MemRetrieveReq32 = 0x84000074,
93 MemRetrieveReq64 = 0xc4000074,
94 MemRetrieveResp = 0x84000075,
95 MemRelinquish = 0x84000076,
96 MemReclaim = 0x84000077,
97 MemPermGet32 = 0x84000088,
98 MemPermGet64 = 0xc4000088,
99 MemPermSet32 = 0x84000089,
100 MemPermSet64 = 0xc4000089,
101 ConsoleLog32 = 0x8400008a,
102 ConsoleLog64 = 0xc400008a,
103}
104
Balint Dobszayde0dc802025-02-28 14:16:52 +0100105impl FuncId {
106 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
107 pub fn is_32bit(&self) -> bool {
108 u32::from(*self) & (1 << 30) != 0
109 }
110}
111
Balint Dobszaya5846852025-02-26 15:38:53 +0100112/// Error status codes used by the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100113#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
114#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
115#[repr(i32)]
116pub enum FfaError {
117 #[error("Not supported")]
118 NotSupported = -1,
119 #[error("Invalid parameters")]
120 InvalidParameters = -2,
121 #[error("No memory")]
122 NoMemory = -3,
123 #[error("Busy")]
124 Busy = -4,
125 #[error("Interrupted")]
126 Interrupted = -5,
127 #[error("Denied")]
128 Denied = -6,
129 #[error("Retry")]
130 Retry = -7,
131 #[error("Aborted")]
132 Aborted = -8,
133 #[error("No data")]
134 NoData = -9,
135}
136
Balint Dobszaya5846852025-02-26 15:38:53 +0100137/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200138#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Balint Dobszay3aad9572025-01-17 16:54:11 +0100139pub struct TargetInfo {
140 pub endpoint_id: u16,
141 pub vcpu_id: u16,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200142}
143
Balint Dobszay3aad9572025-01-17 16:54:11 +0100144impl From<u32> for TargetInfo {
145 fn from(value: u32) -> Self {
146 Self {
147 endpoint_id: (value >> 16) as u16,
148 vcpu_id: value as u16,
149 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200150 }
151}
152
Balint Dobszay3aad9572025-01-17 16:54:11 +0100153impl From<TargetInfo> for u32 {
154 fn from(value: TargetInfo) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100155 ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
Andrew Walbran0d315812024-11-25 15:36:36 +0000156 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100157}
Andrew Walbran0d315812024-11-25 15:36:36 +0000158
Balint Dobszaya5846852025-02-26 15:38:53 +0100159/// Arguments for the `FFA_SUCCESS` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100160#[derive(Debug, Eq, PartialEq, Clone, Copy)]
161pub enum SuccessArgs {
162 Result32([u32; 6]),
163 Result64([u64; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100164 Result64_2([u64; 16]),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200165}
166
Balint Dobszaya5846852025-02-26 15:38:53 +0100167/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100168#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200169pub struct Version(pub u16, pub u16);
170
171impl From<u32> for Version {
172 fn from(val: u32) -> Self {
173 Self((val >> 16) as u16, val as u16)
174 }
175}
176
177impl From<Version> for u32 {
178 fn from(v: Version) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100179 ((v.0 as u32) << 16) | v.1 as u32
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200180 }
181}
182
Andrew Walbran19970ba2024-11-25 15:35:00 +0000183impl Display for Version {
184 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
185 write!(f, "{}.{}", self.0, self.1)
186 }
187}
188
189impl Debug for Version {
190 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
191 Display::fmt(self, f)
192 }
193}
194
Balint Dobszaya5846852025-02-26 15:38:53 +0100195/// Feature IDs used by the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100196#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
197#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
198#[repr(u8)]
199pub enum FeatureId {
200 NotificationPendingInterrupt = 0x1,
201 ScheduleReceiverInterrupt = 0x2,
202 ManagedExitInterrupt = 0x3,
203}
Balint Dobszayc8802492025-01-15 18:11:39 +0100204
Balint Dobszaya5846852025-02-26 15:38:53 +0100205/// Arguments for the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100206#[derive(Debug, Eq, PartialEq, Clone, Copy)]
207pub enum Feature {
208 FuncId(FuncId),
209 FeatureId(FeatureId),
210}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200211
Balint Dobszay3aad9572025-01-17 16:54:11 +0100212impl TryFrom<u32> for Feature {
213 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200214
Balint Dobszay3aad9572025-01-17 16:54:11 +0100215 fn try_from(value: u32) -> Result<Self, Self::Error> {
216 let res = if (value >> 31) & 1 == 1 {
217 Self::FuncId(value.try_into()?)
218 } else {
219 Self::FeatureId((value as u8).try_into()?)
220 };
221
222 Ok(res)
223 }
224}
225
226impl From<Feature> for u32 {
227 fn from(value: Feature) -> Self {
228 match value {
229 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
230 Feature::FeatureId(feature_id) => feature_id as u32,
231 }
232 }
233}
234
Balint Dobszaya5846852025-02-26 15:38:53 +0100235/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100236#[derive(Debug, Eq, PartialEq, Clone, Copy)]
237pub enum RxTxAddr {
238 Addr32 { rx: u32, tx: u32 },
239 Addr64 { rx: u64, tx: u64 },
240}
241
Balint Dobszaya5846852025-02-26 15:38:53 +0100242/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100243#[derive(Debug, Eq, PartialEq, Clone, Copy)]
244pub enum DirectMsgArgs {
245 Args32([u32; 5]),
246 Args64([u64; 5]),
247}
248
Balint Dobszayde0dc802025-02-28 14:16:52 +0100249/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
250#[derive(Debug, Eq, PartialEq, Clone, Copy)]
251pub struct DirectMsg2Args([u64; 14]);
252
Balint Dobszaya5846852025-02-26 15:38:53 +0100253/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
254/// descriptor. Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX
255/// buffer is not used to transmit the transaction descriptor.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100256#[derive(Debug, Eq, PartialEq, Clone, Copy)]
257pub enum MemOpBuf {
258 Buf32 { addr: u32, page_cnt: u32 },
259 Buf64 { addr: u64, page_cnt: u32 },
260}
261
Balint Dobszaya5846852025-02-26 15:38:53 +0100262/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100263#[derive(Debug, Eq, PartialEq, Clone, Copy)]
264pub enum MemAddr {
265 Addr32(u32),
266 Addr64(u64),
267}
268
Balint Dobszayde0dc802025-02-28 14:16:52 +0100269/// Argument for the `FFA_CONSOLE_LOG` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100270#[derive(Debug, Eq, PartialEq, Clone, Copy)]
271pub enum ConsoleLogChars {
272 Reg32([u32; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100273 Reg64([u64; 16]),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100274}
275
Balint Dobszaya5846852025-02-26 15:38:53 +0100276/// FF-A "message types", the terminology used by the spec is "interfaces". The interfaces are used
277/// by FF-A components for communication at an FF-A instance. The spec also describes the valid FF-A
278/// instances and conduits for each interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100279#[derive(Debug, Eq, PartialEq, Clone, Copy)]
280pub enum Interface {
281 Error {
282 target_info: TargetInfo,
283 error_code: FfaError,
284 },
285 Success {
286 target_info: u32,
287 args: SuccessArgs,
288 },
289 Interrupt {
290 target_info: TargetInfo,
291 interrupt_id: u32,
292 },
293 Version {
294 input_version: Version,
295 },
296 VersionOut {
297 output_version: Version,
298 },
299 Features {
300 feat_id: Feature,
301 input_properties: u32,
302 },
303 RxAcquire {
304 vm_id: u16,
305 },
306 RxRelease {
307 vm_id: u16,
308 },
309 RxTxMap {
310 addr: RxTxAddr,
311 page_cnt: u32,
312 },
313 RxTxUnmap {
314 id: u16,
315 },
316 PartitionInfoGet {
317 uuid: Uuid,
318 flags: u32,
319 },
320 IdGet,
321 SpmIdGet,
322 MsgWait,
323 Yield,
324 Run {
325 target_info: TargetInfo,
326 },
327 NormalWorldResume,
328 MsgSend2 {
329 sender_vm_id: u16,
330 flags: u32,
331 },
332 MsgSendDirectReq {
333 src_id: u16,
334 dst_id: u16,
335 flags: u32,
336 args: DirectMsgArgs,
337 },
338 MsgSendDirectResp {
339 src_id: u16,
340 dst_id: u16,
341 flags: u32,
342 args: DirectMsgArgs,
343 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100344 MsgSendDirectReq2 {
345 src_id: u16,
346 dst_id: u16,
347 uuid: Uuid,
348 args: DirectMsg2Args,
349 },
350 MsgSendDirectResp2 {
351 src_id: u16,
352 dst_id: u16,
353 args: DirectMsg2Args,
354 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100355 MemDonate {
356 total_len: u32,
357 frag_len: u32,
358 buf: Option<MemOpBuf>,
359 },
360 MemLend {
361 total_len: u32,
362 frag_len: u32,
363 buf: Option<MemOpBuf>,
364 },
365 MemShare {
366 total_len: u32,
367 frag_len: u32,
368 buf: Option<MemOpBuf>,
369 },
370 MemRetrieveReq {
371 total_len: u32,
372 frag_len: u32,
373 buf: Option<MemOpBuf>,
374 },
375 MemRetrieveResp {
376 total_len: u32,
377 frag_len: u32,
378 },
379 MemRelinquish,
380 MemReclaim {
381 handle: memory_management::Handle,
382 flags: u32,
383 },
384 MemPermGet {
385 addr: MemAddr,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100386 page_cnt: Option<u32>,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100387 },
388 MemPermSet {
389 addr: MemAddr,
390 page_cnt: u32,
391 mem_perm: u32,
392 },
393 ConsoleLog {
394 char_cnt: u8,
395 char_lists: ConsoleLogChars,
396 },
397}
398
Balint Dobszayde0dc802025-02-28 14:16:52 +0100399impl Interface {
400 /// Returns the function ID for the call, if it has one.
401 pub fn function_id(&self) -> Option<FuncId> {
402 match self {
403 Interface::Error { .. } => Some(FuncId::Error),
404 Interface::Success { args, .. } => match args {
405 SuccessArgs::Result32(..) => Some(FuncId::Success32),
406 SuccessArgs::Result64(..) | SuccessArgs::Result64_2(..) => Some(FuncId::Success64),
407 },
408 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
409 Interface::Version { .. } => Some(FuncId::Version),
410 Interface::VersionOut { .. } => None,
411 Interface::Features { .. } => Some(FuncId::Features),
412 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
413 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
414 Interface::RxTxMap { addr, .. } => match addr {
415 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
416 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
417 },
418 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
419 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
420 Interface::IdGet => Some(FuncId::IdGet),
421 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
422 Interface::MsgWait => Some(FuncId::MsgWait),
423 Interface::Yield => Some(FuncId::Yield),
424 Interface::Run { .. } => Some(FuncId::Run),
425 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
426 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
427 Interface::MsgSendDirectReq { args, .. } => match args {
428 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
429 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
430 },
431 Interface::MsgSendDirectResp { args, .. } => match args {
432 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
433 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
434 },
435 Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
436 Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
437 Interface::MemDonate { buf, .. } => match buf {
438 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
439 _ => Some(FuncId::MemDonate32),
440 },
441 Interface::MemLend { buf, .. } => match buf {
442 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
443 _ => Some(FuncId::MemLend32),
444 },
445 Interface::MemShare { buf, .. } => match buf {
446 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
447 _ => Some(FuncId::MemShare32),
448 },
449 Interface::MemRetrieveReq { buf, .. } => match buf {
450 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
451 _ => Some(FuncId::MemRetrieveReq32),
452 },
453 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
454 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
455 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
456 Interface::MemPermGet { addr, .. } => match addr {
457 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
458 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
459 },
460 Interface::MemPermSet { addr, .. } => match addr {
461 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
462 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
463 },
464 Interface::ConsoleLog { char_lists, .. } => match char_lists {
465 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
466 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
467 },
468 }
469 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100470
Balint Dobszayde0dc802025-02-28 14:16:52 +0100471 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
472 pub fn is_32bit(&self) -> bool {
473 // TODO: self should always have a function ID?
474 self.function_id().unwrap().is_32bit()
475 }
476
477 /// Parse interface from register contents. The caller must ensure that the `regs` argument has
478 /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
479 pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
480 let reg_cnt = regs.len();
481
482 let msg = match reg_cnt {
483 8 => {
484 assert!(version <= Version(1, 1));
485 Interface::unpack_regs8(version, regs.try_into().unwrap())?
486 }
487 18 => {
488 assert!(version >= Version(1, 2));
489 match FuncId::try_from(regs[0] as u32)? {
490 FuncId::ConsoleLog64
491 | FuncId::Success64
492 | FuncId::MsgSendDirectReq64_2
493 | FuncId::MsgSendDirectResp64_2 => {
494 Interface::unpack_regs18(version, regs.try_into().unwrap())?
495 }
496 _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
497 }
498 }
499 _ => panic!(
500 "Invalid number of registers ({}) for FF-A version {}",
501 reg_cnt, version
502 ),
503 };
504
505 Ok(msg)
506 }
507
508 fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100509 let fid = FuncId::try_from(regs[0] as u32)?;
510
511 let msg = match fid {
512 FuncId::Error => Self::Error {
513 target_info: (regs[1] as u32).into(),
514 error_code: FfaError::try_from(regs[2] as i32)?,
515 },
516 FuncId::Success32 => Self::Success {
517 target_info: regs[1] as u32,
518 args: SuccessArgs::Result32([
519 regs[2] as u32,
520 regs[3] as u32,
521 regs[4] as u32,
522 regs[5] as u32,
523 regs[6] as u32,
524 regs[7] as u32,
525 ]),
526 },
527 FuncId::Success64 => Self::Success {
528 target_info: regs[1] as u32,
529 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
530 },
531 FuncId::Interrupt => Self::Interrupt {
532 target_info: (regs[1] as u32).into(),
533 interrupt_id: regs[2] as u32,
534 },
535 FuncId::Version => Self::Version {
536 input_version: (regs[1] as u32).into(),
537 },
538 FuncId::Features => Self::Features {
539 feat_id: (regs[1] as u32).try_into()?,
540 input_properties: regs[2] as u32,
541 },
542 FuncId::RxAcquire => Self::RxAcquire {
543 vm_id: regs[1] as u16,
544 },
545 FuncId::RxRelease => Self::RxRelease {
546 vm_id: regs[1] as u16,
547 },
548 FuncId::RxTxMap32 => {
549 let addr = RxTxAddr::Addr32 {
550 rx: regs[2] as u32,
551 tx: regs[1] as u32,
552 };
553 let page_cnt = regs[3] as u32;
554
555 Self::RxTxMap { addr, page_cnt }
556 }
557 FuncId::RxTxMap64 => {
558 let addr = RxTxAddr::Addr64 {
559 rx: regs[2],
560 tx: regs[1],
561 };
562 let page_cnt = regs[3] as u32;
563
564 Self::RxTxMap { addr, page_cnt }
565 }
566 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
567 FuncId::PartitionInfoGet => {
568 let uuid_words = [
569 regs[1] as u32,
570 regs[2] as u32,
571 regs[3] as u32,
572 regs[4] as u32,
573 ];
574 let mut bytes: [u8; 16] = [0; 16];
575 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
576 bytes[i] = b;
577 }
578 Self::PartitionInfoGet {
579 uuid: Uuid::from_bytes(bytes),
580 flags: regs[5] as u32,
581 }
582 }
583 FuncId::IdGet => Self::IdGet,
584 FuncId::SpmIdGet => Self::SpmIdGet,
585 FuncId::MsgWait => Self::MsgWait,
586 FuncId::Yield => Self::Yield,
587 FuncId::Run => Self::Run {
588 target_info: (regs[1] as u32).into(),
589 },
590 FuncId::NormalWorldResume => Self::NormalWorldResume,
591 FuncId::MsgSend2 => Self::MsgSend2 {
592 sender_vm_id: regs[1] as u16,
593 flags: regs[2] as u32,
594 },
595 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
596 src_id: (regs[1] >> 16) as u16,
597 dst_id: regs[1] as u16,
598 flags: regs[2] as u32,
599 args: DirectMsgArgs::Args32([
600 regs[3] as u32,
601 regs[4] as u32,
602 regs[5] as u32,
603 regs[6] as u32,
604 regs[7] as u32,
605 ]),
606 },
607 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
608 src_id: (regs[1] >> 16) as u16,
609 dst_id: regs[1] as u16,
610 flags: regs[2] as u32,
611 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
612 },
613 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
614 src_id: (regs[1] >> 16) as u16,
615 dst_id: regs[1] as u16,
616 flags: regs[2] as u32,
617 args: DirectMsgArgs::Args32([
618 regs[3] as u32,
619 regs[4] as u32,
620 regs[5] as u32,
621 regs[6] as u32,
622 regs[7] as u32,
623 ]),
624 },
625 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
626 src_id: (regs[1] >> 16) as u16,
627 dst_id: regs[1] as u16,
628 flags: regs[2] as u32,
629 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
630 },
631 FuncId::MemDonate32 => Self::MemDonate {
632 total_len: regs[1] as u32,
633 frag_len: regs[2] as u32,
634 buf: if regs[3] != 0 && regs[4] != 0 {
635 Some(MemOpBuf::Buf32 {
636 addr: regs[3] as u32,
637 page_cnt: regs[4] as u32,
638 })
639 } else {
640 None
641 },
642 },
643 FuncId::MemDonate64 => Self::MemDonate {
644 total_len: regs[1] as u32,
645 frag_len: regs[2] as u32,
646 buf: if regs[3] != 0 && regs[4] != 0 {
647 Some(MemOpBuf::Buf64 {
648 addr: regs[3],
649 page_cnt: regs[4] as u32,
650 })
651 } else {
652 None
653 },
654 },
655 FuncId::MemLend32 => Self::MemLend {
656 total_len: regs[1] as u32,
657 frag_len: regs[2] as u32,
658 buf: if regs[3] != 0 && regs[4] != 0 {
659 Some(MemOpBuf::Buf32 {
660 addr: regs[3] as u32,
661 page_cnt: regs[4] as u32,
662 })
663 } else {
664 None
665 },
666 },
667 FuncId::MemLend64 => Self::MemLend {
668 total_len: regs[1] as u32,
669 frag_len: regs[2] as u32,
670 buf: if regs[3] != 0 && regs[4] != 0 {
671 Some(MemOpBuf::Buf64 {
672 addr: regs[3],
673 page_cnt: regs[4] as u32,
674 })
675 } else {
676 None
677 },
678 },
679 FuncId::MemShare32 => Self::MemShare {
680 total_len: regs[1] as u32,
681 frag_len: regs[2] as u32,
682 buf: if regs[3] != 0 && regs[4] != 0 {
683 Some(MemOpBuf::Buf32 {
684 addr: regs[3] as u32,
685 page_cnt: regs[4] as u32,
686 })
687 } else {
688 None
689 },
690 },
691 FuncId::MemShare64 => Self::MemShare {
692 total_len: regs[1] as u32,
693 frag_len: regs[2] as u32,
694 buf: if regs[3] != 0 && regs[4] != 0 {
695 Some(MemOpBuf::Buf64 {
696 addr: regs[3],
697 page_cnt: regs[4] as u32,
698 })
699 } else {
700 None
701 },
702 },
703 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
704 total_len: regs[1] as u32,
705 frag_len: regs[2] as u32,
706 buf: if regs[3] != 0 && regs[4] != 0 {
707 Some(MemOpBuf::Buf32 {
708 addr: regs[3] as u32,
709 page_cnt: regs[4] as u32,
710 })
711 } else {
712 None
713 },
714 },
715 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
716 total_len: regs[1] as u32,
717 frag_len: regs[2] as u32,
718 buf: if regs[3] != 0 && regs[4] != 0 {
719 Some(MemOpBuf::Buf64 {
720 addr: regs[3],
721 page_cnt: regs[4] as u32,
722 })
723 } else {
724 None
725 },
726 },
727 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
728 total_len: regs[1] as u32,
729 frag_len: regs[2] as u32,
730 },
731 FuncId::MemRelinquish => Self::MemRelinquish,
732 FuncId::MemReclaim => Self::MemReclaim {
733 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
734 flags: regs[3] as u32,
735 },
736 FuncId::MemPermGet32 => Self::MemPermGet {
737 addr: MemAddr::Addr32(regs[1] as u32),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100738 page_cnt: if version >= Version(1, 3) {
739 Some(regs[2] as u32)
740 } else {
741 None
742 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100743 },
744 FuncId::MemPermGet64 => Self::MemPermGet {
745 addr: MemAddr::Addr64(regs[1]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100746 page_cnt: if version >= Version(1, 3) {
747 Some(regs[2] as u32)
748 } else {
749 None
750 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100751 },
752 FuncId::MemPermSet32 => Self::MemPermSet {
753 addr: MemAddr::Addr32(regs[1] as u32),
754 page_cnt: regs[2] as u32,
755 mem_perm: regs[3] as u32,
756 },
757 FuncId::MemPermSet64 => Self::MemPermSet {
758 addr: MemAddr::Addr64(regs[1]),
759 page_cnt: regs[2] as u32,
760 mem_perm: regs[3] as u32,
761 },
762 FuncId::ConsoleLog32 => Self::ConsoleLog {
763 char_cnt: regs[1] as u8,
764 char_lists: ConsoleLogChars::Reg32([
765 regs[2] as u32,
766 regs[3] as u32,
767 regs[4] as u32,
768 regs[5] as u32,
769 regs[6] as u32,
770 regs[7] as u32,
771 ]),
772 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100773 _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100774 };
775
776 Ok(msg)
777 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100778
Balint Dobszayde0dc802025-02-28 14:16:52 +0100779 fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
780 assert!(version >= Version(1, 2));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200781
Balint Dobszayde0dc802025-02-28 14:16:52 +0100782 let fid = FuncId::try_from(regs[0] as u32)?;
783
784 let msg = match fid {
785 FuncId::Success64 => Self::Success {
786 target_info: regs[1] as u32,
787 args: SuccessArgs::Result64_2(regs[2..18].try_into().unwrap()),
788 },
789 FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
790 src_id: (regs[1] >> 16) as u16,
791 dst_id: regs[1] as u16,
792 uuid: Uuid::from_u64_pair(regs[2], regs[3]),
793 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
794 },
795 FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
796 src_id: (regs[1] >> 16) as u16,
797 dst_id: regs[1] as u16,
798 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
799 },
800 FuncId::ConsoleLog64 => Self::ConsoleLog {
801 char_cnt: regs[1] as u8,
802 char_lists: ConsoleLogChars::Reg64(regs[2..18].try_into().unwrap()),
803 },
804 _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
805 };
806
807 Ok(msg)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100808 }
809
Balint Dobszaya5846852025-02-26 15:38:53 +0100810 /// Create register contents for an interface.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100811 pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
812 let reg_cnt = regs.len();
813
814 match reg_cnt {
815 8 => {
816 assert!(version <= Version(1, 1));
817 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
818 }
819 18 => {
820 assert!(version >= Version(1, 2));
821
822 match self {
823 Interface::ConsoleLog {
824 char_lists: ConsoleLogChars::Reg64(_),
825 ..
826 }
827 | Interface::Success {
828 args: SuccessArgs::Result64_2(_),
829 ..
830 }
831 | Interface::MsgSendDirectReq2 { .. }
832 | Interface::MsgSendDirectResp2 { .. } => {
833 self.pack_regs18(version, regs.try_into().unwrap());
834 }
835 _ => {
836 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
837 }
838 }
839 }
840 _ => panic!("Invalid number of registers {}", reg_cnt),
841 }
842 }
843
844 fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100845 a.fill(0);
846 if let Some(function_id) = self.function_id() {
847 a[0] = function_id as u64;
848 }
849
850 match *self {
851 Interface::Error {
852 target_info,
853 error_code,
854 } => {
855 a[1] = u32::from(target_info).into();
856 a[2] = (error_code as u32).into();
857 }
858 Interface::Success { target_info, args } => {
859 a[1] = target_info.into();
860 match args {
861 SuccessArgs::Result32(regs) => {
862 a[2] = regs[0].into();
863 a[3] = regs[1].into();
864 a[4] = regs[2].into();
865 a[5] = regs[3].into();
866 a[6] = regs[4].into();
867 a[7] = regs[5].into();
868 }
869 SuccessArgs::Result64(regs) => {
870 a[2] = regs[0];
871 a[3] = regs[1];
872 a[4] = regs[2];
873 a[5] = regs[3];
874 a[6] = regs[4];
875 a[7] = regs[5];
876 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100877 _ => panic!("{:#x?} requires 18 registers", args),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100878 }
879 }
880 Interface::Interrupt {
881 target_info,
882 interrupt_id,
883 } => {
884 a[1] = u32::from(target_info).into();
885 a[2] = interrupt_id.into();
886 }
887 Interface::Version { input_version } => {
888 a[1] = u32::from(input_version).into();
889 }
890 Interface::VersionOut { output_version } => {
891 a[0] = u32::from(output_version).into();
892 }
893 Interface::Features {
894 feat_id,
895 input_properties,
896 } => {
897 a[1] = u32::from(feat_id).into();
898 a[2] = input_properties.into();
899 }
900 Interface::RxAcquire { vm_id } => {
901 a[1] = vm_id.into();
902 }
903 Interface::RxRelease { vm_id } => {
904 a[1] = vm_id.into();
905 }
906 Interface::RxTxMap { addr, page_cnt } => {
907 match addr {
908 RxTxAddr::Addr32 { rx, tx } => {
909 a[1] = tx.into();
910 a[2] = rx.into();
911 }
912 RxTxAddr::Addr64 { rx, tx } => {
913 a[1] = tx;
914 a[2] = rx;
915 }
916 }
917 a[3] = page_cnt.into();
918 }
919 Interface::RxTxUnmap { id } => {
920 a[1] = id.into();
921 }
922 Interface::PartitionInfoGet { uuid, flags } => {
923 let bytes = uuid.into_bytes();
924 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
925 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
926 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
927 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
928 a[5] = flags.into();
929 }
930 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
931 Interface::Run { target_info } => {
932 a[1] = u32::from(target_info).into();
933 }
934 Interface::NormalWorldResume => {}
935 Interface::MsgSend2 {
936 sender_vm_id,
937 flags,
938 } => {
939 a[1] = sender_vm_id.into();
940 a[2] = flags.into();
941 }
942 Interface::MsgSendDirectReq {
943 src_id,
944 dst_id,
945 flags,
946 args,
947 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100948 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100949 a[2] = flags.into();
950 match args {
951 DirectMsgArgs::Args32(args) => {
952 a[3] = args[0].into();
953 a[4] = args[1].into();
954 a[5] = args[2].into();
955 a[6] = args[3].into();
956 a[7] = args[4].into();
957 }
958 DirectMsgArgs::Args64(args) => {
959 a[3] = args[0];
960 a[4] = args[1];
961 a[5] = args[2];
962 a[6] = args[3];
963 a[7] = args[4];
964 }
965 }
966 }
967 Interface::MsgSendDirectResp {
968 src_id,
969 dst_id,
970 flags,
971 args,
972 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100973 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100974 a[2] = flags.into();
975 match args {
976 DirectMsgArgs::Args32(args) => {
977 a[3] = args[0].into();
978 a[4] = args[1].into();
979 a[5] = args[2].into();
980 a[6] = args[3].into();
981 a[7] = args[4].into();
982 }
983 DirectMsgArgs::Args64(args) => {
984 a[3] = args[0];
985 a[4] = args[1];
986 a[5] = args[2];
987 a[6] = args[3];
988 a[7] = args[4];
989 }
990 }
991 }
992 Interface::MemDonate {
993 total_len,
994 frag_len,
995 buf,
996 } => {
997 a[1] = total_len.into();
998 a[2] = frag_len.into();
999 (a[3], a[4]) = match buf {
1000 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1001 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1002 None => (0, 0),
1003 };
1004 }
1005 Interface::MemLend {
1006 total_len,
1007 frag_len,
1008 buf,
1009 } => {
1010 a[1] = total_len.into();
1011 a[2] = frag_len.into();
1012 (a[3], a[4]) = match buf {
1013 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1014 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1015 None => (0, 0),
1016 };
1017 }
1018 Interface::MemShare {
1019 total_len,
1020 frag_len,
1021 buf,
1022 } => {
1023 a[1] = total_len.into();
1024 a[2] = frag_len.into();
1025 (a[3], a[4]) = match buf {
1026 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1027 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1028 None => (0, 0),
1029 };
1030 }
1031 Interface::MemRetrieveReq {
1032 total_len,
1033 frag_len,
1034 buf,
1035 } => {
1036 a[1] = total_len.into();
1037 a[2] = frag_len.into();
1038 (a[3], a[4]) = match buf {
1039 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1040 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1041 None => (0, 0),
1042 };
1043 }
1044 Interface::MemRetrieveResp {
1045 total_len,
1046 frag_len,
1047 } => {
1048 a[1] = total_len.into();
1049 a[2] = frag_len.into();
1050 }
1051 Interface::MemRelinquish => {}
1052 Interface::MemReclaim { handle, flags } => {
1053 let handle_regs: [u32; 2] = handle.into();
1054 a[1] = handle_regs[0].into();
1055 a[2] = handle_regs[1].into();
1056 a[3] = flags.into();
1057 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001058 Interface::MemPermGet { addr, page_cnt } => {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001059 a[1] = match addr {
1060 MemAddr::Addr32(addr) => addr.into(),
1061 MemAddr::Addr64(addr) => addr,
1062 };
Balint Dobszayde0dc802025-02-28 14:16:52 +01001063 a[2] = if version >= Version(1, 3) {
1064 page_cnt.unwrap().into()
1065 } else {
1066 assert!(page_cnt.is_none());
1067 0
1068 }
Balint Dobszay3aad9572025-01-17 16:54:11 +01001069 }
1070 Interface::MemPermSet {
1071 addr,
1072 page_cnt,
1073 mem_perm,
1074 } => {
1075 a[1] = match addr {
1076 MemAddr::Addr32(addr) => addr.into(),
1077 MemAddr::Addr64(addr) => addr,
1078 };
1079 a[2] = page_cnt.into();
1080 a[3] = mem_perm.into();
1081 }
1082 Interface::ConsoleLog {
1083 char_cnt,
1084 char_lists,
1085 } => {
1086 a[1] = char_cnt.into();
1087 match char_lists {
1088 ConsoleLogChars::Reg32(regs) => {
1089 a[2] = regs[0].into();
1090 a[3] = regs[1].into();
1091 a[4] = regs[2].into();
1092 a[5] = regs[3].into();
1093 a[6] = regs[4].into();
1094 a[7] = regs[5].into();
1095 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001096 _ => panic!("{:#x?} requires 18 registers", char_lists),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001097 }
1098 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001099 _ => panic!("{:#x?} requires 18 registers", self),
1100 }
1101 }
1102
1103 fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
1104 assert!(version >= Version(1, 2));
1105
1106 a.fill(0);
1107 if let Some(function_id) = self.function_id() {
1108 a[0] = function_id as u64;
1109 }
1110
1111 match *self {
1112 Interface::Success { target_info, args } => {
1113 a[1] = target_info.into();
1114 match args {
1115 SuccessArgs::Result64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
1116 _ => panic!("{:#x?} requires 8 registers", args),
1117 }
1118 }
1119 Interface::MsgSendDirectReq2 {
1120 src_id,
1121 dst_id,
1122 uuid,
1123 args,
1124 } => {
1125 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1126 (a[2], a[3]) = uuid.as_u64_pair();
1127 a[4..18].copy_from_slice(&args.0[..14]);
1128 }
1129 Interface::MsgSendDirectResp2 {
1130 src_id,
1131 dst_id,
1132 args,
1133 } => {
1134 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1135 a[2] = 0;
1136 a[3] = 0;
1137 a[4..18].copy_from_slice(&args.0[..14]);
1138 }
1139 Interface::ConsoleLog {
1140 char_cnt,
1141 char_lists,
1142 } => {
1143 a[1] = char_cnt.into();
1144 match char_lists {
1145 ConsoleLogChars::Reg64(regs) => a[2..18].copy_from_slice(&regs[..16]),
1146 _ => panic!("{:#x?} requires 8 registers", char_lists),
1147 }
1148 }
1149 _ => panic!("{:#x?} requires 8 registers", self),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001150 }
1151 }
1152
Balint Dobszaya5846852025-02-26 15:38:53 +01001153 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001154 pub fn success32_noargs() -> Self {
1155 Self::Success {
1156 target_info: 0,
1157 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1158 }
1159 }
1160
Balint Dobszaya5846852025-02-26 15:38:53 +01001161 /// Helper function to create an `FFA_ERROR` interface with an error code.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001162 pub fn error(error_code: FfaError) -> Self {
1163 Self::Error {
1164 target_info: TargetInfo {
1165 endpoint_id: 0,
1166 vcpu_id: 0,
1167 },
1168 error_code,
1169 }
1170 }
1171}
1172
Balint Dobszaya5846852025-02-26 15:38:53 +01001173/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
1174pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
Balint Dobszayde0dc802025-02-28 14:16:52 +01001175/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message.
1176pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 128;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001177
Balint Dobszaya5846852025-02-26 15:38:53 +01001178/// Helper function to convert the "Tightly packed list of characters" format used by the
1179/// `FFA_CONSOLE_LOG` interface into a byte slice.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001180pub fn parse_console_log(
1181 char_cnt: u8,
1182 char_lists: &ConsoleLogChars,
1183 log_bytes: &mut [u8],
1184) -> Result<(), FfaError> {
1185 match char_lists {
1186 ConsoleLogChars::Reg32(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001187 if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001188 return Err(FfaError::InvalidParameters);
1189 }
1190 for (i, reg) in regs.iter().enumerate() {
1191 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1192 }
1193 }
1194 ConsoleLogChars::Reg64(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001195 if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001196 return Err(FfaError::InvalidParameters);
1197 }
1198 for (i, reg) in regs.iter().enumerate() {
1199 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1200 }
1201 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001202 }
1203
Balint Dobszayc8802492025-01-15 18:11:39 +01001204 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001205}