blob: cf5a6cafb13920cf21b7001f886572c8340b1ce3 [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,
Balint Dobszaye6aa4862025-02-28 16:37:56 +010073 PartitionInfoGetRegs = 0xc400008b,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020074 IdGet = 0x84000069,
75 SpmIdGet = 0x84000085,
Balint Dobszaye6aa4862025-02-28 16:37:56 +010076 ConsoleLog32 = 0x8400008a,
77 ConsoleLog64 = 0xc400008a,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020078 MsgWait = 0x8400006b,
79 Yield = 0x8400006c,
80 Run = 0x8400006d,
81 NormalWorldResume = 0x8400007c,
82 MsgSend2 = 0x84000086,
83 MsgSendDirectReq32 = 0x8400006f,
84 MsgSendDirectReq64 = 0xc400006f,
Balint Dobszayde0dc802025-02-28 14:16:52 +010085 MsgSendDirectReq64_2 = 0xc400008d,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020086 MsgSendDirectResp32 = 0x84000070,
87 MsgSendDirectResp64 = 0xc4000070,
Balint Dobszayde0dc802025-02-28 14:16:52 +010088 MsgSendDirectResp64_2 = 0xc400008e,
Balint Dobszaye6aa4862025-02-28 16:37:56 +010089 NotificationBitmapCreate = 0x8400007d,
90 NotificationBitmapDestroy = 0x8400007e,
91 NotificationBind = 0x8400007f,
92 NotificationUnbind = 0x84000080,
93 NotificationSet = 0x84000081,
94 NotificationGet = 0x84000082,
95 NotificationInfoGet32 = 0x84000083,
96 NotificationInfoGet64 = 0xc4000083,
97 El3IntrHandle = 0x8400008c,
Balint Dobszay5bf492f2024-07-29 17:21:32 +020098 MemDonate32 = 0x84000071,
99 MemDonate64 = 0xc4000071,
100 MemLend32 = 0x84000072,
101 MemLend64 = 0xc4000072,
102 MemShare32 = 0x84000073,
103 MemShare64 = 0xc4000073,
104 MemRetrieveReq32 = 0x84000074,
105 MemRetrieveReq64 = 0xc4000074,
106 MemRetrieveResp = 0x84000075,
107 MemRelinquish = 0x84000076,
108 MemReclaim = 0x84000077,
109 MemPermGet32 = 0x84000088,
110 MemPermGet64 = 0xc4000088,
111 MemPermSet32 = 0x84000089,
112 MemPermSet64 = 0xc4000089,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200113}
114
Balint Dobszayde0dc802025-02-28 14:16:52 +0100115impl FuncId {
116 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
117 pub fn is_32bit(&self) -> bool {
118 u32::from(*self) & (1 << 30) != 0
119 }
120}
121
Balint Dobszaya5846852025-02-26 15:38:53 +0100122/// Error status codes used by the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100123#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
124#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
125#[repr(i32)]
126pub enum FfaError {
127 #[error("Not supported")]
128 NotSupported = -1,
129 #[error("Invalid parameters")]
130 InvalidParameters = -2,
131 #[error("No memory")]
132 NoMemory = -3,
133 #[error("Busy")]
134 Busy = -4,
135 #[error("Interrupted")]
136 Interrupted = -5,
137 #[error("Denied")]
138 Denied = -6,
139 #[error("Retry")]
140 Retry = -7,
141 #[error("Aborted")]
142 Aborted = -8,
143 #[error("No data")]
144 NoData = -9,
145}
146
Balint Dobszaya5846852025-02-26 15:38:53 +0100147/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200148#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Balint Dobszay3aad9572025-01-17 16:54:11 +0100149pub struct TargetInfo {
150 pub endpoint_id: u16,
151 pub vcpu_id: u16,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200152}
153
Balint Dobszay3aad9572025-01-17 16:54:11 +0100154impl From<u32> for TargetInfo {
155 fn from(value: u32) -> Self {
156 Self {
157 endpoint_id: (value >> 16) as u16,
158 vcpu_id: value as u16,
159 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200160 }
161}
162
Balint Dobszay3aad9572025-01-17 16:54:11 +0100163impl From<TargetInfo> for u32 {
164 fn from(value: TargetInfo) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100165 ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
Andrew Walbran0d315812024-11-25 15:36:36 +0000166 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100167}
Andrew Walbran0d315812024-11-25 15:36:36 +0000168
Balint Dobszaya5846852025-02-26 15:38:53 +0100169/// Arguments for the `FFA_SUCCESS` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100170#[derive(Debug, Eq, PartialEq, Clone, Copy)]
171pub enum SuccessArgs {
172 Result32([u32; 6]),
173 Result64([u64; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100174 Result64_2([u64; 16]),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200175}
176
Balint Dobszaya5846852025-02-26 15:38:53 +0100177/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100178#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200179pub struct Version(pub u16, pub u16);
180
Tomás González1f794352025-03-03 16:47:06 +0000181impl Version {
182 /// Returns whether the caller's version (self) is compatible with the callee's version (input
183 /// parameter)
184 pub fn is_compatible_to(&self, callee_version: &Version) -> bool {
185 self.0 == callee_version.0 && self.1 <= callee_version.1
186 }
187}
188
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200189impl From<u32> for Version {
190 fn from(val: u32) -> Self {
191 Self((val >> 16) as u16, val as u16)
192 }
193}
194
195impl From<Version> for u32 {
196 fn from(v: Version) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100197 ((v.0 as u32) << 16) | v.1 as u32
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200198 }
199}
200
Andrew Walbran19970ba2024-11-25 15:35:00 +0000201impl Display for Version {
202 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
203 write!(f, "{}.{}", self.0, self.1)
204 }
205}
206
207impl Debug for Version {
208 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
209 Display::fmt(self, f)
210 }
211}
212
Balint Dobszaya5846852025-02-26 15:38:53 +0100213/// Feature IDs used by the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100214#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
215#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
216#[repr(u8)]
217pub enum FeatureId {
218 NotificationPendingInterrupt = 0x1,
219 ScheduleReceiverInterrupt = 0x2,
220 ManagedExitInterrupt = 0x3,
221}
Balint Dobszayc8802492025-01-15 18:11:39 +0100222
Balint Dobszaya5846852025-02-26 15:38:53 +0100223/// Arguments for the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100224#[derive(Debug, Eq, PartialEq, Clone, Copy)]
225pub enum Feature {
226 FuncId(FuncId),
227 FeatureId(FeatureId),
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100228 Unknown(u32),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100229}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200230
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100231impl From<u32> for Feature {
232 fn from(value: u32) -> Self {
233 // Bit[31] is set for all valid FF-A function IDs so we don't have to check it separately
234 if let Ok(func_id) = value.try_into() {
235 Self::FuncId(func_id)
236 } else if let Ok(feat_id) = (value as u8).try_into() {
237 Self::FeatureId(feat_id)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100238 } else {
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100239 Self::Unknown(value)
240 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100241 }
242}
243
244impl From<Feature> for u32 {
245 fn from(value: Feature) -> Self {
246 match value {
247 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
248 Feature::FeatureId(feature_id) => feature_id as u32,
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100249 Feature::Unknown(id) => panic!("Unknown feature or function ID {:#x?}", id),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100250 }
251 }
252}
253
Balint Dobszaya5846852025-02-26 15:38:53 +0100254/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100255#[derive(Debug, Eq, PartialEq, Clone, Copy)]
256pub enum RxTxAddr {
257 Addr32 { rx: u32, tx: u32 },
258 Addr64 { rx: u64, tx: u64 },
259}
260
Balint Dobszaya5846852025-02-26 15:38:53 +0100261/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100262#[derive(Debug, Eq, PartialEq, Clone, Copy)]
263pub enum DirectMsgArgs {
264 Args32([u32; 5]),
265 Args64([u64; 5]),
266}
267
Balint Dobszayde0dc802025-02-28 14:16:52 +0100268/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
269#[derive(Debug, Eq, PartialEq, Clone, Copy)]
270pub struct DirectMsg2Args([u64; 14]);
271
Balint Dobszaya5846852025-02-26 15:38:53 +0100272/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
273/// descriptor. Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX
274/// buffer is not used to transmit the transaction descriptor.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100275#[derive(Debug, Eq, PartialEq, Clone, Copy)]
276pub enum MemOpBuf {
277 Buf32 { addr: u32, page_cnt: u32 },
278 Buf64 { addr: u64, page_cnt: u32 },
279}
280
Balint Dobszaya5846852025-02-26 15:38:53 +0100281/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100282#[derive(Debug, Eq, PartialEq, Clone, Copy)]
283pub enum MemAddr {
284 Addr32(u32),
285 Addr64(u64),
286}
287
Balint Dobszayde0dc802025-02-28 14:16:52 +0100288/// Argument for the `FFA_CONSOLE_LOG` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100289#[derive(Debug, Eq, PartialEq, Clone, Copy)]
290pub enum ConsoleLogChars {
291 Reg32([u32; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100292 Reg64([u64; 16]),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100293}
294
Balint Dobszaya5846852025-02-26 15:38:53 +0100295/// FF-A "message types", the terminology used by the spec is "interfaces". The interfaces are used
296/// by FF-A components for communication at an FF-A instance. The spec also describes the valid FF-A
297/// instances and conduits for each interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100298#[derive(Debug, Eq, PartialEq, Clone, Copy)]
299pub enum Interface {
300 Error {
301 target_info: TargetInfo,
302 error_code: FfaError,
303 },
304 Success {
305 target_info: u32,
306 args: SuccessArgs,
307 },
308 Interrupt {
309 target_info: TargetInfo,
310 interrupt_id: u32,
311 },
312 Version {
313 input_version: Version,
314 },
315 VersionOut {
316 output_version: Version,
317 },
318 Features {
319 feat_id: Feature,
320 input_properties: u32,
321 },
322 RxAcquire {
323 vm_id: u16,
324 },
325 RxRelease {
326 vm_id: u16,
327 },
328 RxTxMap {
329 addr: RxTxAddr,
330 page_cnt: u32,
331 },
332 RxTxUnmap {
333 id: u16,
334 },
335 PartitionInfoGet {
336 uuid: Uuid,
337 flags: u32,
338 },
339 IdGet,
340 SpmIdGet,
341 MsgWait,
342 Yield,
343 Run {
344 target_info: TargetInfo,
345 },
346 NormalWorldResume,
347 MsgSend2 {
348 sender_vm_id: u16,
349 flags: u32,
350 },
351 MsgSendDirectReq {
352 src_id: u16,
353 dst_id: u16,
354 flags: u32,
355 args: DirectMsgArgs,
356 },
357 MsgSendDirectResp {
358 src_id: u16,
359 dst_id: u16,
360 flags: u32,
361 args: DirectMsgArgs,
362 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100363 MsgSendDirectReq2 {
364 src_id: u16,
365 dst_id: u16,
366 uuid: Uuid,
367 args: DirectMsg2Args,
368 },
369 MsgSendDirectResp2 {
370 src_id: u16,
371 dst_id: u16,
372 args: DirectMsg2Args,
373 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100374 MemDonate {
375 total_len: u32,
376 frag_len: u32,
377 buf: Option<MemOpBuf>,
378 },
379 MemLend {
380 total_len: u32,
381 frag_len: u32,
382 buf: Option<MemOpBuf>,
383 },
384 MemShare {
385 total_len: u32,
386 frag_len: u32,
387 buf: Option<MemOpBuf>,
388 },
389 MemRetrieveReq {
390 total_len: u32,
391 frag_len: u32,
392 buf: Option<MemOpBuf>,
393 },
394 MemRetrieveResp {
395 total_len: u32,
396 frag_len: u32,
397 },
398 MemRelinquish,
399 MemReclaim {
400 handle: memory_management::Handle,
401 flags: u32,
402 },
403 MemPermGet {
404 addr: MemAddr,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100405 page_cnt: Option<u32>,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100406 },
407 MemPermSet {
408 addr: MemAddr,
409 page_cnt: u32,
410 mem_perm: u32,
411 },
412 ConsoleLog {
413 char_cnt: u8,
414 char_lists: ConsoleLogChars,
415 },
416}
417
Balint Dobszayde0dc802025-02-28 14:16:52 +0100418impl Interface {
419 /// Returns the function ID for the call, if it has one.
420 pub fn function_id(&self) -> Option<FuncId> {
421 match self {
422 Interface::Error { .. } => Some(FuncId::Error),
423 Interface::Success { args, .. } => match args {
424 SuccessArgs::Result32(..) => Some(FuncId::Success32),
425 SuccessArgs::Result64(..) | SuccessArgs::Result64_2(..) => Some(FuncId::Success64),
426 },
427 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
428 Interface::Version { .. } => Some(FuncId::Version),
429 Interface::VersionOut { .. } => None,
430 Interface::Features { .. } => Some(FuncId::Features),
431 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
432 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
433 Interface::RxTxMap { addr, .. } => match addr {
434 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
435 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
436 },
437 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
438 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
439 Interface::IdGet => Some(FuncId::IdGet),
440 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
441 Interface::MsgWait => Some(FuncId::MsgWait),
442 Interface::Yield => Some(FuncId::Yield),
443 Interface::Run { .. } => Some(FuncId::Run),
444 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
445 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
446 Interface::MsgSendDirectReq { args, .. } => match args {
447 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
448 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
449 },
450 Interface::MsgSendDirectResp { args, .. } => match args {
451 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
452 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
453 },
454 Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
455 Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
456 Interface::MemDonate { buf, .. } => match buf {
457 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
458 _ => Some(FuncId::MemDonate32),
459 },
460 Interface::MemLend { buf, .. } => match buf {
461 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
462 _ => Some(FuncId::MemLend32),
463 },
464 Interface::MemShare { buf, .. } => match buf {
465 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
466 _ => Some(FuncId::MemShare32),
467 },
468 Interface::MemRetrieveReq { buf, .. } => match buf {
469 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
470 _ => Some(FuncId::MemRetrieveReq32),
471 },
472 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
473 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
474 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
475 Interface::MemPermGet { addr, .. } => match addr {
476 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
477 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
478 },
479 Interface::MemPermSet { addr, .. } => match addr {
480 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
481 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
482 },
483 Interface::ConsoleLog { char_lists, .. } => match char_lists {
484 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
485 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
486 },
487 }
488 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100489
Balint Dobszayde0dc802025-02-28 14:16:52 +0100490 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
491 pub fn is_32bit(&self) -> bool {
492 // TODO: self should always have a function ID?
493 self.function_id().unwrap().is_32bit()
494 }
495
496 /// Parse interface from register contents. The caller must ensure that the `regs` argument has
497 /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
498 pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
499 let reg_cnt = regs.len();
500
501 let msg = match reg_cnt {
502 8 => {
503 assert!(version <= Version(1, 1));
504 Interface::unpack_regs8(version, regs.try_into().unwrap())?
505 }
506 18 => {
507 assert!(version >= Version(1, 2));
508 match FuncId::try_from(regs[0] as u32)? {
509 FuncId::ConsoleLog64
510 | FuncId::Success64
511 | FuncId::MsgSendDirectReq64_2
512 | FuncId::MsgSendDirectResp64_2 => {
513 Interface::unpack_regs18(version, regs.try_into().unwrap())?
514 }
515 _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
516 }
517 }
518 _ => panic!(
519 "Invalid number of registers ({}) for FF-A version {}",
520 reg_cnt, version
521 ),
522 };
523
524 Ok(msg)
525 }
526
527 fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100528 let fid = FuncId::try_from(regs[0] as u32)?;
529
530 let msg = match fid {
531 FuncId::Error => Self::Error {
532 target_info: (regs[1] as u32).into(),
533 error_code: FfaError::try_from(regs[2] as i32)?,
534 },
535 FuncId::Success32 => Self::Success {
536 target_info: regs[1] as u32,
537 args: SuccessArgs::Result32([
538 regs[2] as u32,
539 regs[3] as u32,
540 regs[4] as u32,
541 regs[5] as u32,
542 regs[6] as u32,
543 regs[7] as u32,
544 ]),
545 },
546 FuncId::Success64 => Self::Success {
547 target_info: regs[1] as u32,
548 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
549 },
550 FuncId::Interrupt => Self::Interrupt {
551 target_info: (regs[1] as u32).into(),
552 interrupt_id: regs[2] as u32,
553 },
554 FuncId::Version => Self::Version {
555 input_version: (regs[1] as u32).into(),
556 },
557 FuncId::Features => Self::Features {
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100558 feat_id: (regs[1] as u32).into(),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100559 input_properties: regs[2] as u32,
560 },
561 FuncId::RxAcquire => Self::RxAcquire {
562 vm_id: regs[1] as u16,
563 },
564 FuncId::RxRelease => Self::RxRelease {
565 vm_id: regs[1] as u16,
566 },
567 FuncId::RxTxMap32 => {
568 let addr = RxTxAddr::Addr32 {
569 rx: regs[2] as u32,
570 tx: regs[1] as u32,
571 };
572 let page_cnt = regs[3] as u32;
573
574 Self::RxTxMap { addr, page_cnt }
575 }
576 FuncId::RxTxMap64 => {
577 let addr = RxTxAddr::Addr64 {
578 rx: regs[2],
579 tx: regs[1],
580 };
581 let page_cnt = regs[3] as u32;
582
583 Self::RxTxMap { addr, page_cnt }
584 }
585 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
586 FuncId::PartitionInfoGet => {
587 let uuid_words = [
588 regs[1] as u32,
589 regs[2] as u32,
590 regs[3] as u32,
591 regs[4] as u32,
592 ];
593 let mut bytes: [u8; 16] = [0; 16];
594 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
595 bytes[i] = b;
596 }
597 Self::PartitionInfoGet {
598 uuid: Uuid::from_bytes(bytes),
599 flags: regs[5] as u32,
600 }
601 }
602 FuncId::IdGet => Self::IdGet,
603 FuncId::SpmIdGet => Self::SpmIdGet,
604 FuncId::MsgWait => Self::MsgWait,
605 FuncId::Yield => Self::Yield,
606 FuncId::Run => Self::Run {
607 target_info: (regs[1] as u32).into(),
608 },
609 FuncId::NormalWorldResume => Self::NormalWorldResume,
610 FuncId::MsgSend2 => Self::MsgSend2 {
611 sender_vm_id: regs[1] as u16,
612 flags: regs[2] as u32,
613 },
614 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
615 src_id: (regs[1] >> 16) as u16,
616 dst_id: regs[1] as u16,
617 flags: regs[2] as u32,
618 args: DirectMsgArgs::Args32([
619 regs[3] as u32,
620 regs[4] as u32,
621 regs[5] as u32,
622 regs[6] as u32,
623 regs[7] as u32,
624 ]),
625 },
626 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
627 src_id: (regs[1] >> 16) as u16,
628 dst_id: regs[1] as u16,
629 flags: regs[2] as u32,
630 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
631 },
632 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
633 src_id: (regs[1] >> 16) as u16,
634 dst_id: regs[1] as u16,
635 flags: regs[2] as u32,
636 args: DirectMsgArgs::Args32([
637 regs[3] as u32,
638 regs[4] as u32,
639 regs[5] as u32,
640 regs[6] as u32,
641 regs[7] as u32,
642 ]),
643 },
644 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
645 src_id: (regs[1] >> 16) as u16,
646 dst_id: regs[1] as u16,
647 flags: regs[2] as u32,
648 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
649 },
650 FuncId::MemDonate32 => Self::MemDonate {
651 total_len: regs[1] as u32,
652 frag_len: regs[2] as u32,
653 buf: if regs[3] != 0 && regs[4] != 0 {
654 Some(MemOpBuf::Buf32 {
655 addr: regs[3] as u32,
656 page_cnt: regs[4] as u32,
657 })
658 } else {
659 None
660 },
661 },
662 FuncId::MemDonate64 => Self::MemDonate {
663 total_len: regs[1] as u32,
664 frag_len: regs[2] as u32,
665 buf: if regs[3] != 0 && regs[4] != 0 {
666 Some(MemOpBuf::Buf64 {
667 addr: regs[3],
668 page_cnt: regs[4] as u32,
669 })
670 } else {
671 None
672 },
673 },
674 FuncId::MemLend32 => Self::MemLend {
675 total_len: regs[1] as u32,
676 frag_len: regs[2] as u32,
677 buf: if regs[3] != 0 && regs[4] != 0 {
678 Some(MemOpBuf::Buf32 {
679 addr: regs[3] as u32,
680 page_cnt: regs[4] as u32,
681 })
682 } else {
683 None
684 },
685 },
686 FuncId::MemLend64 => Self::MemLend {
687 total_len: regs[1] as u32,
688 frag_len: regs[2] as u32,
689 buf: if regs[3] != 0 && regs[4] != 0 {
690 Some(MemOpBuf::Buf64 {
691 addr: regs[3],
692 page_cnt: regs[4] as u32,
693 })
694 } else {
695 None
696 },
697 },
698 FuncId::MemShare32 => Self::MemShare {
699 total_len: regs[1] as u32,
700 frag_len: regs[2] as u32,
701 buf: if regs[3] != 0 && regs[4] != 0 {
702 Some(MemOpBuf::Buf32 {
703 addr: regs[3] as u32,
704 page_cnt: regs[4] as u32,
705 })
706 } else {
707 None
708 },
709 },
710 FuncId::MemShare64 => Self::MemShare {
711 total_len: regs[1] as u32,
712 frag_len: regs[2] as u32,
713 buf: if regs[3] != 0 && regs[4] != 0 {
714 Some(MemOpBuf::Buf64 {
715 addr: regs[3],
716 page_cnt: regs[4] as u32,
717 })
718 } else {
719 None
720 },
721 },
722 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
723 total_len: regs[1] as u32,
724 frag_len: regs[2] as u32,
725 buf: if regs[3] != 0 && regs[4] != 0 {
726 Some(MemOpBuf::Buf32 {
727 addr: regs[3] as u32,
728 page_cnt: regs[4] as u32,
729 })
730 } else {
731 None
732 },
733 },
734 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
735 total_len: regs[1] as u32,
736 frag_len: regs[2] as u32,
737 buf: if regs[3] != 0 && regs[4] != 0 {
738 Some(MemOpBuf::Buf64 {
739 addr: regs[3],
740 page_cnt: regs[4] as u32,
741 })
742 } else {
743 None
744 },
745 },
746 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
747 total_len: regs[1] as u32,
748 frag_len: regs[2] as u32,
749 },
750 FuncId::MemRelinquish => Self::MemRelinquish,
751 FuncId::MemReclaim => Self::MemReclaim {
752 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
753 flags: regs[3] as u32,
754 },
755 FuncId::MemPermGet32 => Self::MemPermGet {
756 addr: MemAddr::Addr32(regs[1] as u32),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100757 page_cnt: if version >= Version(1, 3) {
758 Some(regs[2] as u32)
759 } else {
760 None
761 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100762 },
763 FuncId::MemPermGet64 => Self::MemPermGet {
764 addr: MemAddr::Addr64(regs[1]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100765 page_cnt: if version >= Version(1, 3) {
766 Some(regs[2] as u32)
767 } else {
768 None
769 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100770 },
771 FuncId::MemPermSet32 => Self::MemPermSet {
772 addr: MemAddr::Addr32(regs[1] as u32),
773 page_cnt: regs[2] as u32,
774 mem_perm: regs[3] as u32,
775 },
776 FuncId::MemPermSet64 => Self::MemPermSet {
777 addr: MemAddr::Addr64(regs[1]),
778 page_cnt: regs[2] as u32,
779 mem_perm: regs[3] as u32,
780 },
781 FuncId::ConsoleLog32 => Self::ConsoleLog {
782 char_cnt: regs[1] as u8,
783 char_lists: ConsoleLogChars::Reg32([
784 regs[2] as u32,
785 regs[3] as u32,
786 regs[4] as u32,
787 regs[5] as u32,
788 regs[6] as u32,
789 regs[7] as u32,
790 ]),
791 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100792 _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100793 };
794
795 Ok(msg)
796 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100797
Balint Dobszayde0dc802025-02-28 14:16:52 +0100798 fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
799 assert!(version >= Version(1, 2));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200800
Balint Dobszayde0dc802025-02-28 14:16:52 +0100801 let fid = FuncId::try_from(regs[0] as u32)?;
802
803 let msg = match fid {
804 FuncId::Success64 => Self::Success {
805 target_info: regs[1] as u32,
806 args: SuccessArgs::Result64_2(regs[2..18].try_into().unwrap()),
807 },
808 FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
809 src_id: (regs[1] >> 16) as u16,
810 dst_id: regs[1] as u16,
811 uuid: Uuid::from_u64_pair(regs[2], regs[3]),
812 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
813 },
814 FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
815 src_id: (regs[1] >> 16) as u16,
816 dst_id: regs[1] as u16,
817 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
818 },
819 FuncId::ConsoleLog64 => Self::ConsoleLog {
820 char_cnt: regs[1] as u8,
821 char_lists: ConsoleLogChars::Reg64(regs[2..18].try_into().unwrap()),
822 },
823 _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
824 };
825
826 Ok(msg)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100827 }
828
Balint Dobszaya5846852025-02-26 15:38:53 +0100829 /// Create register contents for an interface.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100830 pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
831 let reg_cnt = regs.len();
832
833 match reg_cnt {
834 8 => {
835 assert!(version <= Version(1, 1));
836 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
837 }
838 18 => {
839 assert!(version >= Version(1, 2));
840
841 match self {
842 Interface::ConsoleLog {
843 char_lists: ConsoleLogChars::Reg64(_),
844 ..
845 }
846 | Interface::Success {
847 args: SuccessArgs::Result64_2(_),
848 ..
849 }
850 | Interface::MsgSendDirectReq2 { .. }
851 | Interface::MsgSendDirectResp2 { .. } => {
852 self.pack_regs18(version, regs.try_into().unwrap());
853 }
854 _ => {
855 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
856 }
857 }
858 }
859 _ => panic!("Invalid number of registers {}", reg_cnt),
860 }
861 }
862
863 fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100864 a.fill(0);
865 if let Some(function_id) = self.function_id() {
866 a[0] = function_id as u64;
867 }
868
869 match *self {
870 Interface::Error {
871 target_info,
872 error_code,
873 } => {
874 a[1] = u32::from(target_info).into();
875 a[2] = (error_code as u32).into();
876 }
877 Interface::Success { target_info, args } => {
878 a[1] = target_info.into();
879 match args {
880 SuccessArgs::Result32(regs) => {
881 a[2] = regs[0].into();
882 a[3] = regs[1].into();
883 a[4] = regs[2].into();
884 a[5] = regs[3].into();
885 a[6] = regs[4].into();
886 a[7] = regs[5].into();
887 }
888 SuccessArgs::Result64(regs) => {
889 a[2] = regs[0];
890 a[3] = regs[1];
891 a[4] = regs[2];
892 a[5] = regs[3];
893 a[6] = regs[4];
894 a[7] = regs[5];
895 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100896 _ => panic!("{:#x?} requires 18 registers", args),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100897 }
898 }
899 Interface::Interrupt {
900 target_info,
901 interrupt_id,
902 } => {
903 a[1] = u32::from(target_info).into();
904 a[2] = interrupt_id.into();
905 }
906 Interface::Version { input_version } => {
907 a[1] = u32::from(input_version).into();
908 }
909 Interface::VersionOut { output_version } => {
910 a[0] = u32::from(output_version).into();
911 }
912 Interface::Features {
913 feat_id,
914 input_properties,
915 } => {
916 a[1] = u32::from(feat_id).into();
917 a[2] = input_properties.into();
918 }
919 Interface::RxAcquire { vm_id } => {
920 a[1] = vm_id.into();
921 }
922 Interface::RxRelease { vm_id } => {
923 a[1] = vm_id.into();
924 }
925 Interface::RxTxMap { addr, page_cnt } => {
926 match addr {
927 RxTxAddr::Addr32 { rx, tx } => {
928 a[1] = tx.into();
929 a[2] = rx.into();
930 }
931 RxTxAddr::Addr64 { rx, tx } => {
932 a[1] = tx;
933 a[2] = rx;
934 }
935 }
936 a[3] = page_cnt.into();
937 }
938 Interface::RxTxUnmap { id } => {
939 a[1] = id.into();
940 }
941 Interface::PartitionInfoGet { uuid, flags } => {
942 let bytes = uuid.into_bytes();
943 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
944 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
945 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
946 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
947 a[5] = flags.into();
948 }
949 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
950 Interface::Run { target_info } => {
951 a[1] = u32::from(target_info).into();
952 }
953 Interface::NormalWorldResume => {}
954 Interface::MsgSend2 {
955 sender_vm_id,
956 flags,
957 } => {
958 a[1] = sender_vm_id.into();
959 a[2] = flags.into();
960 }
961 Interface::MsgSendDirectReq {
962 src_id,
963 dst_id,
964 flags,
965 args,
966 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100967 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100968 a[2] = flags.into();
969 match args {
970 DirectMsgArgs::Args32(args) => {
971 a[3] = args[0].into();
972 a[4] = args[1].into();
973 a[5] = args[2].into();
974 a[6] = args[3].into();
975 a[7] = args[4].into();
976 }
977 DirectMsgArgs::Args64(args) => {
978 a[3] = args[0];
979 a[4] = args[1];
980 a[5] = args[2];
981 a[6] = args[3];
982 a[7] = args[4];
983 }
984 }
985 }
986 Interface::MsgSendDirectResp {
987 src_id,
988 dst_id,
989 flags,
990 args,
991 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100992 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100993 a[2] = flags.into();
994 match args {
995 DirectMsgArgs::Args32(args) => {
996 a[3] = args[0].into();
997 a[4] = args[1].into();
998 a[5] = args[2].into();
999 a[6] = args[3].into();
1000 a[7] = args[4].into();
1001 }
1002 DirectMsgArgs::Args64(args) => {
1003 a[3] = args[0];
1004 a[4] = args[1];
1005 a[5] = args[2];
1006 a[6] = args[3];
1007 a[7] = args[4];
1008 }
1009 }
1010 }
1011 Interface::MemDonate {
1012 total_len,
1013 frag_len,
1014 buf,
1015 } => {
1016 a[1] = total_len.into();
1017 a[2] = frag_len.into();
1018 (a[3], a[4]) = match buf {
1019 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1020 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1021 None => (0, 0),
1022 };
1023 }
1024 Interface::MemLend {
1025 total_len,
1026 frag_len,
1027 buf,
1028 } => {
1029 a[1] = total_len.into();
1030 a[2] = frag_len.into();
1031 (a[3], a[4]) = match buf {
1032 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1033 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1034 None => (0, 0),
1035 };
1036 }
1037 Interface::MemShare {
1038 total_len,
1039 frag_len,
1040 buf,
1041 } => {
1042 a[1] = total_len.into();
1043 a[2] = frag_len.into();
1044 (a[3], a[4]) = match buf {
1045 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1046 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1047 None => (0, 0),
1048 };
1049 }
1050 Interface::MemRetrieveReq {
1051 total_len,
1052 frag_len,
1053 buf,
1054 } => {
1055 a[1] = total_len.into();
1056 a[2] = frag_len.into();
1057 (a[3], a[4]) = match buf {
1058 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1059 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1060 None => (0, 0),
1061 };
1062 }
1063 Interface::MemRetrieveResp {
1064 total_len,
1065 frag_len,
1066 } => {
1067 a[1] = total_len.into();
1068 a[2] = frag_len.into();
1069 }
1070 Interface::MemRelinquish => {}
1071 Interface::MemReclaim { handle, flags } => {
1072 let handle_regs: [u32; 2] = handle.into();
1073 a[1] = handle_regs[0].into();
1074 a[2] = handle_regs[1].into();
1075 a[3] = flags.into();
1076 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001077 Interface::MemPermGet { addr, page_cnt } => {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001078 a[1] = match addr {
1079 MemAddr::Addr32(addr) => addr.into(),
1080 MemAddr::Addr64(addr) => addr,
1081 };
Balint Dobszayde0dc802025-02-28 14:16:52 +01001082 a[2] = if version >= Version(1, 3) {
1083 page_cnt.unwrap().into()
1084 } else {
1085 assert!(page_cnt.is_none());
1086 0
1087 }
Balint Dobszay3aad9572025-01-17 16:54:11 +01001088 }
1089 Interface::MemPermSet {
1090 addr,
1091 page_cnt,
1092 mem_perm,
1093 } => {
1094 a[1] = match addr {
1095 MemAddr::Addr32(addr) => addr.into(),
1096 MemAddr::Addr64(addr) => addr,
1097 };
1098 a[2] = page_cnt.into();
1099 a[3] = mem_perm.into();
1100 }
1101 Interface::ConsoleLog {
1102 char_cnt,
1103 char_lists,
1104 } => {
1105 a[1] = char_cnt.into();
1106 match char_lists {
1107 ConsoleLogChars::Reg32(regs) => {
1108 a[2] = regs[0].into();
1109 a[3] = regs[1].into();
1110 a[4] = regs[2].into();
1111 a[5] = regs[3].into();
1112 a[6] = regs[4].into();
1113 a[7] = regs[5].into();
1114 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001115 _ => panic!("{:#x?} requires 18 registers", char_lists),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001116 }
1117 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001118 _ => panic!("{:#x?} requires 18 registers", self),
1119 }
1120 }
1121
1122 fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
1123 assert!(version >= Version(1, 2));
1124
1125 a.fill(0);
1126 if let Some(function_id) = self.function_id() {
1127 a[0] = function_id as u64;
1128 }
1129
1130 match *self {
1131 Interface::Success { target_info, args } => {
1132 a[1] = target_info.into();
1133 match args {
1134 SuccessArgs::Result64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
1135 _ => panic!("{:#x?} requires 8 registers", args),
1136 }
1137 }
1138 Interface::MsgSendDirectReq2 {
1139 src_id,
1140 dst_id,
1141 uuid,
1142 args,
1143 } => {
1144 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1145 (a[2], a[3]) = uuid.as_u64_pair();
1146 a[4..18].copy_from_slice(&args.0[..14]);
1147 }
1148 Interface::MsgSendDirectResp2 {
1149 src_id,
1150 dst_id,
1151 args,
1152 } => {
1153 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1154 a[2] = 0;
1155 a[3] = 0;
1156 a[4..18].copy_from_slice(&args.0[..14]);
1157 }
1158 Interface::ConsoleLog {
1159 char_cnt,
1160 char_lists,
1161 } => {
1162 a[1] = char_cnt.into();
1163 match char_lists {
1164 ConsoleLogChars::Reg64(regs) => a[2..18].copy_from_slice(&regs[..16]),
1165 _ => panic!("{:#x?} requires 8 registers", char_lists),
1166 }
1167 }
1168 _ => panic!("{:#x?} requires 8 registers", self),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001169 }
1170 }
1171
Balint Dobszaya5846852025-02-26 15:38:53 +01001172 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001173 pub fn success32_noargs() -> Self {
1174 Self::Success {
1175 target_info: 0,
1176 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1177 }
1178 }
1179
Balint Dobszaya5846852025-02-26 15:38:53 +01001180 /// Helper function to create an `FFA_ERROR` interface with an error code.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001181 pub fn error(error_code: FfaError) -> Self {
1182 Self::Error {
1183 target_info: TargetInfo {
1184 endpoint_id: 0,
1185 vcpu_id: 0,
1186 },
1187 error_code,
1188 }
1189 }
1190}
1191
Balint Dobszaya5846852025-02-26 15:38:53 +01001192/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
1193pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
Balint Dobszayde0dc802025-02-28 14:16:52 +01001194/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message.
1195pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 128;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001196
Balint Dobszaya5846852025-02-26 15:38:53 +01001197/// Helper function to convert the "Tightly packed list of characters" format used by the
1198/// `FFA_CONSOLE_LOG` interface into a byte slice.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001199pub fn parse_console_log(
1200 char_cnt: u8,
1201 char_lists: &ConsoleLogChars,
1202 log_bytes: &mut [u8],
1203) -> Result<(), FfaError> {
1204 match char_lists {
1205 ConsoleLogChars::Reg32(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001206 if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001207 return Err(FfaError::InvalidParameters);
1208 }
1209 for (i, reg) in regs.iter().enumerate() {
1210 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1211 }
1212 }
1213 ConsoleLogChars::Reg64(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001214 if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001215 return Err(FfaError::InvalidParameters);
1216 }
1217 for (i, reg) in regs.iter().enumerate() {
1218 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1219 }
1220 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001221 }
1222
Balint Dobszayc8802492025-01-15 18:11:39 +01001223 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001224}