blob: 48264b67488e1aecef993ca2dba9bde9edbc1033 [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),
Tomás González4d5b0ba2025-03-03 17:15:55 +000034 #[error("Unrecognised FF-A Framework Message {0}")]
35 UnrecognisedFwkMsg(u32),
Tomás González092202a2025-03-05 11:56:45 +000036 #[error("Invalid FF-A Msg Wait Flag {0}")]
37 InvalidMsgWaitFlag(u32),
Tomás González4d5b0ba2025-03-03 17:15:55 +000038 #[error("Unrecognised VM availability status {0}")]
39 UnrecognisedVmAvailabilityStatus(i32),
40 #[error("Unrecognised FF-A Warm Boot Type {0}")]
41 UnrecognisedWarmBootType(u32),
42 #[error("Invalid version {0}")]
43 InvalidVersion(u32),
Balint Dobszay3aad9572025-01-17 16:54:11 +010044}
45
46impl From<Error> for FfaError {
47 fn from(value: Error) -> Self {
48 match value {
49 Error::UnrecognisedFunctionId(_) | Error::UnrecognisedFeatureId(_) => {
50 Self::NotSupported
51 }
Tomás González4d5b0ba2025-03-03 17:15:55 +000052 Error::UnrecognisedErrorCode(_)
53 | Error::UnrecognisedFwkMsg(_)
54 | Error::InvalidVersion(_)
Tomás González092202a2025-03-05 11:56:45 +000055 | Error::InvalidMsgWaitFlag(_)
Tomás González4d5b0ba2025-03-03 17:15:55 +000056 | Error::UnrecognisedVmAvailabilityStatus(_)
57 | Error::UnrecognisedWarmBootType(_) => Self::InvalidParameters,
Balint Dobszay3aad9572025-01-17 16:54:11 +010058 }
59 }
60}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020061
Balint Dobszaya5846852025-02-26 15:38:53 +010062/// 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 +020063#[derive(PartialEq, Clone, Copy)]
64pub enum Instance {
Balint Dobszaya5846852025-02-26 15:38:53 +010065 /// The instance between the SPMC and SPMD.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020066 SecurePhysical,
Balint Dobszaya5846852025-02-26 15:38:53 +010067 /// The instance between the SPMC and a physical SP (contains the SP's endpoint ID).
Balint Dobszay5bf492f2024-07-29 17:21:32 +020068 SecureVirtual(u16),
69}
70
Balint Dobszaya5846852025-02-26 15:38:53 +010071/// Function IDs of the various FF-A interfaces.
Andrew Walbran969b9252024-11-25 15:35:42 +000072#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay3aad9572025-01-17 16:54:11 +010073#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFunctionId))]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020074#[repr(u32)]
75pub enum FuncId {
76 Error = 0x84000060,
77 Success32 = 0x84000061,
78 Success64 = 0xc4000061,
79 Interrupt = 0x84000062,
80 Version = 0x84000063,
81 Features = 0x84000064,
82 RxAcquire = 0x84000084,
83 RxRelease = 0x84000065,
84 RxTxMap32 = 0x84000066,
85 RxTxMap64 = 0xc4000066,
86 RxTxUnmap = 0x84000067,
87 PartitionInfoGet = 0x84000068,
Balint Dobszaye6aa4862025-02-28 16:37:56 +010088 PartitionInfoGetRegs = 0xc400008b,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020089 IdGet = 0x84000069,
90 SpmIdGet = 0x84000085,
Balint Dobszaye6aa4862025-02-28 16:37:56 +010091 ConsoleLog32 = 0x8400008a,
92 ConsoleLog64 = 0xc400008a,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020093 MsgWait = 0x8400006b,
94 Yield = 0x8400006c,
95 Run = 0x8400006d,
96 NormalWorldResume = 0x8400007c,
97 MsgSend2 = 0x84000086,
98 MsgSendDirectReq32 = 0x8400006f,
99 MsgSendDirectReq64 = 0xc400006f,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100100 MsgSendDirectReq64_2 = 0xc400008d,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200101 MsgSendDirectResp32 = 0x84000070,
102 MsgSendDirectResp64 = 0xc4000070,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100103 MsgSendDirectResp64_2 = 0xc400008e,
Balint Dobszaye6aa4862025-02-28 16:37:56 +0100104 NotificationBitmapCreate = 0x8400007d,
105 NotificationBitmapDestroy = 0x8400007e,
106 NotificationBind = 0x8400007f,
107 NotificationUnbind = 0x84000080,
108 NotificationSet = 0x84000081,
109 NotificationGet = 0x84000082,
110 NotificationInfoGet32 = 0x84000083,
111 NotificationInfoGet64 = 0xc4000083,
112 El3IntrHandle = 0x8400008c,
Tomás González17b92442025-03-10 16:45:04 +0000113 SecondaryEpRegister32 = 0x84000087,
114 SecondaryEpRegister64 = 0xc4000087,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200115 MemDonate32 = 0x84000071,
116 MemDonate64 = 0xc4000071,
117 MemLend32 = 0x84000072,
118 MemLend64 = 0xc4000072,
119 MemShare32 = 0x84000073,
120 MemShare64 = 0xc4000073,
121 MemRetrieveReq32 = 0x84000074,
122 MemRetrieveReq64 = 0xc4000074,
123 MemRetrieveResp = 0x84000075,
124 MemRelinquish = 0x84000076,
125 MemReclaim = 0x84000077,
126 MemPermGet32 = 0x84000088,
127 MemPermGet64 = 0xc4000088,
128 MemPermSet32 = 0x84000089,
129 MemPermSet64 = 0xc4000089,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200130}
131
Balint Dobszayde0dc802025-02-28 14:16:52 +0100132impl FuncId {
133 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
134 pub fn is_32bit(&self) -> bool {
135 u32::from(*self) & (1 << 30) != 0
136 }
137}
138
Balint Dobszaya5846852025-02-26 15:38:53 +0100139/// Error status codes used by the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100140#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
141#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
142#[repr(i32)]
143pub enum FfaError {
144 #[error("Not supported")]
145 NotSupported = -1,
146 #[error("Invalid parameters")]
147 InvalidParameters = -2,
148 #[error("No memory")]
149 NoMemory = -3,
150 #[error("Busy")]
151 Busy = -4,
152 #[error("Interrupted")]
153 Interrupted = -5,
154 #[error("Denied")]
155 Denied = -6,
156 #[error("Retry")]
157 Retry = -7,
158 #[error("Aborted")]
159 Aborted = -8,
160 #[error("No data")]
161 NoData = -9,
162}
163
Balint Dobszaya5846852025-02-26 15:38:53 +0100164/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200165#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Balint Dobszay3aad9572025-01-17 16:54:11 +0100166pub struct TargetInfo {
167 pub endpoint_id: u16,
168 pub vcpu_id: u16,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200169}
170
Balint Dobszay3aad9572025-01-17 16:54:11 +0100171impl From<u32> for TargetInfo {
172 fn from(value: u32) -> Self {
173 Self {
174 endpoint_id: (value >> 16) as u16,
175 vcpu_id: value as u16,
176 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200177 }
178}
179
Balint Dobszay3aad9572025-01-17 16:54:11 +0100180impl From<TargetInfo> for u32 {
181 fn from(value: TargetInfo) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100182 ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
Andrew Walbran0d315812024-11-25 15:36:36 +0000183 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100184}
Andrew Walbran0d315812024-11-25 15:36:36 +0000185
Balint Dobszaya5846852025-02-26 15:38:53 +0100186/// Arguments for the `FFA_SUCCESS` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100187#[derive(Debug, Eq, PartialEq, Clone, Copy)]
188pub enum SuccessArgs {
189 Result32([u32; 6]),
190 Result64([u64; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100191 Result64_2([u64; 16]),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200192}
193
Tomás González17b92442025-03-10 16:45:04 +0000194/// Entrypoint address argument for `FFA_SECONDARY_EP_REGISTER` interface.
195#[derive(Debug, Eq, PartialEq, Clone, Copy)]
196pub enum SecondaryEpRegisterAddr {
197 Addr32(u32),
198 Addr64(u64),
199}
200
Balint Dobszaya5846852025-02-26 15:38:53 +0100201/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100202#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200203pub struct Version(pub u16, pub u16);
204
Tomás González1f794352025-03-03 16:47:06 +0000205impl Version {
Tomás González83146af2025-03-04 11:32:41 +0000206 // The FF-A spec mandates that bit[31] of a version number must be 0
207 const MBZ_BITS: u32 = 1 << 31;
208
Tomás González1f794352025-03-03 16:47:06 +0000209 /// Returns whether the caller's version (self) is compatible with the callee's version (input
210 /// parameter)
211 pub fn is_compatible_to(&self, callee_version: &Version) -> bool {
212 self.0 == callee_version.0 && self.1 <= callee_version.1
213 }
214}
215
Tomás González83146af2025-03-04 11:32:41 +0000216impl TryFrom<u32> for Version {
217 type Error = Error;
218
219 fn try_from(val: u32) -> Result<Self, Self::Error> {
220 if (val & Self::MBZ_BITS) != 0 {
221 Err(Error::InvalidVersion(val))
222 } else {
223 Ok(Self((val >> 16) as u16, val as u16))
224 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200225 }
226}
227
228impl From<Version> for u32 {
229 fn from(v: Version) -> Self {
Tomás González83146af2025-03-04 11:32:41 +0000230 let v_u32 = ((v.0 as u32) << 16) | v.1 as u32;
231 assert!(v_u32 & Version::MBZ_BITS == 0);
232 v_u32
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200233 }
234}
235
Andrew Walbran19970ba2024-11-25 15:35:00 +0000236impl Display for Version {
237 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
238 write!(f, "{}.{}", self.0, self.1)
239 }
240}
241
242impl Debug for Version {
243 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
244 Display::fmt(self, f)
245 }
246}
247
Balint Dobszaya5846852025-02-26 15:38:53 +0100248/// Feature IDs used by the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100249#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
250#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
251#[repr(u8)]
252pub enum FeatureId {
253 NotificationPendingInterrupt = 0x1,
254 ScheduleReceiverInterrupt = 0x2,
255 ManagedExitInterrupt = 0x3,
256}
Balint Dobszayc8802492025-01-15 18:11:39 +0100257
Balint Dobszaya5846852025-02-26 15:38:53 +0100258/// Arguments for the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100259#[derive(Debug, Eq, PartialEq, Clone, Copy)]
260pub enum Feature {
261 FuncId(FuncId),
262 FeatureId(FeatureId),
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100263 Unknown(u32),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100264}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200265
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100266impl From<u32> for Feature {
267 fn from(value: u32) -> Self {
268 // Bit[31] is set for all valid FF-A function IDs so we don't have to check it separately
269 if let Ok(func_id) = value.try_into() {
270 Self::FuncId(func_id)
271 } else if let Ok(feat_id) = (value as u8).try_into() {
272 Self::FeatureId(feat_id)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100273 } else {
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100274 Self::Unknown(value)
275 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100276 }
277}
278
279impl From<Feature> for u32 {
280 fn from(value: Feature) -> Self {
281 match value {
282 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
283 Feature::FeatureId(feature_id) => feature_id as u32,
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100284 Feature::Unknown(id) => panic!("Unknown feature or function ID {:#x?}", id),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100285 }
286 }
287}
288
Balint Dobszaya5846852025-02-26 15:38:53 +0100289/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100290#[derive(Debug, Eq, PartialEq, Clone, Copy)]
291pub enum RxTxAddr {
292 Addr32 { rx: u32, tx: u32 },
293 Addr64 { rx: u64, tx: u64 },
294}
295
Tomás González4d5b0ba2025-03-03 17:15:55 +0000296/// Composite type for capturing success and error return codes for the VM availability messages.
297///
298/// Error codes are handled by the `FfaError` type. Having a separate type for errors helps using
299/// `Result<(), FfaError>`. If a single type would include both success and error values,
300/// then `Err(FfaError::Success)` would be incomprehensible.
301#[derive(Debug, Eq, PartialEq, Clone, Copy)]
302pub enum VmAvailabilityStatus {
303 Success,
304 Error(FfaError),
305}
306
307impl TryFrom<i32> for VmAvailabilityStatus {
308 type Error = Error;
309 fn try_from(value: i32) -> Result<Self, <Self as TryFrom<i32>>::Error> {
310 Ok(match value {
311 0 => Self::Success,
312 error_code => Self::Error(FfaError::try_from(error_code)?),
313 })
314 }
315}
316
317impl From<VmAvailabilityStatus> for i32 {
318 fn from(value: VmAvailabilityStatus) -> Self {
319 match value {
320 VmAvailabilityStatus::Success => 0,
321 VmAvailabilityStatus::Error(error_code) => error_code.into(),
322 }
323 }
324}
325
326/// Arguments for the Power Warm Boot `FFA_MSG_SEND_DIRECT_REQ` interface.
327#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
328#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedWarmBootType))]
329#[repr(u32)]
330pub enum WarmBootType {
331 ExitFromSuspend = 0,
332 ExitFromLowPower = 1,
333}
334
Balint Dobszaya5846852025-02-26 15:38:53 +0100335/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100336#[derive(Debug, Eq, PartialEq, Clone, Copy)]
337pub enum DirectMsgArgs {
338 Args32([u32; 5]),
339 Args64([u64; 5]),
Tomás González4d5b0ba2025-03-03 17:15:55 +0000340 /// Message for forwarding FFA_VERSION call from Normal world to the SPMC
341 VersionReq {
342 version: Version,
343 },
344 /// Response message to forwarded FFA_VERSION call from the Normal world
345 /// Contains the version returned by the SPMC or None
346 VersionResp {
347 version: Option<Version>,
348 },
349 /// Message for a power management operation initiated by a PSCI function
350 PowerPsciReq32 {
351 function_id: u32,
352 // params[i]: Input parameter in w[i] in PSCI function invocation at EL3.
353 params: [u32; 3],
354 },
355 /// Message for a power management operation initiated by a PSCI function
356 PowerPsciReq64 {
357 function_id: u32,
358 // params[i]: Input parameter in x[i] in PSCI function invocation at EL3.
359 params: [u64; 3],
360 },
361 /// Message for a warm boot
362 PowerWarmBootReq {
363 boot_type: WarmBootType,
364 },
365 /// Response message to indicate return status of the last power management request message
366 /// Return error code SUCCESS or DENIED as defined in PSCI spec. Caller is left to do the
367 /// parsing of the return status.
368 PowerPsciResp {
369 // TODO: Use arm-psci crate's return status here.
370 psci_status: i32,
371 },
372 /// Message to signal creation of a VM
373 VmCreated {
374 // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
375 // information associated with the created VM.
376 // The invalid memory region handle must be specified by the Hypervisor if this field is not
377 // used.
378 handle: memory_management::Handle,
379 vm_id: u16,
380 },
381 /// Message to acknowledge creation of a VM
382 VmCreatedAck {
383 sp_status: VmAvailabilityStatus,
384 },
385 /// Message to signal destruction of a VM
386 VmDestructed {
387 // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
388 // information associated with the created VM.
389 // The invalid memory region handle must be specified by the Hypervisor if this field is not
390 // used.
391 handle: memory_management::Handle,
392 vm_id: u16,
393 },
394 /// Message to acknowledge destruction of a VM
395 VmDestructedAck {
396 sp_status: VmAvailabilityStatus,
397 },
398}
399
400impl DirectMsgArgs {
401 // Flags for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
402
403 const FWK_MSG_BITS: u32 = 1 << 31;
404 const VERSION_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1000;
405 const VERSION_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1001;
406 const POWER_PSCI_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS;
407 const POWER_WARM_BOOT_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0001;
408 const POWER_PSCI_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0010;
409 const VM_CREATED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0100;
410 const VM_CREATED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0101;
411 const VM_DESTRUCTED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0110;
412 const VM_DESTRUCTED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0111;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100413}
414
Balint Dobszayde0dc802025-02-28 14:16:52 +0100415/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
416#[derive(Debug, Eq, PartialEq, Clone, Copy)]
417pub struct DirectMsg2Args([u64; 14]);
418
Tomás González092202a2025-03-05 11:56:45 +0000419#[derive(Debug, Eq, PartialEq, Clone, Copy)]
420pub struct MsgWaitFlags {
421 retain_rx_buffer: bool,
422}
423
424impl MsgWaitFlags {
425 const RETAIN_RX_BUFFER: u32 = 0x01;
426 const MBZ_BITS: u32 = 0xfffe;
427}
428
429impl TryFrom<u32> for MsgWaitFlags {
430 type Error = Error;
431
432 fn try_from(val: u32) -> Result<Self, Self::Error> {
433 if (val & Self::MBZ_BITS) != 0 {
434 Err(Error::InvalidMsgWaitFlag(val))
435 } else {
436 Ok(MsgWaitFlags {
437 retain_rx_buffer: val & Self::RETAIN_RX_BUFFER != 0,
438 })
439 }
440 }
441}
442
443impl From<MsgWaitFlags> for u32 {
444 fn from(flags: MsgWaitFlags) -> Self {
445 let mut bits: u32 = 0;
446 if flags.retain_rx_buffer {
447 bits |= MsgWaitFlags::RETAIN_RX_BUFFER;
448 }
449 bits
450 }
451}
452
Balint Dobszaya5846852025-02-26 15:38:53 +0100453/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
Tomás Gonzálezf268e322025-03-05 11:18:11 +0000454/// descriptor.
455///
456/// Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX buffer is not
457/// used to transmit the transaction descriptor.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100458#[derive(Debug, Eq, PartialEq, Clone, Copy)]
459pub enum MemOpBuf {
460 Buf32 { addr: u32, page_cnt: u32 },
461 Buf64 { addr: u64, page_cnt: u32 },
462}
463
Balint Dobszaya5846852025-02-26 15:38:53 +0100464/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100465#[derive(Debug, Eq, PartialEq, Clone, Copy)]
466pub enum MemAddr {
467 Addr32(u32),
468 Addr64(u64),
469}
470
Balint Dobszayde0dc802025-02-28 14:16:52 +0100471/// Argument for the `FFA_CONSOLE_LOG` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100472#[derive(Debug, Eq, PartialEq, Clone, Copy)]
473pub enum ConsoleLogChars {
474 Reg32([u32; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100475 Reg64([u64; 16]),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100476}
477
Tomás Gonzálezf268e322025-03-05 11:18:11 +0000478/// FF-A "message types", the terminology used by the spec is "interfaces".
479///
480/// The interfaces are used by FF-A components for communication at an FF-A instance. The spec also
481/// describes the valid FF-A instances and conduits for each interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100482#[derive(Debug, Eq, PartialEq, Clone, Copy)]
483pub enum Interface {
484 Error {
485 target_info: TargetInfo,
486 error_code: FfaError,
487 },
488 Success {
489 target_info: u32,
490 args: SuccessArgs,
491 },
492 Interrupt {
493 target_info: TargetInfo,
494 interrupt_id: u32,
495 },
496 Version {
497 input_version: Version,
498 },
499 VersionOut {
500 output_version: Version,
501 },
502 Features {
503 feat_id: Feature,
504 input_properties: u32,
505 },
506 RxAcquire {
507 vm_id: u16,
508 },
509 RxRelease {
510 vm_id: u16,
511 },
512 RxTxMap {
513 addr: RxTxAddr,
514 page_cnt: u32,
515 },
516 RxTxUnmap {
517 id: u16,
518 },
519 PartitionInfoGet {
520 uuid: Uuid,
521 flags: u32,
522 },
523 IdGet,
524 SpmIdGet,
Tomás González092202a2025-03-05 11:56:45 +0000525 MsgWait {
526 flags: Option<MsgWaitFlags>,
527 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100528 Yield,
529 Run {
530 target_info: TargetInfo,
531 },
532 NormalWorldResume,
Tomás González17b92442025-03-10 16:45:04 +0000533 SecondaryEpRegister {
534 entrypoint: SecondaryEpRegisterAddr,
535 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100536 MsgSend2 {
537 sender_vm_id: u16,
538 flags: u32,
539 },
540 MsgSendDirectReq {
541 src_id: u16,
542 dst_id: u16,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100543 args: DirectMsgArgs,
544 },
545 MsgSendDirectResp {
546 src_id: u16,
547 dst_id: u16,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100548 args: DirectMsgArgs,
549 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100550 MsgSendDirectReq2 {
551 src_id: u16,
552 dst_id: u16,
553 uuid: Uuid,
554 args: DirectMsg2Args,
555 },
556 MsgSendDirectResp2 {
557 src_id: u16,
558 dst_id: u16,
559 args: DirectMsg2Args,
560 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100561 MemDonate {
562 total_len: u32,
563 frag_len: u32,
564 buf: Option<MemOpBuf>,
565 },
566 MemLend {
567 total_len: u32,
568 frag_len: u32,
569 buf: Option<MemOpBuf>,
570 },
571 MemShare {
572 total_len: u32,
573 frag_len: u32,
574 buf: Option<MemOpBuf>,
575 },
576 MemRetrieveReq {
577 total_len: u32,
578 frag_len: u32,
579 buf: Option<MemOpBuf>,
580 },
581 MemRetrieveResp {
582 total_len: u32,
583 frag_len: u32,
584 },
585 MemRelinquish,
586 MemReclaim {
587 handle: memory_management::Handle,
588 flags: u32,
589 },
590 MemPermGet {
591 addr: MemAddr,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100592 page_cnt: Option<u32>,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100593 },
594 MemPermSet {
595 addr: MemAddr,
596 page_cnt: u32,
597 mem_perm: u32,
598 },
599 ConsoleLog {
600 char_cnt: u8,
601 char_lists: ConsoleLogChars,
602 },
603}
604
Balint Dobszayde0dc802025-02-28 14:16:52 +0100605impl Interface {
606 /// Returns the function ID for the call, if it has one.
607 pub fn function_id(&self) -> Option<FuncId> {
608 match self {
609 Interface::Error { .. } => Some(FuncId::Error),
610 Interface::Success { args, .. } => match args {
611 SuccessArgs::Result32(..) => Some(FuncId::Success32),
612 SuccessArgs::Result64(..) | SuccessArgs::Result64_2(..) => Some(FuncId::Success64),
613 },
614 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
615 Interface::Version { .. } => Some(FuncId::Version),
616 Interface::VersionOut { .. } => None,
617 Interface::Features { .. } => Some(FuncId::Features),
618 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
619 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
620 Interface::RxTxMap { addr, .. } => match addr {
621 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
622 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
623 },
624 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
625 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
626 Interface::IdGet => Some(FuncId::IdGet),
627 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
Tomás González092202a2025-03-05 11:56:45 +0000628 Interface::MsgWait { .. } => Some(FuncId::MsgWait),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100629 Interface::Yield => Some(FuncId::Yield),
630 Interface::Run { .. } => Some(FuncId::Run),
631 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
Tomás González17b92442025-03-10 16:45:04 +0000632 Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
633 SecondaryEpRegisterAddr::Addr32 { .. } => Some(FuncId::SecondaryEpRegister32),
634 SecondaryEpRegisterAddr::Addr64 { .. } => Some(FuncId::SecondaryEpRegister64),
635 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100636 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
637 Interface::MsgSendDirectReq { args, .. } => match args {
638 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
639 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
Tomás González4d5b0ba2025-03-03 17:15:55 +0000640 DirectMsgArgs::VersionReq { .. } => Some(FuncId::MsgSendDirectReq32),
641 DirectMsgArgs::PowerPsciReq32 { .. } => Some(FuncId::MsgSendDirectReq32),
642 DirectMsgArgs::PowerPsciReq64 { .. } => Some(FuncId::MsgSendDirectReq64),
643 DirectMsgArgs::PowerWarmBootReq { .. } => Some(FuncId::MsgSendDirectReq32),
644 DirectMsgArgs::VmCreated { .. } => Some(FuncId::MsgSendDirectReq32),
645 DirectMsgArgs::VmDestructed { .. } => Some(FuncId::MsgSendDirectReq32),
646 _ => None,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100647 },
648 Interface::MsgSendDirectResp { args, .. } => match args {
649 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
650 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
Tomás González4d5b0ba2025-03-03 17:15:55 +0000651 DirectMsgArgs::VersionResp { .. } => Some(FuncId::MsgSendDirectResp32),
652 DirectMsgArgs::PowerPsciResp { .. } => Some(FuncId::MsgSendDirectResp32),
653 DirectMsgArgs::VmCreatedAck { .. } => Some(FuncId::MsgSendDirectResp32),
654 DirectMsgArgs::VmDestructedAck { .. } => Some(FuncId::MsgSendDirectResp32),
655 _ => None,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100656 },
657 Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
658 Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
659 Interface::MemDonate { buf, .. } => match buf {
660 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
661 _ => Some(FuncId::MemDonate32),
662 },
663 Interface::MemLend { buf, .. } => match buf {
664 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
665 _ => Some(FuncId::MemLend32),
666 },
667 Interface::MemShare { buf, .. } => match buf {
668 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
669 _ => Some(FuncId::MemShare32),
670 },
671 Interface::MemRetrieveReq { buf, .. } => match buf {
672 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
673 _ => Some(FuncId::MemRetrieveReq32),
674 },
675 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
676 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
677 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
678 Interface::MemPermGet { addr, .. } => match addr {
679 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
680 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
681 },
682 Interface::MemPermSet { addr, .. } => match addr {
683 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
684 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
685 },
686 Interface::ConsoleLog { char_lists, .. } => match char_lists {
687 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
688 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
689 },
690 }
691 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100692
Balint Dobszayde0dc802025-02-28 14:16:52 +0100693 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
694 pub fn is_32bit(&self) -> bool {
695 // TODO: self should always have a function ID?
696 self.function_id().unwrap().is_32bit()
697 }
698
699 /// Parse interface from register contents. The caller must ensure that the `regs` argument has
700 /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
701 pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
702 let reg_cnt = regs.len();
703
704 let msg = match reg_cnt {
705 8 => {
706 assert!(version <= Version(1, 1));
707 Interface::unpack_regs8(version, regs.try_into().unwrap())?
708 }
709 18 => {
710 assert!(version >= Version(1, 2));
711 match FuncId::try_from(regs[0] as u32)? {
712 FuncId::ConsoleLog64
713 | FuncId::Success64
714 | FuncId::MsgSendDirectReq64_2
715 | FuncId::MsgSendDirectResp64_2 => {
716 Interface::unpack_regs18(version, regs.try_into().unwrap())?
717 }
718 _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
719 }
720 }
721 _ => panic!(
722 "Invalid number of registers ({}) for FF-A version {}",
723 reg_cnt, version
724 ),
725 };
726
727 Ok(msg)
728 }
729
730 fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100731 let fid = FuncId::try_from(regs[0] as u32)?;
732
733 let msg = match fid {
734 FuncId::Error => Self::Error {
735 target_info: (regs[1] as u32).into(),
736 error_code: FfaError::try_from(regs[2] as i32)?,
737 },
738 FuncId::Success32 => Self::Success {
739 target_info: regs[1] as u32,
740 args: SuccessArgs::Result32([
741 regs[2] as u32,
742 regs[3] as u32,
743 regs[4] as u32,
744 regs[5] as u32,
745 regs[6] as u32,
746 regs[7] as u32,
747 ]),
748 },
749 FuncId::Success64 => Self::Success {
750 target_info: regs[1] as u32,
751 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
752 },
753 FuncId::Interrupt => Self::Interrupt {
754 target_info: (regs[1] as u32).into(),
755 interrupt_id: regs[2] as u32,
756 },
757 FuncId::Version => Self::Version {
Tomás González83146af2025-03-04 11:32:41 +0000758 input_version: (regs[1] as u32).try_into()?,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100759 },
760 FuncId::Features => Self::Features {
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100761 feat_id: (regs[1] as u32).into(),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100762 input_properties: regs[2] as u32,
763 },
764 FuncId::RxAcquire => Self::RxAcquire {
765 vm_id: regs[1] as u16,
766 },
767 FuncId::RxRelease => Self::RxRelease {
768 vm_id: regs[1] as u16,
769 },
770 FuncId::RxTxMap32 => {
771 let addr = RxTxAddr::Addr32 {
772 rx: regs[2] as u32,
773 tx: regs[1] as u32,
774 };
775 let page_cnt = regs[3] as u32;
776
777 Self::RxTxMap { addr, page_cnt }
778 }
779 FuncId::RxTxMap64 => {
780 let addr = RxTxAddr::Addr64 {
781 rx: regs[2],
782 tx: regs[1],
783 };
784 let page_cnt = regs[3] as u32;
785
786 Self::RxTxMap { addr, page_cnt }
787 }
788 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
789 FuncId::PartitionInfoGet => {
790 let uuid_words = [
791 regs[1] as u32,
792 regs[2] as u32,
793 regs[3] as u32,
794 regs[4] as u32,
795 ];
796 let mut bytes: [u8; 16] = [0; 16];
797 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
798 bytes[i] = b;
799 }
800 Self::PartitionInfoGet {
801 uuid: Uuid::from_bytes(bytes),
802 flags: regs[5] as u32,
803 }
804 }
805 FuncId::IdGet => Self::IdGet,
806 FuncId::SpmIdGet => Self::SpmIdGet,
Tomás González092202a2025-03-05 11:56:45 +0000807 FuncId::MsgWait => Self::MsgWait {
808 flags: if version >= Version(1, 2) {
809 Some(MsgWaitFlags::try_from(regs[2] as u32)?)
810 } else {
811 None
812 },
813 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100814 FuncId::Yield => Self::Yield,
815 FuncId::Run => Self::Run {
816 target_info: (regs[1] as u32).into(),
817 },
818 FuncId::NormalWorldResume => Self::NormalWorldResume,
Tomás González17b92442025-03-10 16:45:04 +0000819 FuncId::SecondaryEpRegister32 => Self::SecondaryEpRegister {
820 entrypoint: SecondaryEpRegisterAddr::Addr32(regs[1] as u32),
821 },
822 FuncId::SecondaryEpRegister64 => Self::SecondaryEpRegister {
823 entrypoint: SecondaryEpRegisterAddr::Addr64(regs[1]),
824 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100825 FuncId::MsgSend2 => Self::MsgSend2 {
826 sender_vm_id: regs[1] as u16,
827 flags: regs[2] as u32,
828 },
829 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
830 src_id: (regs[1] >> 16) as u16,
831 dst_id: regs[1] as u16,
Tomás González4d5b0ba2025-03-03 17:15:55 +0000832 args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
833 match regs[2] as u32 {
834 DirectMsgArgs::VERSION_REQ => DirectMsgArgs::VersionReq {
835 version: Version::try_from(regs[3] as u32)?,
836 },
837 DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq32 {
838 function_id: regs[3] as u32,
839 params: [regs[4] as u32, regs[5] as u32, regs[6] as u32],
840 },
841 DirectMsgArgs::POWER_WARM_BOOT_REQ => DirectMsgArgs::PowerWarmBootReq {
842 boot_type: WarmBootType::try_from(regs[3] as u32)?,
843 },
844 DirectMsgArgs::VM_CREATED => DirectMsgArgs::VmCreated {
845 handle: memory_management::Handle::from([
846 regs[3] as u32,
847 regs[4] as u32,
848 ]),
849 vm_id: regs[5] as u16,
850 },
851 DirectMsgArgs::VM_DESTRUCTED => DirectMsgArgs::VmDestructed {
852 handle: memory_management::Handle::from([
853 regs[3] as u32,
854 regs[4] as u32,
855 ]),
856 vm_id: regs[5] as u16,
857 },
858 _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
859 }
860 } else {
861 DirectMsgArgs::Args32([
862 regs[3] as u32,
863 regs[4] as u32,
864 regs[5] as u32,
865 regs[6] as u32,
866 regs[7] as u32,
867 ])
868 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100869 },
870 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
871 src_id: (regs[1] >> 16) as u16,
872 dst_id: regs[1] as u16,
Tomás González4d5b0ba2025-03-03 17:15:55 +0000873 args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
874 match regs[2] as u32 {
875 DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq64 {
876 function_id: regs[3] as u32,
877 params: [regs[4], regs[5], regs[6]],
878 },
879 _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
880 }
881 } else {
882 DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
883 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100884 },
885 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
886 src_id: (regs[1] >> 16) as u16,
887 dst_id: regs[1] as u16,
Tomás González4d5b0ba2025-03-03 17:15:55 +0000888 args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
889 match regs[2] as u32 {
890 DirectMsgArgs::VERSION_RESP => {
891 if regs[3] as i32 == FfaError::NotSupported.into() {
892 DirectMsgArgs::VersionResp { version: None }
893 } else {
894 DirectMsgArgs::VersionResp {
895 version: Some(Version::try_from(regs[3] as u32)?),
896 }
897 }
898 }
899 DirectMsgArgs::POWER_PSCI_RESP => DirectMsgArgs::PowerPsciResp {
900 psci_status: regs[3] as i32,
901 },
902 DirectMsgArgs::VM_CREATED_ACK => DirectMsgArgs::VmCreatedAck {
903 sp_status: (regs[3] as i32).try_into()?,
904 },
905 DirectMsgArgs::VM_DESTRUCTED_ACK => DirectMsgArgs::VmDestructedAck {
906 sp_status: (regs[3] as i32).try_into()?,
907 },
908 _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
909 }
910 } else {
911 DirectMsgArgs::Args32([
912 regs[3] as u32,
913 regs[4] as u32,
914 regs[5] as u32,
915 regs[6] as u32,
916 regs[7] as u32,
917 ])
918 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100919 },
920 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
921 src_id: (regs[1] >> 16) as u16,
922 dst_id: regs[1] as u16,
Tomás González4d5b0ba2025-03-03 17:15:55 +0000923 args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
924 return Err(Error::UnrecognisedFwkMsg(regs[2] as u32));
925 } else {
926 DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
927 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100928 },
929 FuncId::MemDonate32 => Self::MemDonate {
930 total_len: regs[1] as u32,
931 frag_len: regs[2] as u32,
932 buf: if regs[3] != 0 && regs[4] != 0 {
933 Some(MemOpBuf::Buf32 {
934 addr: regs[3] as u32,
935 page_cnt: regs[4] as u32,
936 })
937 } else {
938 None
939 },
940 },
941 FuncId::MemDonate64 => Self::MemDonate {
942 total_len: regs[1] as u32,
943 frag_len: regs[2] as u32,
944 buf: if regs[3] != 0 && regs[4] != 0 {
945 Some(MemOpBuf::Buf64 {
946 addr: regs[3],
947 page_cnt: regs[4] as u32,
948 })
949 } else {
950 None
951 },
952 },
953 FuncId::MemLend32 => Self::MemLend {
954 total_len: regs[1] as u32,
955 frag_len: regs[2] as u32,
956 buf: if regs[3] != 0 && regs[4] != 0 {
957 Some(MemOpBuf::Buf32 {
958 addr: regs[3] as u32,
959 page_cnt: regs[4] as u32,
960 })
961 } else {
962 None
963 },
964 },
965 FuncId::MemLend64 => Self::MemLend {
966 total_len: regs[1] as u32,
967 frag_len: regs[2] as u32,
968 buf: if regs[3] != 0 && regs[4] != 0 {
969 Some(MemOpBuf::Buf64 {
970 addr: regs[3],
971 page_cnt: regs[4] as u32,
972 })
973 } else {
974 None
975 },
976 },
977 FuncId::MemShare32 => Self::MemShare {
978 total_len: regs[1] as u32,
979 frag_len: regs[2] as u32,
980 buf: if regs[3] != 0 && regs[4] != 0 {
981 Some(MemOpBuf::Buf32 {
982 addr: regs[3] as u32,
983 page_cnt: regs[4] as u32,
984 })
985 } else {
986 None
987 },
988 },
989 FuncId::MemShare64 => Self::MemShare {
990 total_len: regs[1] as u32,
991 frag_len: regs[2] as u32,
992 buf: if regs[3] != 0 && regs[4] != 0 {
993 Some(MemOpBuf::Buf64 {
994 addr: regs[3],
995 page_cnt: regs[4] as u32,
996 })
997 } else {
998 None
999 },
1000 },
1001 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
1002 total_len: regs[1] as u32,
1003 frag_len: regs[2] as u32,
1004 buf: if regs[3] != 0 && regs[4] != 0 {
1005 Some(MemOpBuf::Buf32 {
1006 addr: regs[3] as u32,
1007 page_cnt: regs[4] as u32,
1008 })
1009 } else {
1010 None
1011 },
1012 },
1013 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
1014 total_len: regs[1] as u32,
1015 frag_len: regs[2] as u32,
1016 buf: if regs[3] != 0 && regs[4] != 0 {
1017 Some(MemOpBuf::Buf64 {
1018 addr: regs[3],
1019 page_cnt: regs[4] as u32,
1020 })
1021 } else {
1022 None
1023 },
1024 },
1025 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
1026 total_len: regs[1] as u32,
1027 frag_len: regs[2] as u32,
1028 },
1029 FuncId::MemRelinquish => Self::MemRelinquish,
1030 FuncId::MemReclaim => Self::MemReclaim {
1031 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
1032 flags: regs[3] as u32,
1033 },
1034 FuncId::MemPermGet32 => Self::MemPermGet {
1035 addr: MemAddr::Addr32(regs[1] as u32),
Balint Dobszayde0dc802025-02-28 14:16:52 +01001036 page_cnt: if version >= Version(1, 3) {
1037 Some(regs[2] as u32)
1038 } else {
1039 None
1040 },
Balint Dobszay3aad9572025-01-17 16:54:11 +01001041 },
1042 FuncId::MemPermGet64 => Self::MemPermGet {
1043 addr: MemAddr::Addr64(regs[1]),
Balint Dobszayde0dc802025-02-28 14:16:52 +01001044 page_cnt: if version >= Version(1, 3) {
1045 Some(regs[2] as u32)
1046 } else {
1047 None
1048 },
Balint Dobszay3aad9572025-01-17 16:54:11 +01001049 },
1050 FuncId::MemPermSet32 => Self::MemPermSet {
1051 addr: MemAddr::Addr32(regs[1] as u32),
1052 page_cnt: regs[2] as u32,
1053 mem_perm: regs[3] as u32,
1054 },
1055 FuncId::MemPermSet64 => Self::MemPermSet {
1056 addr: MemAddr::Addr64(regs[1]),
1057 page_cnt: regs[2] as u32,
1058 mem_perm: regs[3] as u32,
1059 },
1060 FuncId::ConsoleLog32 => Self::ConsoleLog {
1061 char_cnt: regs[1] as u8,
1062 char_lists: ConsoleLogChars::Reg32([
1063 regs[2] as u32,
1064 regs[3] as u32,
1065 regs[4] as u32,
1066 regs[5] as u32,
1067 regs[6] as u32,
1068 regs[7] as u32,
1069 ]),
1070 },
Balint Dobszayde0dc802025-02-28 14:16:52 +01001071 _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001072 };
1073
1074 Ok(msg)
1075 }
Balint Dobszay3aad9572025-01-17 16:54:11 +01001076
Balint Dobszayde0dc802025-02-28 14:16:52 +01001077 fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
1078 assert!(version >= Version(1, 2));
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001079
Balint Dobszayde0dc802025-02-28 14:16:52 +01001080 let fid = FuncId::try_from(regs[0] as u32)?;
1081
1082 let msg = match fid {
1083 FuncId::Success64 => Self::Success {
1084 target_info: regs[1] as u32,
1085 args: SuccessArgs::Result64_2(regs[2..18].try_into().unwrap()),
1086 },
1087 FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
1088 src_id: (regs[1] >> 16) as u16,
1089 dst_id: regs[1] as u16,
1090 uuid: Uuid::from_u64_pair(regs[2], regs[3]),
1091 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
1092 },
1093 FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
1094 src_id: (regs[1] >> 16) as u16,
1095 dst_id: regs[1] as u16,
1096 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
1097 },
1098 FuncId::ConsoleLog64 => Self::ConsoleLog {
1099 char_cnt: regs[1] as u8,
1100 char_lists: ConsoleLogChars::Reg64(regs[2..18].try_into().unwrap()),
1101 },
1102 _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
1103 };
1104
1105 Ok(msg)
Balint Dobszay3aad9572025-01-17 16:54:11 +01001106 }
1107
Balint Dobszaya5846852025-02-26 15:38:53 +01001108 /// Create register contents for an interface.
Balint Dobszayde0dc802025-02-28 14:16:52 +01001109 pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
1110 let reg_cnt = regs.len();
1111
1112 match reg_cnt {
1113 8 => {
1114 assert!(version <= Version(1, 1));
1115 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
1116 }
1117 18 => {
1118 assert!(version >= Version(1, 2));
1119
1120 match self {
1121 Interface::ConsoleLog {
1122 char_lists: ConsoleLogChars::Reg64(_),
1123 ..
1124 }
1125 | Interface::Success {
1126 args: SuccessArgs::Result64_2(_),
1127 ..
1128 }
1129 | Interface::MsgSendDirectReq2 { .. }
1130 | Interface::MsgSendDirectResp2 { .. } => {
1131 self.pack_regs18(version, regs.try_into().unwrap());
1132 }
1133 _ => {
1134 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
1135 }
1136 }
1137 }
1138 _ => panic!("Invalid number of registers {}", reg_cnt),
1139 }
1140 }
1141
1142 fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001143 a.fill(0);
1144 if let Some(function_id) = self.function_id() {
1145 a[0] = function_id as u64;
1146 }
1147
1148 match *self {
1149 Interface::Error {
1150 target_info,
1151 error_code,
1152 } => {
1153 a[1] = u32::from(target_info).into();
1154 a[2] = (error_code as u32).into();
1155 }
1156 Interface::Success { target_info, args } => {
1157 a[1] = target_info.into();
1158 match args {
1159 SuccessArgs::Result32(regs) => {
1160 a[2] = regs[0].into();
1161 a[3] = regs[1].into();
1162 a[4] = regs[2].into();
1163 a[5] = regs[3].into();
1164 a[6] = regs[4].into();
1165 a[7] = regs[5].into();
1166 }
1167 SuccessArgs::Result64(regs) => {
1168 a[2] = regs[0];
1169 a[3] = regs[1];
1170 a[4] = regs[2];
1171 a[5] = regs[3];
1172 a[6] = regs[4];
1173 a[7] = regs[5];
1174 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001175 _ => panic!("{:#x?} requires 18 registers", args),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001176 }
1177 }
1178 Interface::Interrupt {
1179 target_info,
1180 interrupt_id,
1181 } => {
1182 a[1] = u32::from(target_info).into();
1183 a[2] = interrupt_id.into();
1184 }
1185 Interface::Version { input_version } => {
1186 a[1] = u32::from(input_version).into();
1187 }
1188 Interface::VersionOut { output_version } => {
1189 a[0] = u32::from(output_version).into();
1190 }
1191 Interface::Features {
1192 feat_id,
1193 input_properties,
1194 } => {
1195 a[1] = u32::from(feat_id).into();
1196 a[2] = input_properties.into();
1197 }
1198 Interface::RxAcquire { vm_id } => {
1199 a[1] = vm_id.into();
1200 }
1201 Interface::RxRelease { vm_id } => {
1202 a[1] = vm_id.into();
1203 }
1204 Interface::RxTxMap { addr, page_cnt } => {
1205 match addr {
1206 RxTxAddr::Addr32 { rx, tx } => {
1207 a[1] = tx.into();
1208 a[2] = rx.into();
1209 }
1210 RxTxAddr::Addr64 { rx, tx } => {
1211 a[1] = tx;
1212 a[2] = rx;
1213 }
1214 }
1215 a[3] = page_cnt.into();
1216 }
1217 Interface::RxTxUnmap { id } => {
1218 a[1] = id.into();
1219 }
1220 Interface::PartitionInfoGet { uuid, flags } => {
1221 let bytes = uuid.into_bytes();
1222 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
1223 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
1224 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
1225 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
1226 a[5] = flags.into();
1227 }
Tomás González092202a2025-03-05 11:56:45 +00001228 Interface::MsgWait { flags } => {
1229 if version >= Version(1, 2) {
1230 if let Some(flags) = flags {
1231 a[2] = u32::from(flags).into();
1232 }
1233 }
1234 }
1235 Interface::IdGet | Interface::SpmIdGet | Interface::Yield => {}
Balint Dobszay3aad9572025-01-17 16:54:11 +01001236 Interface::Run { target_info } => {
1237 a[1] = u32::from(target_info).into();
1238 }
1239 Interface::NormalWorldResume => {}
Tomás González17b92442025-03-10 16:45:04 +00001240 Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
1241 SecondaryEpRegisterAddr::Addr32(addr) => a[1] = addr as u64,
1242 SecondaryEpRegisterAddr::Addr64(addr) => a[1] = addr,
1243 },
Balint Dobszay3aad9572025-01-17 16:54:11 +01001244 Interface::MsgSend2 {
1245 sender_vm_id,
1246 flags,
1247 } => {
1248 a[1] = sender_vm_id.into();
1249 a[2] = flags.into();
1250 }
1251 Interface::MsgSendDirectReq {
1252 src_id,
1253 dst_id,
Balint Dobszay3aad9572025-01-17 16:54:11 +01001254 args,
1255 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +01001256 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001257 match args {
1258 DirectMsgArgs::Args32(args) => {
1259 a[3] = args[0].into();
1260 a[4] = args[1].into();
1261 a[5] = args[2].into();
1262 a[6] = args[3].into();
1263 a[7] = args[4].into();
1264 }
1265 DirectMsgArgs::Args64(args) => {
1266 a[3] = args[0];
1267 a[4] = args[1];
1268 a[5] = args[2];
1269 a[6] = args[3];
1270 a[7] = args[4];
1271 }
Tomás González4d5b0ba2025-03-03 17:15:55 +00001272 DirectMsgArgs::VersionReq { version } => {
1273 a[2] = DirectMsgArgs::VERSION_REQ.into();
1274 a[3] = u32::from(version).into();
1275 }
1276 DirectMsgArgs::PowerPsciReq32 {
1277 function_id,
1278 params,
1279 } => {
1280 a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
1281 a[3] = function_id.into();
1282 a[4] = params[0].into();
1283 a[5] = params[1].into();
1284 a[6] = params[2].into();
1285 }
1286 DirectMsgArgs::PowerPsciReq64 {
1287 function_id,
1288 params,
1289 } => {
1290 a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
1291 a[3] = function_id.into();
1292 a[4] = params[0];
1293 a[5] = params[1];
1294 a[6] = params[2];
1295 }
1296 DirectMsgArgs::PowerWarmBootReq { boot_type } => {
1297 a[2] = DirectMsgArgs::POWER_WARM_BOOT_REQ.into();
1298 a[3] = u32::from(boot_type).into();
1299 }
1300 DirectMsgArgs::VmCreated { handle, vm_id } => {
1301 a[2] = DirectMsgArgs::VM_CREATED.into();
1302 let handle_regs: [u32; 2] = handle.into();
1303 a[3] = handle_regs[0].into();
1304 a[4] = handle_regs[1].into();
1305 a[5] = vm_id.into();
1306 }
1307 DirectMsgArgs::VmDestructed { handle, vm_id } => {
1308 a[2] = DirectMsgArgs::VM_DESTRUCTED.into();
1309 let handle_regs: [u32; 2] = handle.into();
1310 a[3] = handle_regs[0].into();
1311 a[4] = handle_regs[1].into();
1312 a[5] = vm_id.into();
1313 }
1314 _ => panic!("Malformed MsgSendDirectReq interface"),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001315 }
1316 }
1317 Interface::MsgSendDirectResp {
1318 src_id,
1319 dst_id,
Balint Dobszay3aad9572025-01-17 16:54:11 +01001320 args,
1321 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +01001322 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001323 match args {
1324 DirectMsgArgs::Args32(args) => {
1325 a[3] = args[0].into();
1326 a[4] = args[1].into();
1327 a[5] = args[2].into();
1328 a[6] = args[3].into();
1329 a[7] = args[4].into();
1330 }
1331 DirectMsgArgs::Args64(args) => {
1332 a[3] = args[0];
1333 a[4] = args[1];
1334 a[5] = args[2];
1335 a[6] = args[3];
1336 a[7] = args[4];
1337 }
Tomás González4d5b0ba2025-03-03 17:15:55 +00001338 DirectMsgArgs::VersionResp { version } => {
1339 a[2] = DirectMsgArgs::VERSION_RESP.into();
1340 match version {
1341 None => a[3] = i32::from(FfaError::NotSupported) as u64,
1342 Some(ver) => a[3] = u32::from(ver).into(),
1343 }
1344 }
1345 DirectMsgArgs::PowerPsciResp { psci_status } => {
1346 a[2] = DirectMsgArgs::POWER_PSCI_RESP.into();
1347 a[3] = psci_status as u64;
1348 }
1349 DirectMsgArgs::VmCreatedAck { sp_status } => {
1350 a[2] = DirectMsgArgs::VM_CREATED_ACK.into();
1351 a[4] = i32::from(sp_status) as u64;
1352 }
1353 DirectMsgArgs::VmDestructedAck { sp_status } => {
1354 a[2] = DirectMsgArgs::VM_DESTRUCTED_ACK.into();
1355 a[3] = i32::from(sp_status) as u64;
1356 }
1357 _ => panic!("Malformed MsgSendDirectResp interface"),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001358 }
1359 }
1360 Interface::MemDonate {
1361 total_len,
1362 frag_len,
1363 buf,
1364 } => {
1365 a[1] = total_len.into();
1366 a[2] = frag_len.into();
1367 (a[3], a[4]) = match buf {
1368 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1369 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1370 None => (0, 0),
1371 };
1372 }
1373 Interface::MemLend {
1374 total_len,
1375 frag_len,
1376 buf,
1377 } => {
1378 a[1] = total_len.into();
1379 a[2] = frag_len.into();
1380 (a[3], a[4]) = match buf {
1381 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1382 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1383 None => (0, 0),
1384 };
1385 }
1386 Interface::MemShare {
1387 total_len,
1388 frag_len,
1389 buf,
1390 } => {
1391 a[1] = total_len.into();
1392 a[2] = frag_len.into();
1393 (a[3], a[4]) = match buf {
1394 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1395 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1396 None => (0, 0),
1397 };
1398 }
1399 Interface::MemRetrieveReq {
1400 total_len,
1401 frag_len,
1402 buf,
1403 } => {
1404 a[1] = total_len.into();
1405 a[2] = frag_len.into();
1406 (a[3], a[4]) = match buf {
1407 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1408 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1409 None => (0, 0),
1410 };
1411 }
1412 Interface::MemRetrieveResp {
1413 total_len,
1414 frag_len,
1415 } => {
1416 a[1] = total_len.into();
1417 a[2] = frag_len.into();
1418 }
1419 Interface::MemRelinquish => {}
1420 Interface::MemReclaim { handle, flags } => {
1421 let handle_regs: [u32; 2] = handle.into();
1422 a[1] = handle_regs[0].into();
1423 a[2] = handle_regs[1].into();
1424 a[3] = flags.into();
1425 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001426 Interface::MemPermGet { addr, page_cnt } => {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001427 a[1] = match addr {
1428 MemAddr::Addr32(addr) => addr.into(),
1429 MemAddr::Addr64(addr) => addr,
1430 };
Balint Dobszayde0dc802025-02-28 14:16:52 +01001431 a[2] = if version >= Version(1, 3) {
1432 page_cnt.unwrap().into()
1433 } else {
1434 assert!(page_cnt.is_none());
1435 0
1436 }
Balint Dobszay3aad9572025-01-17 16:54:11 +01001437 }
1438 Interface::MemPermSet {
1439 addr,
1440 page_cnt,
1441 mem_perm,
1442 } => {
1443 a[1] = match addr {
1444 MemAddr::Addr32(addr) => addr.into(),
1445 MemAddr::Addr64(addr) => addr,
1446 };
1447 a[2] = page_cnt.into();
1448 a[3] = mem_perm.into();
1449 }
1450 Interface::ConsoleLog {
1451 char_cnt,
1452 char_lists,
1453 } => {
1454 a[1] = char_cnt.into();
1455 match char_lists {
1456 ConsoleLogChars::Reg32(regs) => {
1457 a[2] = regs[0].into();
1458 a[3] = regs[1].into();
1459 a[4] = regs[2].into();
1460 a[5] = regs[3].into();
1461 a[6] = regs[4].into();
1462 a[7] = regs[5].into();
1463 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001464 _ => panic!("{:#x?} requires 18 registers", char_lists),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001465 }
1466 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001467 _ => panic!("{:#x?} requires 18 registers", self),
1468 }
1469 }
1470
1471 fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
1472 assert!(version >= Version(1, 2));
1473
1474 a.fill(0);
1475 if let Some(function_id) = self.function_id() {
1476 a[0] = function_id as u64;
1477 }
1478
1479 match *self {
1480 Interface::Success { target_info, args } => {
1481 a[1] = target_info.into();
1482 match args {
1483 SuccessArgs::Result64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
1484 _ => panic!("{:#x?} requires 8 registers", args),
1485 }
1486 }
1487 Interface::MsgSendDirectReq2 {
1488 src_id,
1489 dst_id,
1490 uuid,
1491 args,
1492 } => {
1493 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1494 (a[2], a[3]) = uuid.as_u64_pair();
1495 a[4..18].copy_from_slice(&args.0[..14]);
1496 }
1497 Interface::MsgSendDirectResp2 {
1498 src_id,
1499 dst_id,
1500 args,
1501 } => {
1502 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1503 a[2] = 0;
1504 a[3] = 0;
1505 a[4..18].copy_from_slice(&args.0[..14]);
1506 }
1507 Interface::ConsoleLog {
1508 char_cnt,
1509 char_lists,
1510 } => {
1511 a[1] = char_cnt.into();
1512 match char_lists {
1513 ConsoleLogChars::Reg64(regs) => a[2..18].copy_from_slice(&regs[..16]),
1514 _ => panic!("{:#x?} requires 8 registers", char_lists),
1515 }
1516 }
1517 _ => panic!("{:#x?} requires 8 registers", self),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001518 }
1519 }
1520
Balint Dobszaya5846852025-02-26 15:38:53 +01001521 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001522 pub fn success32_noargs() -> Self {
1523 Self::Success {
1524 target_info: 0,
1525 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1526 }
1527 }
1528
Tomás González4c8c7d22025-03-10 17:14:57 +00001529 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
1530 pub fn success64_noargs() -> Self {
1531 Self::Success {
1532 target_info: 0,
1533 args: SuccessArgs::Result64([0, 0, 0, 0, 0, 0]),
1534 }
1535 }
1536
Balint Dobszaya5846852025-02-26 15:38:53 +01001537 /// Helper function to create an `FFA_ERROR` interface with an error code.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001538 pub fn error(error_code: FfaError) -> Self {
1539 Self::Error {
1540 target_info: TargetInfo {
1541 endpoint_id: 0,
1542 vcpu_id: 0,
1543 },
1544 error_code,
1545 }
1546 }
1547}
1548
Balint Dobszaya5846852025-02-26 15:38:53 +01001549/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
1550pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
Balint Dobszayde0dc802025-02-28 14:16:52 +01001551/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message.
1552pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 128;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001553
Balint Dobszaya5846852025-02-26 15:38:53 +01001554/// Helper function to convert the "Tightly packed list of characters" format used by the
1555/// `FFA_CONSOLE_LOG` interface into a byte slice.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001556pub fn parse_console_log(
1557 char_cnt: u8,
1558 char_lists: &ConsoleLogChars,
1559 log_bytes: &mut [u8],
1560) -> Result<(), FfaError> {
1561 match char_lists {
1562 ConsoleLogChars::Reg32(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001563 if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001564 return Err(FfaError::InvalidParameters);
1565 }
1566 for (i, reg) in regs.iter().enumerate() {
1567 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1568 }
1569 }
1570 ConsoleLogChars::Reg64(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001571 if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001572 return Err(FfaError::InvalidParameters);
1573 }
1574 for (i, reg) in regs.iter().enumerate() {
1575 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1576 }
1577 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001578 }
1579
Balint Dobszayc8802492025-01-15 18:11:39 +01001580 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001581}