blob: fda75d460e9957c884a0c0460d867ab5715da885 [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,
Tomás González17b92442025-03-10 16:45:04 +000098 SecondaryEpRegister32 = 0x84000087,
99 SecondaryEpRegister64 = 0xc4000087,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200100 MemDonate32 = 0x84000071,
101 MemDonate64 = 0xc4000071,
102 MemLend32 = 0x84000072,
103 MemLend64 = 0xc4000072,
104 MemShare32 = 0x84000073,
105 MemShare64 = 0xc4000073,
106 MemRetrieveReq32 = 0x84000074,
107 MemRetrieveReq64 = 0xc4000074,
108 MemRetrieveResp = 0x84000075,
109 MemRelinquish = 0x84000076,
110 MemReclaim = 0x84000077,
111 MemPermGet32 = 0x84000088,
112 MemPermGet64 = 0xc4000088,
113 MemPermSet32 = 0x84000089,
114 MemPermSet64 = 0xc4000089,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200115}
116
Balint Dobszayde0dc802025-02-28 14:16:52 +0100117impl FuncId {
118 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
119 pub fn is_32bit(&self) -> bool {
120 u32::from(*self) & (1 << 30) != 0
121 }
122}
123
Balint Dobszaya5846852025-02-26 15:38:53 +0100124/// Error status codes used by the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100125#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
126#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
127#[repr(i32)]
128pub enum FfaError {
129 #[error("Not supported")]
130 NotSupported = -1,
131 #[error("Invalid parameters")]
132 InvalidParameters = -2,
133 #[error("No memory")]
134 NoMemory = -3,
135 #[error("Busy")]
136 Busy = -4,
137 #[error("Interrupted")]
138 Interrupted = -5,
139 #[error("Denied")]
140 Denied = -6,
141 #[error("Retry")]
142 Retry = -7,
143 #[error("Aborted")]
144 Aborted = -8,
145 #[error("No data")]
146 NoData = -9,
147}
148
Balint Dobszaya5846852025-02-26 15:38:53 +0100149/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200150#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Balint Dobszay3aad9572025-01-17 16:54:11 +0100151pub struct TargetInfo {
152 pub endpoint_id: u16,
153 pub vcpu_id: u16,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200154}
155
Balint Dobszay3aad9572025-01-17 16:54:11 +0100156impl From<u32> for TargetInfo {
157 fn from(value: u32) -> Self {
158 Self {
159 endpoint_id: (value >> 16) as u16,
160 vcpu_id: value as u16,
161 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200162 }
163}
164
Balint Dobszay3aad9572025-01-17 16:54:11 +0100165impl From<TargetInfo> for u32 {
166 fn from(value: TargetInfo) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100167 ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
Andrew Walbran0d315812024-11-25 15:36:36 +0000168 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100169}
Andrew Walbran0d315812024-11-25 15:36:36 +0000170
Balint Dobszaya5846852025-02-26 15:38:53 +0100171/// Arguments for the `FFA_SUCCESS` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100172#[derive(Debug, Eq, PartialEq, Clone, Copy)]
173pub enum SuccessArgs {
174 Result32([u32; 6]),
175 Result64([u64; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100176 Result64_2([u64; 16]),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200177}
178
Tomás González17b92442025-03-10 16:45:04 +0000179/// Entrypoint address argument for `FFA_SECONDARY_EP_REGISTER` interface.
180#[derive(Debug, Eq, PartialEq, Clone, Copy)]
181pub enum SecondaryEpRegisterAddr {
182 Addr32(u32),
183 Addr64(u64),
184}
185
Balint Dobszaya5846852025-02-26 15:38:53 +0100186/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100187#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200188pub struct Version(pub u16, pub u16);
189
Tomás González1f794352025-03-03 16:47:06 +0000190impl Version {
191 /// Returns whether the caller's version (self) is compatible with the callee's version (input
192 /// parameter)
193 pub fn is_compatible_to(&self, callee_version: &Version) -> bool {
194 self.0 == callee_version.0 && self.1 <= callee_version.1
195 }
196}
197
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200198impl From<u32> for Version {
199 fn from(val: u32) -> Self {
200 Self((val >> 16) as u16, val as u16)
201 }
202}
203
204impl From<Version> for u32 {
205 fn from(v: Version) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100206 ((v.0 as u32) << 16) | v.1 as u32
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200207 }
208}
209
Andrew Walbran19970ba2024-11-25 15:35:00 +0000210impl Display for Version {
211 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
212 write!(f, "{}.{}", self.0, self.1)
213 }
214}
215
216impl Debug for Version {
217 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
218 Display::fmt(self, f)
219 }
220}
221
Balint Dobszaya5846852025-02-26 15:38:53 +0100222/// Feature IDs used by the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100223#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
224#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
225#[repr(u8)]
226pub enum FeatureId {
227 NotificationPendingInterrupt = 0x1,
228 ScheduleReceiverInterrupt = 0x2,
229 ManagedExitInterrupt = 0x3,
230}
Balint Dobszayc8802492025-01-15 18:11:39 +0100231
Balint Dobszaya5846852025-02-26 15:38:53 +0100232/// Arguments for the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100233#[derive(Debug, Eq, PartialEq, Clone, Copy)]
234pub enum Feature {
235 FuncId(FuncId),
236 FeatureId(FeatureId),
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100237 Unknown(u32),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100238}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200239
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100240impl From<u32> for Feature {
241 fn from(value: u32) -> Self {
242 // Bit[31] is set for all valid FF-A function IDs so we don't have to check it separately
243 if let Ok(func_id) = value.try_into() {
244 Self::FuncId(func_id)
245 } else if let Ok(feat_id) = (value as u8).try_into() {
246 Self::FeatureId(feat_id)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100247 } else {
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100248 Self::Unknown(value)
249 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100250 }
251}
252
253impl From<Feature> for u32 {
254 fn from(value: Feature) -> Self {
255 match value {
256 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
257 Feature::FeatureId(feature_id) => feature_id as u32,
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100258 Feature::Unknown(id) => panic!("Unknown feature or function ID {:#x?}", id),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100259 }
260 }
261}
262
Balint Dobszaya5846852025-02-26 15:38:53 +0100263/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100264#[derive(Debug, Eq, PartialEq, Clone, Copy)]
265pub enum RxTxAddr {
266 Addr32 { rx: u32, tx: u32 },
267 Addr64 { rx: u64, tx: u64 },
268}
269
Balint Dobszaya5846852025-02-26 15:38:53 +0100270/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100271#[derive(Debug, Eq, PartialEq, Clone, Copy)]
272pub enum DirectMsgArgs {
273 Args32([u32; 5]),
274 Args64([u64; 5]),
275}
276
Balint Dobszayde0dc802025-02-28 14:16:52 +0100277/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
278#[derive(Debug, Eq, PartialEq, Clone, Copy)]
279pub struct DirectMsg2Args([u64; 14]);
280
Balint Dobszaya5846852025-02-26 15:38:53 +0100281/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
282/// descriptor. Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX
283/// buffer is not used to transmit the transaction descriptor.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100284#[derive(Debug, Eq, PartialEq, Clone, Copy)]
285pub enum MemOpBuf {
286 Buf32 { addr: u32, page_cnt: u32 },
287 Buf64 { addr: u64, page_cnt: u32 },
288}
289
Balint Dobszaya5846852025-02-26 15:38:53 +0100290/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100291#[derive(Debug, Eq, PartialEq, Clone, Copy)]
292pub enum MemAddr {
293 Addr32(u32),
294 Addr64(u64),
295}
296
Balint Dobszayde0dc802025-02-28 14:16:52 +0100297/// Argument for the `FFA_CONSOLE_LOG` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100298#[derive(Debug, Eq, PartialEq, Clone, Copy)]
299pub enum ConsoleLogChars {
300 Reg32([u32; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100301 Reg64([u64; 16]),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100302}
303
Balint Dobszaya5846852025-02-26 15:38:53 +0100304/// FF-A "message types", the terminology used by the spec is "interfaces". The interfaces are used
305/// by FF-A components for communication at an FF-A instance. The spec also describes the valid FF-A
306/// instances and conduits for each interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100307#[derive(Debug, Eq, PartialEq, Clone, Copy)]
308pub enum Interface {
309 Error {
310 target_info: TargetInfo,
311 error_code: FfaError,
312 },
313 Success {
314 target_info: u32,
315 args: SuccessArgs,
316 },
317 Interrupt {
318 target_info: TargetInfo,
319 interrupt_id: u32,
320 },
321 Version {
322 input_version: Version,
323 },
324 VersionOut {
325 output_version: Version,
326 },
327 Features {
328 feat_id: Feature,
329 input_properties: u32,
330 },
331 RxAcquire {
332 vm_id: u16,
333 },
334 RxRelease {
335 vm_id: u16,
336 },
337 RxTxMap {
338 addr: RxTxAddr,
339 page_cnt: u32,
340 },
341 RxTxUnmap {
342 id: u16,
343 },
344 PartitionInfoGet {
345 uuid: Uuid,
346 flags: u32,
347 },
348 IdGet,
349 SpmIdGet,
350 MsgWait,
351 Yield,
352 Run {
353 target_info: TargetInfo,
354 },
355 NormalWorldResume,
Tomás González17b92442025-03-10 16:45:04 +0000356 SecondaryEpRegister {
357 entrypoint: SecondaryEpRegisterAddr,
358 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100359 MsgSend2 {
360 sender_vm_id: u16,
361 flags: u32,
362 },
363 MsgSendDirectReq {
364 src_id: u16,
365 dst_id: u16,
366 flags: u32,
367 args: DirectMsgArgs,
368 },
369 MsgSendDirectResp {
370 src_id: u16,
371 dst_id: u16,
372 flags: u32,
373 args: DirectMsgArgs,
374 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100375 MsgSendDirectReq2 {
376 src_id: u16,
377 dst_id: u16,
378 uuid: Uuid,
379 args: DirectMsg2Args,
380 },
381 MsgSendDirectResp2 {
382 src_id: u16,
383 dst_id: u16,
384 args: DirectMsg2Args,
385 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100386 MemDonate {
387 total_len: u32,
388 frag_len: u32,
389 buf: Option<MemOpBuf>,
390 },
391 MemLend {
392 total_len: u32,
393 frag_len: u32,
394 buf: Option<MemOpBuf>,
395 },
396 MemShare {
397 total_len: u32,
398 frag_len: u32,
399 buf: Option<MemOpBuf>,
400 },
401 MemRetrieveReq {
402 total_len: u32,
403 frag_len: u32,
404 buf: Option<MemOpBuf>,
405 },
406 MemRetrieveResp {
407 total_len: u32,
408 frag_len: u32,
409 },
410 MemRelinquish,
411 MemReclaim {
412 handle: memory_management::Handle,
413 flags: u32,
414 },
415 MemPermGet {
416 addr: MemAddr,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100417 page_cnt: Option<u32>,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100418 },
419 MemPermSet {
420 addr: MemAddr,
421 page_cnt: u32,
422 mem_perm: u32,
423 },
424 ConsoleLog {
425 char_cnt: u8,
426 char_lists: ConsoleLogChars,
427 },
428}
429
Balint Dobszayde0dc802025-02-28 14:16:52 +0100430impl Interface {
431 /// Returns the function ID for the call, if it has one.
432 pub fn function_id(&self) -> Option<FuncId> {
433 match self {
434 Interface::Error { .. } => Some(FuncId::Error),
435 Interface::Success { args, .. } => match args {
436 SuccessArgs::Result32(..) => Some(FuncId::Success32),
437 SuccessArgs::Result64(..) | SuccessArgs::Result64_2(..) => Some(FuncId::Success64),
438 },
439 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
440 Interface::Version { .. } => Some(FuncId::Version),
441 Interface::VersionOut { .. } => None,
442 Interface::Features { .. } => Some(FuncId::Features),
443 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
444 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
445 Interface::RxTxMap { addr, .. } => match addr {
446 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
447 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
448 },
449 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
450 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
451 Interface::IdGet => Some(FuncId::IdGet),
452 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
453 Interface::MsgWait => Some(FuncId::MsgWait),
454 Interface::Yield => Some(FuncId::Yield),
455 Interface::Run { .. } => Some(FuncId::Run),
456 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
Tomás González17b92442025-03-10 16:45:04 +0000457 Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
458 SecondaryEpRegisterAddr::Addr32 { .. } => Some(FuncId::SecondaryEpRegister32),
459 SecondaryEpRegisterAddr::Addr64 { .. } => Some(FuncId::SecondaryEpRegister64),
460 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100461 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
462 Interface::MsgSendDirectReq { args, .. } => match args {
463 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
464 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
465 },
466 Interface::MsgSendDirectResp { args, .. } => match args {
467 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
468 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
469 },
470 Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
471 Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
472 Interface::MemDonate { buf, .. } => match buf {
473 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
474 _ => Some(FuncId::MemDonate32),
475 },
476 Interface::MemLend { buf, .. } => match buf {
477 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
478 _ => Some(FuncId::MemLend32),
479 },
480 Interface::MemShare { buf, .. } => match buf {
481 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
482 _ => Some(FuncId::MemShare32),
483 },
484 Interface::MemRetrieveReq { buf, .. } => match buf {
485 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
486 _ => Some(FuncId::MemRetrieveReq32),
487 },
488 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
489 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
490 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
491 Interface::MemPermGet { addr, .. } => match addr {
492 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
493 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
494 },
495 Interface::MemPermSet { addr, .. } => match addr {
496 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
497 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
498 },
499 Interface::ConsoleLog { char_lists, .. } => match char_lists {
500 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
501 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
502 },
503 }
504 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100505
Balint Dobszayde0dc802025-02-28 14:16:52 +0100506 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
507 pub fn is_32bit(&self) -> bool {
508 // TODO: self should always have a function ID?
509 self.function_id().unwrap().is_32bit()
510 }
511
512 /// Parse interface from register contents. The caller must ensure that the `regs` argument has
513 /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
514 pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
515 let reg_cnt = regs.len();
516
517 let msg = match reg_cnt {
518 8 => {
519 assert!(version <= Version(1, 1));
520 Interface::unpack_regs8(version, regs.try_into().unwrap())?
521 }
522 18 => {
523 assert!(version >= Version(1, 2));
524 match FuncId::try_from(regs[0] as u32)? {
525 FuncId::ConsoleLog64
526 | FuncId::Success64
527 | FuncId::MsgSendDirectReq64_2
528 | FuncId::MsgSendDirectResp64_2 => {
529 Interface::unpack_regs18(version, regs.try_into().unwrap())?
530 }
531 _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
532 }
533 }
534 _ => panic!(
535 "Invalid number of registers ({}) for FF-A version {}",
536 reg_cnt, version
537 ),
538 };
539
540 Ok(msg)
541 }
542
543 fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100544 let fid = FuncId::try_from(regs[0] as u32)?;
545
546 let msg = match fid {
547 FuncId::Error => Self::Error {
548 target_info: (regs[1] as u32).into(),
549 error_code: FfaError::try_from(regs[2] as i32)?,
550 },
551 FuncId::Success32 => Self::Success {
552 target_info: regs[1] as u32,
553 args: SuccessArgs::Result32([
554 regs[2] as u32,
555 regs[3] as u32,
556 regs[4] as u32,
557 regs[5] as u32,
558 regs[6] as u32,
559 regs[7] as u32,
560 ]),
561 },
562 FuncId::Success64 => Self::Success {
563 target_info: regs[1] as u32,
564 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
565 },
566 FuncId::Interrupt => Self::Interrupt {
567 target_info: (regs[1] as u32).into(),
568 interrupt_id: regs[2] as u32,
569 },
570 FuncId::Version => Self::Version {
571 input_version: (regs[1] as u32).into(),
572 },
573 FuncId::Features => Self::Features {
Balint Dobszayc31e0b92025-03-03 20:16:56 +0100574 feat_id: (regs[1] as u32).into(),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100575 input_properties: regs[2] as u32,
576 },
577 FuncId::RxAcquire => Self::RxAcquire {
578 vm_id: regs[1] as u16,
579 },
580 FuncId::RxRelease => Self::RxRelease {
581 vm_id: regs[1] as u16,
582 },
583 FuncId::RxTxMap32 => {
584 let addr = RxTxAddr::Addr32 {
585 rx: regs[2] as u32,
586 tx: regs[1] as u32,
587 };
588 let page_cnt = regs[3] as u32;
589
590 Self::RxTxMap { addr, page_cnt }
591 }
592 FuncId::RxTxMap64 => {
593 let addr = RxTxAddr::Addr64 {
594 rx: regs[2],
595 tx: regs[1],
596 };
597 let page_cnt = regs[3] as u32;
598
599 Self::RxTxMap { addr, page_cnt }
600 }
601 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
602 FuncId::PartitionInfoGet => {
603 let uuid_words = [
604 regs[1] as u32,
605 regs[2] as u32,
606 regs[3] as u32,
607 regs[4] as u32,
608 ];
609 let mut bytes: [u8; 16] = [0; 16];
610 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
611 bytes[i] = b;
612 }
613 Self::PartitionInfoGet {
614 uuid: Uuid::from_bytes(bytes),
615 flags: regs[5] as u32,
616 }
617 }
618 FuncId::IdGet => Self::IdGet,
619 FuncId::SpmIdGet => Self::SpmIdGet,
620 FuncId::MsgWait => Self::MsgWait,
621 FuncId::Yield => Self::Yield,
622 FuncId::Run => Self::Run {
623 target_info: (regs[1] as u32).into(),
624 },
625 FuncId::NormalWorldResume => Self::NormalWorldResume,
Tomás González17b92442025-03-10 16:45:04 +0000626 FuncId::SecondaryEpRegister32 => Self::SecondaryEpRegister {
627 entrypoint: SecondaryEpRegisterAddr::Addr32(regs[1] as u32),
628 },
629 FuncId::SecondaryEpRegister64 => Self::SecondaryEpRegister {
630 entrypoint: SecondaryEpRegisterAddr::Addr64(regs[1]),
631 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100632 FuncId::MsgSend2 => Self::MsgSend2 {
633 sender_vm_id: regs[1] as u16,
634 flags: regs[2] as u32,
635 },
636 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
637 src_id: (regs[1] >> 16) as u16,
638 dst_id: regs[1] as u16,
639 flags: regs[2] as u32,
640 args: DirectMsgArgs::Args32([
641 regs[3] as u32,
642 regs[4] as u32,
643 regs[5] as u32,
644 regs[6] as u32,
645 regs[7] as u32,
646 ]),
647 },
648 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
649 src_id: (regs[1] >> 16) as u16,
650 dst_id: regs[1] as u16,
651 flags: regs[2] as u32,
652 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
653 },
654 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
655 src_id: (regs[1] >> 16) as u16,
656 dst_id: regs[1] as u16,
657 flags: regs[2] as u32,
658 args: DirectMsgArgs::Args32([
659 regs[3] as u32,
660 regs[4] as u32,
661 regs[5] as u32,
662 regs[6] as u32,
663 regs[7] as u32,
664 ]),
665 },
666 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
667 src_id: (regs[1] >> 16) as u16,
668 dst_id: regs[1] as u16,
669 flags: regs[2] as u32,
670 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
671 },
672 FuncId::MemDonate32 => Self::MemDonate {
673 total_len: regs[1] as u32,
674 frag_len: regs[2] as u32,
675 buf: if regs[3] != 0 && regs[4] != 0 {
676 Some(MemOpBuf::Buf32 {
677 addr: regs[3] as u32,
678 page_cnt: regs[4] as u32,
679 })
680 } else {
681 None
682 },
683 },
684 FuncId::MemDonate64 => Self::MemDonate {
685 total_len: regs[1] as u32,
686 frag_len: regs[2] as u32,
687 buf: if regs[3] != 0 && regs[4] != 0 {
688 Some(MemOpBuf::Buf64 {
689 addr: regs[3],
690 page_cnt: regs[4] as u32,
691 })
692 } else {
693 None
694 },
695 },
696 FuncId::MemLend32 => Self::MemLend {
697 total_len: regs[1] as u32,
698 frag_len: regs[2] as u32,
699 buf: if regs[3] != 0 && regs[4] != 0 {
700 Some(MemOpBuf::Buf32 {
701 addr: regs[3] as u32,
702 page_cnt: regs[4] as u32,
703 })
704 } else {
705 None
706 },
707 },
708 FuncId::MemLend64 => Self::MemLend {
709 total_len: regs[1] as u32,
710 frag_len: regs[2] as u32,
711 buf: if regs[3] != 0 && regs[4] != 0 {
712 Some(MemOpBuf::Buf64 {
713 addr: regs[3],
714 page_cnt: regs[4] as u32,
715 })
716 } else {
717 None
718 },
719 },
720 FuncId::MemShare32 => Self::MemShare {
721 total_len: regs[1] as u32,
722 frag_len: regs[2] as u32,
723 buf: if regs[3] != 0 && regs[4] != 0 {
724 Some(MemOpBuf::Buf32 {
725 addr: regs[3] as u32,
726 page_cnt: regs[4] as u32,
727 })
728 } else {
729 None
730 },
731 },
732 FuncId::MemShare64 => Self::MemShare {
733 total_len: regs[1] as u32,
734 frag_len: regs[2] as u32,
735 buf: if regs[3] != 0 && regs[4] != 0 {
736 Some(MemOpBuf::Buf64 {
737 addr: regs[3],
738 page_cnt: regs[4] as u32,
739 })
740 } else {
741 None
742 },
743 },
744 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
745 total_len: regs[1] as u32,
746 frag_len: regs[2] as u32,
747 buf: if regs[3] != 0 && regs[4] != 0 {
748 Some(MemOpBuf::Buf32 {
749 addr: regs[3] as u32,
750 page_cnt: regs[4] as u32,
751 })
752 } else {
753 None
754 },
755 },
756 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
757 total_len: regs[1] as u32,
758 frag_len: regs[2] as u32,
759 buf: if regs[3] != 0 && regs[4] != 0 {
760 Some(MemOpBuf::Buf64 {
761 addr: regs[3],
762 page_cnt: regs[4] as u32,
763 })
764 } else {
765 None
766 },
767 },
768 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
769 total_len: regs[1] as u32,
770 frag_len: regs[2] as u32,
771 },
772 FuncId::MemRelinquish => Self::MemRelinquish,
773 FuncId::MemReclaim => Self::MemReclaim {
774 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
775 flags: regs[3] as u32,
776 },
777 FuncId::MemPermGet32 => Self::MemPermGet {
778 addr: MemAddr::Addr32(regs[1] as u32),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100779 page_cnt: if version >= Version(1, 3) {
780 Some(regs[2] as u32)
781 } else {
782 None
783 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100784 },
785 FuncId::MemPermGet64 => Self::MemPermGet {
786 addr: MemAddr::Addr64(regs[1]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100787 page_cnt: if version >= Version(1, 3) {
788 Some(regs[2] as u32)
789 } else {
790 None
791 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100792 },
793 FuncId::MemPermSet32 => Self::MemPermSet {
794 addr: MemAddr::Addr32(regs[1] as u32),
795 page_cnt: regs[2] as u32,
796 mem_perm: regs[3] as u32,
797 },
798 FuncId::MemPermSet64 => Self::MemPermSet {
799 addr: MemAddr::Addr64(regs[1]),
800 page_cnt: regs[2] as u32,
801 mem_perm: regs[3] as u32,
802 },
803 FuncId::ConsoleLog32 => Self::ConsoleLog {
804 char_cnt: regs[1] as u8,
805 char_lists: ConsoleLogChars::Reg32([
806 regs[2] as u32,
807 regs[3] as u32,
808 regs[4] as u32,
809 regs[5] as u32,
810 regs[6] as u32,
811 regs[7] as u32,
812 ]),
813 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100814 _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100815 };
816
817 Ok(msg)
818 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100819
Balint Dobszayde0dc802025-02-28 14:16:52 +0100820 fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
821 assert!(version >= Version(1, 2));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200822
Balint Dobszayde0dc802025-02-28 14:16:52 +0100823 let fid = FuncId::try_from(regs[0] as u32)?;
824
825 let msg = match fid {
826 FuncId::Success64 => Self::Success {
827 target_info: regs[1] as u32,
828 args: SuccessArgs::Result64_2(regs[2..18].try_into().unwrap()),
829 },
830 FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
831 src_id: (regs[1] >> 16) as u16,
832 dst_id: regs[1] as u16,
833 uuid: Uuid::from_u64_pair(regs[2], regs[3]),
834 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
835 },
836 FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
837 src_id: (regs[1] >> 16) as u16,
838 dst_id: regs[1] as u16,
839 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
840 },
841 FuncId::ConsoleLog64 => Self::ConsoleLog {
842 char_cnt: regs[1] as u8,
843 char_lists: ConsoleLogChars::Reg64(regs[2..18].try_into().unwrap()),
844 },
845 _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
846 };
847
848 Ok(msg)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100849 }
850
Balint Dobszaya5846852025-02-26 15:38:53 +0100851 /// Create register contents for an interface.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100852 pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
853 let reg_cnt = regs.len();
854
855 match reg_cnt {
856 8 => {
857 assert!(version <= Version(1, 1));
858 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
859 }
860 18 => {
861 assert!(version >= Version(1, 2));
862
863 match self {
864 Interface::ConsoleLog {
865 char_lists: ConsoleLogChars::Reg64(_),
866 ..
867 }
868 | Interface::Success {
869 args: SuccessArgs::Result64_2(_),
870 ..
871 }
872 | Interface::MsgSendDirectReq2 { .. }
873 | Interface::MsgSendDirectResp2 { .. } => {
874 self.pack_regs18(version, regs.try_into().unwrap());
875 }
876 _ => {
877 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
878 }
879 }
880 }
881 _ => panic!("Invalid number of registers {}", reg_cnt),
882 }
883 }
884
885 fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100886 a.fill(0);
887 if let Some(function_id) = self.function_id() {
888 a[0] = function_id as u64;
889 }
890
891 match *self {
892 Interface::Error {
893 target_info,
894 error_code,
895 } => {
896 a[1] = u32::from(target_info).into();
897 a[2] = (error_code as u32).into();
898 }
899 Interface::Success { target_info, args } => {
900 a[1] = target_info.into();
901 match args {
902 SuccessArgs::Result32(regs) => {
903 a[2] = regs[0].into();
904 a[3] = regs[1].into();
905 a[4] = regs[2].into();
906 a[5] = regs[3].into();
907 a[6] = regs[4].into();
908 a[7] = regs[5].into();
909 }
910 SuccessArgs::Result64(regs) => {
911 a[2] = regs[0];
912 a[3] = regs[1];
913 a[4] = regs[2];
914 a[5] = regs[3];
915 a[6] = regs[4];
916 a[7] = regs[5];
917 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100918 _ => panic!("{:#x?} requires 18 registers", args),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100919 }
920 }
921 Interface::Interrupt {
922 target_info,
923 interrupt_id,
924 } => {
925 a[1] = u32::from(target_info).into();
926 a[2] = interrupt_id.into();
927 }
928 Interface::Version { input_version } => {
929 a[1] = u32::from(input_version).into();
930 }
931 Interface::VersionOut { output_version } => {
932 a[0] = u32::from(output_version).into();
933 }
934 Interface::Features {
935 feat_id,
936 input_properties,
937 } => {
938 a[1] = u32::from(feat_id).into();
939 a[2] = input_properties.into();
940 }
941 Interface::RxAcquire { vm_id } => {
942 a[1] = vm_id.into();
943 }
944 Interface::RxRelease { vm_id } => {
945 a[1] = vm_id.into();
946 }
947 Interface::RxTxMap { addr, page_cnt } => {
948 match addr {
949 RxTxAddr::Addr32 { rx, tx } => {
950 a[1] = tx.into();
951 a[2] = rx.into();
952 }
953 RxTxAddr::Addr64 { rx, tx } => {
954 a[1] = tx;
955 a[2] = rx;
956 }
957 }
958 a[3] = page_cnt.into();
959 }
960 Interface::RxTxUnmap { id } => {
961 a[1] = id.into();
962 }
963 Interface::PartitionInfoGet { uuid, flags } => {
964 let bytes = uuid.into_bytes();
965 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
966 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
967 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
968 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
969 a[5] = flags.into();
970 }
971 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
972 Interface::Run { target_info } => {
973 a[1] = u32::from(target_info).into();
974 }
975 Interface::NormalWorldResume => {}
Tomás González17b92442025-03-10 16:45:04 +0000976 Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
977 SecondaryEpRegisterAddr::Addr32(addr) => a[1] = addr as u64,
978 SecondaryEpRegisterAddr::Addr64(addr) => a[1] = addr,
979 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100980 Interface::MsgSend2 {
981 sender_vm_id,
982 flags,
983 } => {
984 a[1] = sender_vm_id.into();
985 a[2] = flags.into();
986 }
987 Interface::MsgSendDirectReq {
988 src_id,
989 dst_id,
990 flags,
991 args,
992 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100993 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100994 a[2] = flags.into();
995 match args {
996 DirectMsgArgs::Args32(args) => {
997 a[3] = args[0].into();
998 a[4] = args[1].into();
999 a[5] = args[2].into();
1000 a[6] = args[3].into();
1001 a[7] = args[4].into();
1002 }
1003 DirectMsgArgs::Args64(args) => {
1004 a[3] = args[0];
1005 a[4] = args[1];
1006 a[5] = args[2];
1007 a[6] = args[3];
1008 a[7] = args[4];
1009 }
1010 }
1011 }
1012 Interface::MsgSendDirectResp {
1013 src_id,
1014 dst_id,
1015 flags,
1016 args,
1017 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +01001018 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001019 a[2] = flags.into();
1020 match args {
1021 DirectMsgArgs::Args32(args) => {
1022 a[3] = args[0].into();
1023 a[4] = args[1].into();
1024 a[5] = args[2].into();
1025 a[6] = args[3].into();
1026 a[7] = args[4].into();
1027 }
1028 DirectMsgArgs::Args64(args) => {
1029 a[3] = args[0];
1030 a[4] = args[1];
1031 a[5] = args[2];
1032 a[6] = args[3];
1033 a[7] = args[4];
1034 }
1035 }
1036 }
1037 Interface::MemDonate {
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::MemLend {
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::MemShare {
1064 total_len,
1065 frag_len,
1066 buf,
1067 } => {
1068 a[1] = total_len.into();
1069 a[2] = frag_len.into();
1070 (a[3], a[4]) = match buf {
1071 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1072 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1073 None => (0, 0),
1074 };
1075 }
1076 Interface::MemRetrieveReq {
1077 total_len,
1078 frag_len,
1079 buf,
1080 } => {
1081 a[1] = total_len.into();
1082 a[2] = frag_len.into();
1083 (a[3], a[4]) = match buf {
1084 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1085 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1086 None => (0, 0),
1087 };
1088 }
1089 Interface::MemRetrieveResp {
1090 total_len,
1091 frag_len,
1092 } => {
1093 a[1] = total_len.into();
1094 a[2] = frag_len.into();
1095 }
1096 Interface::MemRelinquish => {}
1097 Interface::MemReclaim { handle, flags } => {
1098 let handle_regs: [u32; 2] = handle.into();
1099 a[1] = handle_regs[0].into();
1100 a[2] = handle_regs[1].into();
1101 a[3] = flags.into();
1102 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001103 Interface::MemPermGet { addr, page_cnt } => {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001104 a[1] = match addr {
1105 MemAddr::Addr32(addr) => addr.into(),
1106 MemAddr::Addr64(addr) => addr,
1107 };
Balint Dobszayde0dc802025-02-28 14:16:52 +01001108 a[2] = if version >= Version(1, 3) {
1109 page_cnt.unwrap().into()
1110 } else {
1111 assert!(page_cnt.is_none());
1112 0
1113 }
Balint Dobszay3aad9572025-01-17 16:54:11 +01001114 }
1115 Interface::MemPermSet {
1116 addr,
1117 page_cnt,
1118 mem_perm,
1119 } => {
1120 a[1] = match addr {
1121 MemAddr::Addr32(addr) => addr.into(),
1122 MemAddr::Addr64(addr) => addr,
1123 };
1124 a[2] = page_cnt.into();
1125 a[3] = mem_perm.into();
1126 }
1127 Interface::ConsoleLog {
1128 char_cnt,
1129 char_lists,
1130 } => {
1131 a[1] = char_cnt.into();
1132 match char_lists {
1133 ConsoleLogChars::Reg32(regs) => {
1134 a[2] = regs[0].into();
1135 a[3] = regs[1].into();
1136 a[4] = regs[2].into();
1137 a[5] = regs[3].into();
1138 a[6] = regs[4].into();
1139 a[7] = regs[5].into();
1140 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001141 _ => panic!("{:#x?} requires 18 registers", char_lists),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001142 }
1143 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001144 _ => panic!("{:#x?} requires 18 registers", self),
1145 }
1146 }
1147
1148 fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
1149 assert!(version >= Version(1, 2));
1150
1151 a.fill(0);
1152 if let Some(function_id) = self.function_id() {
1153 a[0] = function_id as u64;
1154 }
1155
1156 match *self {
1157 Interface::Success { target_info, args } => {
1158 a[1] = target_info.into();
1159 match args {
1160 SuccessArgs::Result64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
1161 _ => panic!("{:#x?} requires 8 registers", args),
1162 }
1163 }
1164 Interface::MsgSendDirectReq2 {
1165 src_id,
1166 dst_id,
1167 uuid,
1168 args,
1169 } => {
1170 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1171 (a[2], a[3]) = uuid.as_u64_pair();
1172 a[4..18].copy_from_slice(&args.0[..14]);
1173 }
1174 Interface::MsgSendDirectResp2 {
1175 src_id,
1176 dst_id,
1177 args,
1178 } => {
1179 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1180 a[2] = 0;
1181 a[3] = 0;
1182 a[4..18].copy_from_slice(&args.0[..14]);
1183 }
1184 Interface::ConsoleLog {
1185 char_cnt,
1186 char_lists,
1187 } => {
1188 a[1] = char_cnt.into();
1189 match char_lists {
1190 ConsoleLogChars::Reg64(regs) => a[2..18].copy_from_slice(&regs[..16]),
1191 _ => panic!("{:#x?} requires 8 registers", char_lists),
1192 }
1193 }
1194 _ => panic!("{:#x?} requires 8 registers", self),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001195 }
1196 }
1197
Balint Dobszaya5846852025-02-26 15:38:53 +01001198 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001199 pub fn success32_noargs() -> Self {
1200 Self::Success {
1201 target_info: 0,
1202 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1203 }
1204 }
1205
Tomás González4c8c7d22025-03-10 17:14:57 +00001206 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
1207 pub fn success64_noargs() -> Self {
1208 Self::Success {
1209 target_info: 0,
1210 args: SuccessArgs::Result64([0, 0, 0, 0, 0, 0]),
1211 }
1212 }
1213
Balint Dobszaya5846852025-02-26 15:38:53 +01001214 /// Helper function to create an `FFA_ERROR` interface with an error code.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001215 pub fn error(error_code: FfaError) -> Self {
1216 Self::Error {
1217 target_info: TargetInfo {
1218 endpoint_id: 0,
1219 vcpu_id: 0,
1220 },
1221 error_code,
1222 }
1223 }
1224}
1225
Balint Dobszaya5846852025-02-26 15:38:53 +01001226/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
1227pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
Balint Dobszayde0dc802025-02-28 14:16:52 +01001228/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message.
1229pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 128;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001230
Balint Dobszaya5846852025-02-26 15:38:53 +01001231/// Helper function to convert the "Tightly packed list of characters" format used by the
1232/// `FFA_CONSOLE_LOG` interface into a byte slice.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001233pub fn parse_console_log(
1234 char_cnt: u8,
1235 char_lists: &ConsoleLogChars,
1236 log_bytes: &mut [u8],
1237) -> Result<(), FfaError> {
1238 match char_lists {
1239 ConsoleLogChars::Reg32(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001240 if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001241 return Err(FfaError::InvalidParameters);
1242 }
1243 for (i, reg) in regs.iter().enumerate() {
1244 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1245 }
1246 }
1247 ConsoleLogChars::Reg64(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001248 if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001249 return Err(FfaError::InvalidParameters);
1250 }
1251 for (i, reg) in regs.iter().enumerate() {
1252 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1253 }
1254 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001255 }
1256
Balint Dobszayc8802492025-01-15 18:11:39 +01001257 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001258}