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