blob: eb04ee54ca74e973a8c08e290623f84035a6246b [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
181impl From<u32> for Version {
182 fn from(val: u32) -> Self {
183 Self((val >> 16) as u16, val as u16)
184 }
185}
186
187impl From<Version> for u32 {
188 fn from(v: Version) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100189 ((v.0 as u32) << 16) | v.1 as u32
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200190 }
191}
192
Andrew Walbran19970ba2024-11-25 15:35:00 +0000193impl Display for Version {
194 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
195 write!(f, "{}.{}", self.0, self.1)
196 }
197}
198
199impl Debug for Version {
200 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
201 Display::fmt(self, f)
202 }
203}
204
Balint Dobszaya5846852025-02-26 15:38:53 +0100205/// Feature IDs used by the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100206#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
207#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
208#[repr(u8)]
209pub enum FeatureId {
210 NotificationPendingInterrupt = 0x1,
211 ScheduleReceiverInterrupt = 0x2,
212 ManagedExitInterrupt = 0x3,
213}
Balint Dobszayc8802492025-01-15 18:11:39 +0100214
Balint Dobszaya5846852025-02-26 15:38:53 +0100215/// Arguments for the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100216#[derive(Debug, Eq, PartialEq, Clone, Copy)]
217pub enum Feature {
218 FuncId(FuncId),
219 FeatureId(FeatureId),
220}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200221
Balint Dobszay3aad9572025-01-17 16:54:11 +0100222impl TryFrom<u32> for Feature {
223 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200224
Balint Dobszay3aad9572025-01-17 16:54:11 +0100225 fn try_from(value: u32) -> Result<Self, Self::Error> {
226 let res = if (value >> 31) & 1 == 1 {
227 Self::FuncId(value.try_into()?)
228 } else {
229 Self::FeatureId((value as u8).try_into()?)
230 };
231
232 Ok(res)
233 }
234}
235
236impl From<Feature> for u32 {
237 fn from(value: Feature) -> Self {
238 match value {
239 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
240 Feature::FeatureId(feature_id) => feature_id as u32,
241 }
242 }
243}
244
Balint Dobszaya5846852025-02-26 15:38:53 +0100245/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100246#[derive(Debug, Eq, PartialEq, Clone, Copy)]
247pub enum RxTxAddr {
248 Addr32 { rx: u32, tx: u32 },
249 Addr64 { rx: u64, tx: u64 },
250}
251
Balint Dobszaya5846852025-02-26 15:38:53 +0100252/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100253#[derive(Debug, Eq, PartialEq, Clone, Copy)]
254pub enum DirectMsgArgs {
255 Args32([u32; 5]),
256 Args64([u64; 5]),
257}
258
Balint Dobszayde0dc802025-02-28 14:16:52 +0100259/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
260#[derive(Debug, Eq, PartialEq, Clone, Copy)]
261pub struct DirectMsg2Args([u64; 14]);
262
Balint Dobszaya5846852025-02-26 15:38:53 +0100263/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
264/// descriptor. Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX
265/// buffer is not used to transmit the transaction descriptor.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100266#[derive(Debug, Eq, PartialEq, Clone, Copy)]
267pub enum MemOpBuf {
268 Buf32 { addr: u32, page_cnt: u32 },
269 Buf64 { addr: u64, page_cnt: u32 },
270}
271
Balint Dobszaya5846852025-02-26 15:38:53 +0100272/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100273#[derive(Debug, Eq, PartialEq, Clone, Copy)]
274pub enum MemAddr {
275 Addr32(u32),
276 Addr64(u64),
277}
278
Balint Dobszayde0dc802025-02-28 14:16:52 +0100279/// Argument for the `FFA_CONSOLE_LOG` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100280#[derive(Debug, Eq, PartialEq, Clone, Copy)]
281pub enum ConsoleLogChars {
282 Reg32([u32; 6]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100283 Reg64([u64; 16]),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100284}
285
Balint Dobszaya5846852025-02-26 15:38:53 +0100286/// FF-A "message types", the terminology used by the spec is "interfaces". The interfaces are used
287/// by FF-A components for communication at an FF-A instance. The spec also describes the valid FF-A
288/// instances and conduits for each interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100289#[derive(Debug, Eq, PartialEq, Clone, Copy)]
290pub enum Interface {
291 Error {
292 target_info: TargetInfo,
293 error_code: FfaError,
294 },
295 Success {
296 target_info: u32,
297 args: SuccessArgs,
298 },
299 Interrupt {
300 target_info: TargetInfo,
301 interrupt_id: u32,
302 },
303 Version {
304 input_version: Version,
305 },
306 VersionOut {
307 output_version: Version,
308 },
309 Features {
310 feat_id: Feature,
311 input_properties: u32,
312 },
313 RxAcquire {
314 vm_id: u16,
315 },
316 RxRelease {
317 vm_id: u16,
318 },
319 RxTxMap {
320 addr: RxTxAddr,
321 page_cnt: u32,
322 },
323 RxTxUnmap {
324 id: u16,
325 },
326 PartitionInfoGet {
327 uuid: Uuid,
328 flags: u32,
329 },
330 IdGet,
331 SpmIdGet,
332 MsgWait,
333 Yield,
334 Run {
335 target_info: TargetInfo,
336 },
337 NormalWorldResume,
338 MsgSend2 {
339 sender_vm_id: u16,
340 flags: u32,
341 },
342 MsgSendDirectReq {
343 src_id: u16,
344 dst_id: u16,
345 flags: u32,
346 args: DirectMsgArgs,
347 },
348 MsgSendDirectResp {
349 src_id: u16,
350 dst_id: u16,
351 flags: u32,
352 args: DirectMsgArgs,
353 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100354 MsgSendDirectReq2 {
355 src_id: u16,
356 dst_id: u16,
357 uuid: Uuid,
358 args: DirectMsg2Args,
359 },
360 MsgSendDirectResp2 {
361 src_id: u16,
362 dst_id: u16,
363 args: DirectMsg2Args,
364 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100365 MemDonate {
366 total_len: u32,
367 frag_len: u32,
368 buf: Option<MemOpBuf>,
369 },
370 MemLend {
371 total_len: u32,
372 frag_len: u32,
373 buf: Option<MemOpBuf>,
374 },
375 MemShare {
376 total_len: u32,
377 frag_len: u32,
378 buf: Option<MemOpBuf>,
379 },
380 MemRetrieveReq {
381 total_len: u32,
382 frag_len: u32,
383 buf: Option<MemOpBuf>,
384 },
385 MemRetrieveResp {
386 total_len: u32,
387 frag_len: u32,
388 },
389 MemRelinquish,
390 MemReclaim {
391 handle: memory_management::Handle,
392 flags: u32,
393 },
394 MemPermGet {
395 addr: MemAddr,
Balint Dobszayde0dc802025-02-28 14:16:52 +0100396 page_cnt: Option<u32>,
Balint Dobszay3aad9572025-01-17 16:54:11 +0100397 },
398 MemPermSet {
399 addr: MemAddr,
400 page_cnt: u32,
401 mem_perm: u32,
402 },
403 ConsoleLog {
404 char_cnt: u8,
405 char_lists: ConsoleLogChars,
406 },
407}
408
Balint Dobszayde0dc802025-02-28 14:16:52 +0100409impl Interface {
410 /// Returns the function ID for the call, if it has one.
411 pub fn function_id(&self) -> Option<FuncId> {
412 match self {
413 Interface::Error { .. } => Some(FuncId::Error),
414 Interface::Success { args, .. } => match args {
415 SuccessArgs::Result32(..) => Some(FuncId::Success32),
416 SuccessArgs::Result64(..) | SuccessArgs::Result64_2(..) => Some(FuncId::Success64),
417 },
418 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
419 Interface::Version { .. } => Some(FuncId::Version),
420 Interface::VersionOut { .. } => None,
421 Interface::Features { .. } => Some(FuncId::Features),
422 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
423 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
424 Interface::RxTxMap { addr, .. } => match addr {
425 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
426 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
427 },
428 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
429 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
430 Interface::IdGet => Some(FuncId::IdGet),
431 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
432 Interface::MsgWait => Some(FuncId::MsgWait),
433 Interface::Yield => Some(FuncId::Yield),
434 Interface::Run { .. } => Some(FuncId::Run),
435 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
436 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
437 Interface::MsgSendDirectReq { args, .. } => match args {
438 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
439 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
440 },
441 Interface::MsgSendDirectResp { args, .. } => match args {
442 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
443 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
444 },
445 Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
446 Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
447 Interface::MemDonate { buf, .. } => match buf {
448 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
449 _ => Some(FuncId::MemDonate32),
450 },
451 Interface::MemLend { buf, .. } => match buf {
452 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
453 _ => Some(FuncId::MemLend32),
454 },
455 Interface::MemShare { buf, .. } => match buf {
456 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
457 _ => Some(FuncId::MemShare32),
458 },
459 Interface::MemRetrieveReq { buf, .. } => match buf {
460 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
461 _ => Some(FuncId::MemRetrieveReq32),
462 },
463 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
464 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
465 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
466 Interface::MemPermGet { addr, .. } => match addr {
467 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
468 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
469 },
470 Interface::MemPermSet { addr, .. } => match addr {
471 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
472 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
473 },
474 Interface::ConsoleLog { char_lists, .. } => match char_lists {
475 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
476 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
477 },
478 }
479 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100480
Balint Dobszayde0dc802025-02-28 14:16:52 +0100481 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
482 pub fn is_32bit(&self) -> bool {
483 // TODO: self should always have a function ID?
484 self.function_id().unwrap().is_32bit()
485 }
486
487 /// Parse interface from register contents. The caller must ensure that the `regs` argument has
488 /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
489 pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
490 let reg_cnt = regs.len();
491
492 let msg = match reg_cnt {
493 8 => {
494 assert!(version <= Version(1, 1));
495 Interface::unpack_regs8(version, regs.try_into().unwrap())?
496 }
497 18 => {
498 assert!(version >= Version(1, 2));
499 match FuncId::try_from(regs[0] as u32)? {
500 FuncId::ConsoleLog64
501 | FuncId::Success64
502 | FuncId::MsgSendDirectReq64_2
503 | FuncId::MsgSendDirectResp64_2 => {
504 Interface::unpack_regs18(version, regs.try_into().unwrap())?
505 }
506 _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
507 }
508 }
509 _ => panic!(
510 "Invalid number of registers ({}) for FF-A version {}",
511 reg_cnt, version
512 ),
513 };
514
515 Ok(msg)
516 }
517
518 fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100519 let fid = FuncId::try_from(regs[0] as u32)?;
520
521 let msg = match fid {
522 FuncId::Error => Self::Error {
523 target_info: (regs[1] as u32).into(),
524 error_code: FfaError::try_from(regs[2] as i32)?,
525 },
526 FuncId::Success32 => Self::Success {
527 target_info: regs[1] as u32,
528 args: SuccessArgs::Result32([
529 regs[2] as u32,
530 regs[3] as u32,
531 regs[4] as u32,
532 regs[5] as u32,
533 regs[6] as u32,
534 regs[7] as u32,
535 ]),
536 },
537 FuncId::Success64 => Self::Success {
538 target_info: regs[1] as u32,
539 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
540 },
541 FuncId::Interrupt => Self::Interrupt {
542 target_info: (regs[1] as u32).into(),
543 interrupt_id: regs[2] as u32,
544 },
545 FuncId::Version => Self::Version {
546 input_version: (regs[1] as u32).into(),
547 },
548 FuncId::Features => Self::Features {
549 feat_id: (regs[1] as u32).try_into()?,
550 input_properties: regs[2] as u32,
551 },
552 FuncId::RxAcquire => Self::RxAcquire {
553 vm_id: regs[1] as u16,
554 },
555 FuncId::RxRelease => Self::RxRelease {
556 vm_id: regs[1] as u16,
557 },
558 FuncId::RxTxMap32 => {
559 let addr = RxTxAddr::Addr32 {
560 rx: regs[2] as u32,
561 tx: regs[1] as u32,
562 };
563 let page_cnt = regs[3] as u32;
564
565 Self::RxTxMap { addr, page_cnt }
566 }
567 FuncId::RxTxMap64 => {
568 let addr = RxTxAddr::Addr64 {
569 rx: regs[2],
570 tx: regs[1],
571 };
572 let page_cnt = regs[3] as u32;
573
574 Self::RxTxMap { addr, page_cnt }
575 }
576 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
577 FuncId::PartitionInfoGet => {
578 let uuid_words = [
579 regs[1] as u32,
580 regs[2] as u32,
581 regs[3] as u32,
582 regs[4] as u32,
583 ];
584 let mut bytes: [u8; 16] = [0; 16];
585 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
586 bytes[i] = b;
587 }
588 Self::PartitionInfoGet {
589 uuid: Uuid::from_bytes(bytes),
590 flags: regs[5] as u32,
591 }
592 }
593 FuncId::IdGet => Self::IdGet,
594 FuncId::SpmIdGet => Self::SpmIdGet,
595 FuncId::MsgWait => Self::MsgWait,
596 FuncId::Yield => Self::Yield,
597 FuncId::Run => Self::Run {
598 target_info: (regs[1] as u32).into(),
599 },
600 FuncId::NormalWorldResume => Self::NormalWorldResume,
601 FuncId::MsgSend2 => Self::MsgSend2 {
602 sender_vm_id: regs[1] as u16,
603 flags: regs[2] as u32,
604 },
605 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
606 src_id: (regs[1] >> 16) as u16,
607 dst_id: regs[1] as u16,
608 flags: regs[2] as u32,
609 args: DirectMsgArgs::Args32([
610 regs[3] as u32,
611 regs[4] as u32,
612 regs[5] as u32,
613 regs[6] as u32,
614 regs[7] as u32,
615 ]),
616 },
617 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
618 src_id: (regs[1] >> 16) as u16,
619 dst_id: regs[1] as u16,
620 flags: regs[2] as u32,
621 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
622 },
623 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
624 src_id: (regs[1] >> 16) as u16,
625 dst_id: regs[1] as u16,
626 flags: regs[2] as u32,
627 args: DirectMsgArgs::Args32([
628 regs[3] as u32,
629 regs[4] as u32,
630 regs[5] as u32,
631 regs[6] as u32,
632 regs[7] as u32,
633 ]),
634 },
635 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
636 src_id: (regs[1] >> 16) as u16,
637 dst_id: regs[1] as u16,
638 flags: regs[2] as u32,
639 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
640 },
641 FuncId::MemDonate32 => Self::MemDonate {
642 total_len: regs[1] as u32,
643 frag_len: regs[2] as u32,
644 buf: if regs[3] != 0 && regs[4] != 0 {
645 Some(MemOpBuf::Buf32 {
646 addr: regs[3] as u32,
647 page_cnt: regs[4] as u32,
648 })
649 } else {
650 None
651 },
652 },
653 FuncId::MemDonate64 => Self::MemDonate {
654 total_len: regs[1] as u32,
655 frag_len: regs[2] as u32,
656 buf: if regs[3] != 0 && regs[4] != 0 {
657 Some(MemOpBuf::Buf64 {
658 addr: regs[3],
659 page_cnt: regs[4] as u32,
660 })
661 } else {
662 None
663 },
664 },
665 FuncId::MemLend32 => Self::MemLend {
666 total_len: regs[1] as u32,
667 frag_len: regs[2] as u32,
668 buf: if regs[3] != 0 && regs[4] != 0 {
669 Some(MemOpBuf::Buf32 {
670 addr: regs[3] as u32,
671 page_cnt: regs[4] as u32,
672 })
673 } else {
674 None
675 },
676 },
677 FuncId::MemLend64 => Self::MemLend {
678 total_len: regs[1] as u32,
679 frag_len: regs[2] as u32,
680 buf: if regs[3] != 0 && regs[4] != 0 {
681 Some(MemOpBuf::Buf64 {
682 addr: regs[3],
683 page_cnt: regs[4] as u32,
684 })
685 } else {
686 None
687 },
688 },
689 FuncId::MemShare32 => Self::MemShare {
690 total_len: regs[1] as u32,
691 frag_len: regs[2] as u32,
692 buf: if regs[3] != 0 && regs[4] != 0 {
693 Some(MemOpBuf::Buf32 {
694 addr: regs[3] as u32,
695 page_cnt: regs[4] as u32,
696 })
697 } else {
698 None
699 },
700 },
701 FuncId::MemShare64 => Self::MemShare {
702 total_len: regs[1] as u32,
703 frag_len: regs[2] as u32,
704 buf: if regs[3] != 0 && regs[4] != 0 {
705 Some(MemOpBuf::Buf64 {
706 addr: regs[3],
707 page_cnt: regs[4] as u32,
708 })
709 } else {
710 None
711 },
712 },
713 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
714 total_len: regs[1] as u32,
715 frag_len: regs[2] as u32,
716 buf: if regs[3] != 0 && regs[4] != 0 {
717 Some(MemOpBuf::Buf32 {
718 addr: regs[3] as u32,
719 page_cnt: regs[4] as u32,
720 })
721 } else {
722 None
723 },
724 },
725 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
726 total_len: regs[1] as u32,
727 frag_len: regs[2] as u32,
728 buf: if regs[3] != 0 && regs[4] != 0 {
729 Some(MemOpBuf::Buf64 {
730 addr: regs[3],
731 page_cnt: regs[4] as u32,
732 })
733 } else {
734 None
735 },
736 },
737 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
738 total_len: regs[1] as u32,
739 frag_len: regs[2] as u32,
740 },
741 FuncId::MemRelinquish => Self::MemRelinquish,
742 FuncId::MemReclaim => Self::MemReclaim {
743 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
744 flags: regs[3] as u32,
745 },
746 FuncId::MemPermGet32 => Self::MemPermGet {
747 addr: MemAddr::Addr32(regs[1] as u32),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100748 page_cnt: if version >= Version(1, 3) {
749 Some(regs[2] as u32)
750 } else {
751 None
752 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100753 },
754 FuncId::MemPermGet64 => Self::MemPermGet {
755 addr: MemAddr::Addr64(regs[1]),
Balint Dobszayde0dc802025-02-28 14:16:52 +0100756 page_cnt: if version >= Version(1, 3) {
757 Some(regs[2] as u32)
758 } else {
759 None
760 },
Balint Dobszay3aad9572025-01-17 16:54:11 +0100761 },
762 FuncId::MemPermSet32 => Self::MemPermSet {
763 addr: MemAddr::Addr32(regs[1] as u32),
764 page_cnt: regs[2] as u32,
765 mem_perm: regs[3] as u32,
766 },
767 FuncId::MemPermSet64 => Self::MemPermSet {
768 addr: MemAddr::Addr64(regs[1]),
769 page_cnt: regs[2] as u32,
770 mem_perm: regs[3] as u32,
771 },
772 FuncId::ConsoleLog32 => Self::ConsoleLog {
773 char_cnt: regs[1] as u8,
774 char_lists: ConsoleLogChars::Reg32([
775 regs[2] as u32,
776 regs[3] as u32,
777 regs[4] as u32,
778 regs[5] as u32,
779 regs[6] as u32,
780 regs[7] as u32,
781 ]),
782 },
Balint Dobszayde0dc802025-02-28 14:16:52 +0100783 _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100784 };
785
786 Ok(msg)
787 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100788
Balint Dobszayde0dc802025-02-28 14:16:52 +0100789 fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
790 assert!(version >= Version(1, 2));
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200791
Balint Dobszayde0dc802025-02-28 14:16:52 +0100792 let fid = FuncId::try_from(regs[0] as u32)?;
793
794 let msg = match fid {
795 FuncId::Success64 => Self::Success {
796 target_info: regs[1] as u32,
797 args: SuccessArgs::Result64_2(regs[2..18].try_into().unwrap()),
798 },
799 FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
800 src_id: (regs[1] >> 16) as u16,
801 dst_id: regs[1] as u16,
802 uuid: Uuid::from_u64_pair(regs[2], regs[3]),
803 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
804 },
805 FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
806 src_id: (regs[1] >> 16) as u16,
807 dst_id: regs[1] as u16,
808 args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
809 },
810 FuncId::ConsoleLog64 => Self::ConsoleLog {
811 char_cnt: regs[1] as u8,
812 char_lists: ConsoleLogChars::Reg64(regs[2..18].try_into().unwrap()),
813 },
814 _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
815 };
816
817 Ok(msg)
Balint Dobszay3aad9572025-01-17 16:54:11 +0100818 }
819
Balint Dobszaya5846852025-02-26 15:38:53 +0100820 /// Create register contents for an interface.
Balint Dobszayde0dc802025-02-28 14:16:52 +0100821 pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
822 let reg_cnt = regs.len();
823
824 match reg_cnt {
825 8 => {
826 assert!(version <= Version(1, 1));
827 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
828 }
829 18 => {
830 assert!(version >= Version(1, 2));
831
832 match self {
833 Interface::ConsoleLog {
834 char_lists: ConsoleLogChars::Reg64(_),
835 ..
836 }
837 | Interface::Success {
838 args: SuccessArgs::Result64_2(_),
839 ..
840 }
841 | Interface::MsgSendDirectReq2 { .. }
842 | Interface::MsgSendDirectResp2 { .. } => {
843 self.pack_regs18(version, regs.try_into().unwrap());
844 }
845 _ => {
846 self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
847 }
848 }
849 }
850 _ => panic!("Invalid number of registers {}", reg_cnt),
851 }
852 }
853
854 fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
Balint Dobszay3aad9572025-01-17 16:54:11 +0100855 a.fill(0);
856 if let Some(function_id) = self.function_id() {
857 a[0] = function_id as u64;
858 }
859
860 match *self {
861 Interface::Error {
862 target_info,
863 error_code,
864 } => {
865 a[1] = u32::from(target_info).into();
866 a[2] = (error_code as u32).into();
867 }
868 Interface::Success { target_info, args } => {
869 a[1] = target_info.into();
870 match args {
871 SuccessArgs::Result32(regs) => {
872 a[2] = regs[0].into();
873 a[3] = regs[1].into();
874 a[4] = regs[2].into();
875 a[5] = regs[3].into();
876 a[6] = regs[4].into();
877 a[7] = regs[5].into();
878 }
879 SuccessArgs::Result64(regs) => {
880 a[2] = regs[0];
881 a[3] = regs[1];
882 a[4] = regs[2];
883 a[5] = regs[3];
884 a[6] = regs[4];
885 a[7] = regs[5];
886 }
Balint Dobszayde0dc802025-02-28 14:16:52 +0100887 _ => panic!("{:#x?} requires 18 registers", args),
Balint Dobszay3aad9572025-01-17 16:54:11 +0100888 }
889 }
890 Interface::Interrupt {
891 target_info,
892 interrupt_id,
893 } => {
894 a[1] = u32::from(target_info).into();
895 a[2] = interrupt_id.into();
896 }
897 Interface::Version { input_version } => {
898 a[1] = u32::from(input_version).into();
899 }
900 Interface::VersionOut { output_version } => {
901 a[0] = u32::from(output_version).into();
902 }
903 Interface::Features {
904 feat_id,
905 input_properties,
906 } => {
907 a[1] = u32::from(feat_id).into();
908 a[2] = input_properties.into();
909 }
910 Interface::RxAcquire { vm_id } => {
911 a[1] = vm_id.into();
912 }
913 Interface::RxRelease { vm_id } => {
914 a[1] = vm_id.into();
915 }
916 Interface::RxTxMap { addr, page_cnt } => {
917 match addr {
918 RxTxAddr::Addr32 { rx, tx } => {
919 a[1] = tx.into();
920 a[2] = rx.into();
921 }
922 RxTxAddr::Addr64 { rx, tx } => {
923 a[1] = tx;
924 a[2] = rx;
925 }
926 }
927 a[3] = page_cnt.into();
928 }
929 Interface::RxTxUnmap { id } => {
930 a[1] = id.into();
931 }
932 Interface::PartitionInfoGet { uuid, flags } => {
933 let bytes = uuid.into_bytes();
934 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
935 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
936 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
937 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
938 a[5] = flags.into();
939 }
940 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
941 Interface::Run { target_info } => {
942 a[1] = u32::from(target_info).into();
943 }
944 Interface::NormalWorldResume => {}
945 Interface::MsgSend2 {
946 sender_vm_id,
947 flags,
948 } => {
949 a[1] = sender_vm_id.into();
950 a[2] = flags.into();
951 }
952 Interface::MsgSendDirectReq {
953 src_id,
954 dst_id,
955 flags,
956 args,
957 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100958 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100959 a[2] = flags.into();
960 match args {
961 DirectMsgArgs::Args32(args) => {
962 a[3] = args[0].into();
963 a[4] = args[1].into();
964 a[5] = args[2].into();
965 a[6] = args[3].into();
966 a[7] = args[4].into();
967 }
968 DirectMsgArgs::Args64(args) => {
969 a[3] = args[0];
970 a[4] = args[1];
971 a[5] = args[2];
972 a[6] = args[3];
973 a[7] = args[4];
974 }
975 }
976 }
977 Interface::MsgSendDirectResp {
978 src_id,
979 dst_id,
980 flags,
981 args,
982 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100983 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100984 a[2] = flags.into();
985 match args {
986 DirectMsgArgs::Args32(args) => {
987 a[3] = args[0].into();
988 a[4] = args[1].into();
989 a[5] = args[2].into();
990 a[6] = args[3].into();
991 a[7] = args[4].into();
992 }
993 DirectMsgArgs::Args64(args) => {
994 a[3] = args[0];
995 a[4] = args[1];
996 a[5] = args[2];
997 a[6] = args[3];
998 a[7] = args[4];
999 }
1000 }
1001 }
1002 Interface::MemDonate {
1003 total_len,
1004 frag_len,
1005 buf,
1006 } => {
1007 a[1] = total_len.into();
1008 a[2] = frag_len.into();
1009 (a[3], a[4]) = match buf {
1010 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1011 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1012 None => (0, 0),
1013 };
1014 }
1015 Interface::MemLend {
1016 total_len,
1017 frag_len,
1018 buf,
1019 } => {
1020 a[1] = total_len.into();
1021 a[2] = frag_len.into();
1022 (a[3], a[4]) = match buf {
1023 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1024 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1025 None => (0, 0),
1026 };
1027 }
1028 Interface::MemShare {
1029 total_len,
1030 frag_len,
1031 buf,
1032 } => {
1033 a[1] = total_len.into();
1034 a[2] = frag_len.into();
1035 (a[3], a[4]) = match buf {
1036 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1037 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1038 None => (0, 0),
1039 };
1040 }
1041 Interface::MemRetrieveReq {
1042 total_len,
1043 frag_len,
1044 buf,
1045 } => {
1046 a[1] = total_len.into();
1047 a[2] = frag_len.into();
1048 (a[3], a[4]) = match buf {
1049 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
1050 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
1051 None => (0, 0),
1052 };
1053 }
1054 Interface::MemRetrieveResp {
1055 total_len,
1056 frag_len,
1057 } => {
1058 a[1] = total_len.into();
1059 a[2] = frag_len.into();
1060 }
1061 Interface::MemRelinquish => {}
1062 Interface::MemReclaim { handle, flags } => {
1063 let handle_regs: [u32; 2] = handle.into();
1064 a[1] = handle_regs[0].into();
1065 a[2] = handle_regs[1].into();
1066 a[3] = flags.into();
1067 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001068 Interface::MemPermGet { addr, page_cnt } => {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001069 a[1] = match addr {
1070 MemAddr::Addr32(addr) => addr.into(),
1071 MemAddr::Addr64(addr) => addr,
1072 };
Balint Dobszayde0dc802025-02-28 14:16:52 +01001073 a[2] = if version >= Version(1, 3) {
1074 page_cnt.unwrap().into()
1075 } else {
1076 assert!(page_cnt.is_none());
1077 0
1078 }
Balint Dobszay3aad9572025-01-17 16:54:11 +01001079 }
1080 Interface::MemPermSet {
1081 addr,
1082 page_cnt,
1083 mem_perm,
1084 } => {
1085 a[1] = match addr {
1086 MemAddr::Addr32(addr) => addr.into(),
1087 MemAddr::Addr64(addr) => addr,
1088 };
1089 a[2] = page_cnt.into();
1090 a[3] = mem_perm.into();
1091 }
1092 Interface::ConsoleLog {
1093 char_cnt,
1094 char_lists,
1095 } => {
1096 a[1] = char_cnt.into();
1097 match char_lists {
1098 ConsoleLogChars::Reg32(regs) => {
1099 a[2] = regs[0].into();
1100 a[3] = regs[1].into();
1101 a[4] = regs[2].into();
1102 a[5] = regs[3].into();
1103 a[6] = regs[4].into();
1104 a[7] = regs[5].into();
1105 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001106 _ => panic!("{:#x?} requires 18 registers", char_lists),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001107 }
1108 }
Balint Dobszayde0dc802025-02-28 14:16:52 +01001109 _ => panic!("{:#x?} requires 18 registers", self),
1110 }
1111 }
1112
1113 fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
1114 assert!(version >= Version(1, 2));
1115
1116 a.fill(0);
1117 if let Some(function_id) = self.function_id() {
1118 a[0] = function_id as u64;
1119 }
1120
1121 match *self {
1122 Interface::Success { target_info, args } => {
1123 a[1] = target_info.into();
1124 match args {
1125 SuccessArgs::Result64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
1126 _ => panic!("{:#x?} requires 8 registers", args),
1127 }
1128 }
1129 Interface::MsgSendDirectReq2 {
1130 src_id,
1131 dst_id,
1132 uuid,
1133 args,
1134 } => {
1135 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1136 (a[2], a[3]) = uuid.as_u64_pair();
1137 a[4..18].copy_from_slice(&args.0[..14]);
1138 }
1139 Interface::MsgSendDirectResp2 {
1140 src_id,
1141 dst_id,
1142 args,
1143 } => {
1144 a[1] = ((src_id as u64) << 16) | dst_id as u64;
1145 a[2] = 0;
1146 a[3] = 0;
1147 a[4..18].copy_from_slice(&args.0[..14]);
1148 }
1149 Interface::ConsoleLog {
1150 char_cnt,
1151 char_lists,
1152 } => {
1153 a[1] = char_cnt.into();
1154 match char_lists {
1155 ConsoleLogChars::Reg64(regs) => a[2..18].copy_from_slice(&regs[..16]),
1156 _ => panic!("{:#x?} requires 8 registers", char_lists),
1157 }
1158 }
1159 _ => panic!("{:#x?} requires 8 registers", self),
Balint Dobszay3aad9572025-01-17 16:54:11 +01001160 }
1161 }
1162
Balint Dobszaya5846852025-02-26 15:38:53 +01001163 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001164 pub fn success32_noargs() -> Self {
1165 Self::Success {
1166 target_info: 0,
1167 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1168 }
1169 }
1170
Balint Dobszaya5846852025-02-26 15:38:53 +01001171 /// Helper function to create an `FFA_ERROR` interface with an error code.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001172 pub fn error(error_code: FfaError) -> Self {
1173 Self::Error {
1174 target_info: TargetInfo {
1175 endpoint_id: 0,
1176 vcpu_id: 0,
1177 },
1178 error_code,
1179 }
1180 }
1181}
1182
Balint Dobszaya5846852025-02-26 15:38:53 +01001183/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
1184pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
Balint Dobszayde0dc802025-02-28 14:16:52 +01001185/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message.
1186pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 128;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001187
Balint Dobszaya5846852025-02-26 15:38:53 +01001188/// Helper function to convert the "Tightly packed list of characters" format used by the
1189/// `FFA_CONSOLE_LOG` interface into a byte slice.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001190pub fn parse_console_log(
1191 char_cnt: u8,
1192 char_lists: &ConsoleLogChars,
1193 log_bytes: &mut [u8],
1194) -> Result<(), FfaError> {
1195 match char_lists {
1196 ConsoleLogChars::Reg32(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001197 if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001198 return Err(FfaError::InvalidParameters);
1199 }
1200 for (i, reg) in regs.iter().enumerate() {
1201 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1202 }
1203 }
1204 ConsoleLogChars::Reg64(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001205 if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001206 return Err(FfaError::InvalidParameters);
1207 }
1208 for (i, reg) in regs.iter().enumerate() {
1209 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1210 }
1211 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001212 }
1213
Balint Dobszayc8802492025-01-15 18:11:39 +01001214 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001215}