arm_ffa/
lib.rs

1// 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)]
5#![deny(clippy::undocumented_unsafe_blocks)]
6#![deny(unsafe_op_in_unsafe_fn)]
7#![doc = include_str!("../README.md")]
8
9use core::fmt::{self, Debug, Display, Formatter};
10use num_enum::{IntoPrimitive, TryFromPrimitive};
11use thiserror::Error;
12pub use uuid::Uuid;
13use zerocopy::{transmute, FromBytes, Immutable, IntoBytes};
14
15pub mod boot_info;
16mod ffa_v1_1;
17mod ffa_v1_2;
18pub mod memory_management;
19pub mod partition_info;
20
21/// Constant for 4K page size. On many occasions the FF-A spec defines memory size as count of 4K
22/// pages, regardless of the current translation granule.
23pub const FFA_PAGE_SIZE_4K: usize = 4096;
24
25/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
26/// with the `FFA_ERROR` interface.
27#[derive(Debug, Error, PartialEq)]
28pub enum Error {
29    #[error("Unrecognised FF-A function ID {0}")]
30    UnrecognisedFunctionId(u32),
31    #[error("Unrecognised FF-A feature ID {0}")]
32    UnrecognisedFeatureId(u8),
33    #[error("Unrecognised FF-A error code {0}")]
34    UnrecognisedErrorCode(i32),
35    #[error("Unrecognised FF-A Framework Message {0}")]
36    UnrecognisedFwkMsg(u32),
37    #[error("Invalid FF-A Msg Wait Flag {0}")]
38    InvalidMsgWaitFlag(u32),
39    #[error("Invalid FF-A Msg Send2 Flag {0}")]
40    InvalidMsgSend2Flag(u32),
41    #[error("Unrecognised VM availability status {0}")]
42    UnrecognisedVmAvailabilityStatus(i32),
43    #[error("Unrecognised FF-A Warm Boot Type {0}")]
44    UnrecognisedWarmBootType(u32),
45    #[error("Invalid version {0}")]
46    InvalidVersion(u32),
47    #[error("Invalid Information Tag {0}")]
48    InvalidInformationTag(u16),
49    #[error("Invalid Flag for Notification Set")]
50    InvalidNotificationSetFlag(u32),
51    #[error("Invalid Vm ID")]
52    InvalidVmId(u32),
53    #[error("Invalid FF-A Partition Info Get Flag {0}")]
54    InvalidPartitionInfoGetFlag(u32),
55    #[error("Invalid success argument variant")]
56    InvalidSuccessArgsVariant,
57    #[error("Invalid notification count")]
58    InvalidNotificationCount,
59    #[error("Invalid Partition Info Get Regs response")]
60    InvalidPartitionInfoGetRegsResponse,
61    #[error("Invalid FF-A version {0} for function ID {1:?}")]
62    InvalidVersionForFunctionId(Version, FuncId),
63    #[error("Invalid character count {0}")]
64    InvalidCharacterCount(u8),
65    #[error("Invalid memory reclaim flags {0}")]
66    InvalidMemReclaimFlags(u32),
67    #[error("Memory management error")]
68    MemoryManagementError(#[from] memory_management::Error),
69}
70
71impl From<Error> for FfaError {
72    fn from(value: Error) -> Self {
73        match value {
74            Error::UnrecognisedFunctionId(_)
75            | Error::UnrecognisedFeatureId(_)
76            | Error::InvalidVersionForFunctionId(..) => Self::NotSupported,
77            Error::InvalidInformationTag(_) => Self::Retry,
78            Error::UnrecognisedErrorCode(_)
79            | Error::UnrecognisedFwkMsg(_)
80            | Error::InvalidVersion(_)
81            | Error::InvalidMsgWaitFlag(_)
82            | Error::InvalidMsgSend2Flag(_)
83            | Error::UnrecognisedVmAvailabilityStatus(_)
84            | Error::InvalidNotificationSetFlag(_)
85            | Error::InvalidVmId(_)
86            | Error::UnrecognisedWarmBootType(_)
87            | Error::InvalidPartitionInfoGetFlag(_)
88            | Error::InvalidSuccessArgsVariant
89            | Error::InvalidNotificationCount
90            | Error::InvalidPartitionInfoGetRegsResponse
91            | Error::InvalidCharacterCount(_)
92            | Error::InvalidMemReclaimFlags(_)
93            | Error::MemoryManagementError(_) => Self::InvalidParameters,
94        }
95    }
96}
97
98/// An FF-A instance is a valid combination of two FF-A components at an exception level boundary.
99#[derive(PartialEq, Clone, Copy)]
100pub enum Instance {
101    /// The instance between the SPMC and SPMD.
102    SecurePhysical,
103    /// The instance between the SPMC and a physical SP (contains the SP's endpoint ID).
104    SecureVirtual(u16),
105}
106
107/// Function IDs of the various FF-A interfaces.
108#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
109#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFunctionId))]
110#[repr(u32)]
111pub enum FuncId {
112    Error = 0x84000060,
113    Success32 = 0x84000061,
114    Success64 = 0xc4000061,
115    Interrupt = 0x84000062,
116    Version = 0x84000063,
117    Features = 0x84000064,
118    RxAcquire = 0x84000084,
119    RxRelease = 0x84000065,
120    RxTxMap32 = 0x84000066,
121    RxTxMap64 = 0xc4000066,
122    RxTxUnmap = 0x84000067,
123    PartitionInfoGet = 0x84000068,
124    PartitionInfoGetRegs = 0xc400008b,
125    IdGet = 0x84000069,
126    SpmIdGet = 0x84000085,
127    ConsoleLog32 = 0x8400008a,
128    ConsoleLog64 = 0xc400008a,
129    MsgWait = 0x8400006b,
130    Yield = 0x8400006c,
131    Run = 0x8400006d,
132    NormalWorldResume = 0x8400007c,
133    MsgSend2 = 0x84000086,
134    MsgSendDirectReq32 = 0x8400006f,
135    MsgSendDirectReq64 = 0xc400006f,
136    MsgSendDirectReq64_2 = 0xc400008d,
137    MsgSendDirectResp32 = 0x84000070,
138    MsgSendDirectResp64 = 0xc4000070,
139    MsgSendDirectResp64_2 = 0xc400008e,
140    NotificationBitmapCreate = 0x8400007d,
141    NotificationBitmapDestroy = 0x8400007e,
142    NotificationBind = 0x8400007f,
143    NotificationUnbind = 0x84000080,
144    NotificationSet = 0x84000081,
145    NotificationGet = 0x84000082,
146    NotificationInfoGet32 = 0x84000083,
147    NotificationInfoGet64 = 0xc4000083,
148    El3IntrHandle = 0x8400008c,
149    SecondaryEpRegister32 = 0x84000087,
150    SecondaryEpRegister64 = 0xc4000087,
151    MemDonate32 = 0x84000071,
152    MemDonate64 = 0xc4000071,
153    MemLend32 = 0x84000072,
154    MemLend64 = 0xc4000072,
155    MemShare32 = 0x84000073,
156    MemShare64 = 0xc4000073,
157    MemRetrieveReq32 = 0x84000074,
158    MemRetrieveReq64 = 0xc4000074,
159    MemRetrieveResp = 0x84000075,
160    MemRelinquish = 0x84000076,
161    MemReclaim = 0x84000077,
162    MemPermGet32 = 0x84000088,
163    MemPermGet64 = 0xc4000088,
164    MemPermSet32 = 0x84000089,
165    MemPermSet64 = 0xc4000089,
166}
167
168impl FuncId {
169    /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
170    pub fn is_32bit(&self) -> bool {
171        u32::from(*self) & (1 << 30) == 0
172    }
173
174    /// Returns the FF-A version that has introduced the function ID.
175    pub fn minimum_ffa_version(&self) -> Version {
176        match self {
177            FuncId::Error
178            | FuncId::Success32
179            | FuncId::Success64
180            | FuncId::Interrupt
181            | FuncId::Version
182            | FuncId::Features
183            | FuncId::RxRelease
184            | FuncId::RxTxMap32
185            | FuncId::RxTxMap64
186            | FuncId::RxTxUnmap
187            | FuncId::PartitionInfoGet
188            | FuncId::IdGet
189            | FuncId::MsgWait
190            | FuncId::Yield
191            | FuncId::Run
192            | FuncId::NormalWorldResume
193            | FuncId::MsgSendDirectReq32
194            | FuncId::MsgSendDirectReq64
195            | FuncId::MsgSendDirectResp32
196            | FuncId::MsgSendDirectResp64
197            | FuncId::MemDonate32
198            | FuncId::MemDonate64
199            | FuncId::MemLend32
200            | FuncId::MemLend64
201            | FuncId::MemShare32
202            | FuncId::MemShare64
203            | FuncId::MemRetrieveReq32
204            | FuncId::MemRetrieveReq64
205            | FuncId::MemRetrieveResp
206            | FuncId::MemRelinquish
207            | FuncId::MemReclaim => Version(1, 0),
208
209            FuncId::RxAcquire
210            | FuncId::SpmIdGet
211            | FuncId::MsgSend2
212            | FuncId::MemPermGet32
213            | FuncId::MemPermGet64
214            | FuncId::MemPermSet32
215            | FuncId::MemPermSet64
216            | FuncId::NotificationBitmapCreate
217            | FuncId::NotificationBitmapDestroy
218            | FuncId::NotificationBind
219            | FuncId::NotificationUnbind
220            | FuncId::NotificationSet
221            | FuncId::NotificationGet
222            | FuncId::NotificationInfoGet32
223            | FuncId::NotificationInfoGet64
224            | FuncId::SecondaryEpRegister32
225            | FuncId::SecondaryEpRegister64 => Version(1, 1),
226
227            FuncId::PartitionInfoGetRegs
228            | FuncId::ConsoleLog32
229            | FuncId::ConsoleLog64
230            | FuncId::MsgSendDirectReq64_2
231            | FuncId::MsgSendDirectResp64_2
232            | FuncId::El3IntrHandle => Version(1, 2),
233        }
234    }
235}
236
237/// Error status codes used by the `FFA_ERROR` interface.
238#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
239#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
240#[repr(i32)]
241pub enum FfaError {
242    #[error("Not supported")]
243    NotSupported = -1,
244    #[error("Invalid parameters")]
245    InvalidParameters = -2,
246    #[error("No memory")]
247    NoMemory = -3,
248    #[error("Busy")]
249    Busy = -4,
250    #[error("Interrupted")]
251    Interrupted = -5,
252    #[error("Denied")]
253    Denied = -6,
254    #[error("Retry")]
255    Retry = -7,
256    #[error("Aborted")]
257    Aborted = -8,
258    #[error("No data")]
259    NoData = -9,
260}
261
262/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
263#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
264pub struct TargetInfo {
265    pub endpoint_id: u16,
266    pub vcpu_id: u16,
267}
268
269impl From<u32> for TargetInfo {
270    fn from(value: u32) -> Self {
271        Self {
272            endpoint_id: (value >> 16) as u16,
273            vcpu_id: value as u16,
274        }
275    }
276}
277
278impl From<TargetInfo> for u32 {
279    fn from(value: TargetInfo) -> Self {
280        ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
281    }
282}
283
284/// Generic arguments of the `FFA_SUCCESS` interface. The interpretation of the arguments depends on
285/// the interface that initiated the request. The application code has knowledge of the request, so
286/// it has to convert `SuccessArgs` into/from a specific success args structure that matches the
287/// request.
288///
289/// The current specialized success arguments types are:
290/// * `FFA_FEATURES` - [`SuccessArgsFeatures`]
291/// * `FFA_ID_GET` - [`SuccessArgsIdGet`]
292/// * `FFA_SPM_ID_GET` - [`SuccessArgsSpmIdGet`]
293/// * `FFA_PARTITION_INFO_GET` - [`partition_info::SuccessArgsPartitionInfoGet`]
294/// * `FFA_PARTITION_INFO_GET_REGS` - [`partition_info::SuccessArgsPartitionInfoGetRegs`]
295/// * `FFA_NOTIFICATION_GET` - [`SuccessArgsNotificationGet`]
296/// * `FFA_NOTIFICATION_INFO_GET_32` - [`SuccessArgsNotificationInfoGet32`]
297/// * `FFA_NOTIFICATION_INFO_GET_64` - [`SuccessArgsNotificationInfoGet64`]
298#[derive(Debug, Eq, PartialEq, Clone, Copy)]
299pub enum SuccessArgs {
300    Args32([u32; 6]),
301    Args64([u64; 6]),
302    Args64_2([u64; 16]),
303}
304
305impl SuccessArgs {
306    fn try_get_args32(self) -> Result<[u32; 6], Error> {
307        match self {
308            SuccessArgs::Args32(args) => Ok(args),
309            SuccessArgs::Args64(_) | SuccessArgs::Args64_2(_) => {
310                Err(Error::InvalidSuccessArgsVariant)
311            }
312        }
313    }
314
315    fn try_get_args64(self) -> Result<[u64; 6], Error> {
316        match self {
317            SuccessArgs::Args64(args) => Ok(args),
318            SuccessArgs::Args32(_) | SuccessArgs::Args64_2(_) => {
319                Err(Error::InvalidSuccessArgsVariant)
320            }
321        }
322    }
323
324    fn try_get_args64_2(self) -> Result<[u64; 16], Error> {
325        match self {
326            SuccessArgs::Args64_2(args) => Ok(args),
327            SuccessArgs::Args32(_) | SuccessArgs::Args64(_) => {
328                Err(Error::InvalidSuccessArgsVariant)
329            }
330        }
331    }
332}
333
334/// Entrypoint address argument for `FFA_SECONDARY_EP_REGISTER` interface.
335#[derive(Debug, Eq, PartialEq, Clone, Copy)]
336pub enum SecondaryEpRegisterAddr {
337    Addr32(u32),
338    Addr64(u64),
339}
340
341/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
342#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
343pub struct Version(pub u16, pub u16);
344
345impl Version {
346    // The FF-A spec mandates that bit[31] of a version number must be 0
347    const MBZ_BITS: u32 = 1 << 31;
348
349    /// Returns whether the caller's version (self) is compatible with the callee's version (input
350    /// parameter)
351    pub fn is_compatible_to(&self, callee_version: &Version) -> bool {
352        self.0 == callee_version.0 && self.1 <= callee_version.1
353    }
354
355    /// Returns true if the specified FF-A version uses 18 registers for calls, false if it uses 8.
356    pub fn needs_18_regs(&self) -> bool {
357        *self >= Version(1, 2)
358    }
359}
360
361impl TryFrom<u32> for Version {
362    type Error = Error;
363
364    fn try_from(val: u32) -> Result<Self, Self::Error> {
365        if (val & Self::MBZ_BITS) != 0 {
366            Err(Error::InvalidVersion(val))
367        } else {
368            Ok(Self((val >> 16) as u16, val as u16))
369        }
370    }
371}
372
373impl From<Version> for u32 {
374    fn from(v: Version) -> Self {
375        let v_u32 = ((v.0 as u32) << 16) | v.1 as u32;
376        assert!(v_u32 & Version::MBZ_BITS == 0);
377        v_u32
378    }
379}
380
381impl Display for Version {
382    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
383        write!(f, "{}.{}", self.0, self.1)
384    }
385}
386
387impl Debug for Version {
388    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
389        Display::fmt(self, f)
390    }
391}
392
393/// Feature IDs used by the `FFA_FEATURES` interface.
394#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
395#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
396#[repr(u8)]
397pub enum FeatureId {
398    NotificationPendingInterrupt = 0x1,
399    ScheduleReceiverInterrupt = 0x2,
400    ManagedExitInterrupt = 0x3,
401}
402
403/// Arguments for the `FFA_FEATURES` interface.
404#[derive(Debug, Eq, PartialEq, Clone, Copy)]
405pub enum Feature {
406    FuncId(FuncId),
407    FeatureId(FeatureId),
408    Unknown(u32),
409}
410
411impl From<u32> for Feature {
412    fn from(value: u32) -> Self {
413        // Bit[31] is set for all valid FF-A function IDs so we don't have to check it separately
414        if let Ok(func_id) = value.try_into() {
415            Self::FuncId(func_id)
416        } else if let Ok(feat_id) = (value as u8).try_into() {
417            Self::FeatureId(feat_id)
418        } else {
419            Self::Unknown(value)
420        }
421    }
422}
423
424impl From<Feature> for u32 {
425    fn from(value: Feature) -> Self {
426        match value {
427            Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
428            Feature::FeatureId(feature_id) => feature_id as u32,
429            Feature::Unknown(id) => id,
430        }
431    }
432}
433
434/// `FFA_FEATURES` specific success argument structure. This type needs further specialization based
435/// on 'FF-A function ID or Feature ID' field of the preceeding `FFA_FEATURES` request.
436#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
437pub struct SuccessArgsFeatures {
438    pub properties: [u32; 2],
439}
440
441impl From<SuccessArgsFeatures> for SuccessArgs {
442    fn from(value: SuccessArgsFeatures) -> Self {
443        Self::Args32([value.properties[0], value.properties[1], 0, 0, 0, 0])
444    }
445}
446
447impl TryFrom<SuccessArgs> for SuccessArgsFeatures {
448    type Error = Error;
449
450    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
451        let args = value.try_get_args32()?;
452
453        Ok(Self {
454            properties: [args[0], args[1]],
455        })
456    }
457}
458
459/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
460#[derive(Debug, Eq, PartialEq, Clone, Copy)]
461pub enum RxTxAddr {
462    Addr32 { rx: u32, tx: u32 },
463    Addr64 { rx: u64, tx: u64 },
464}
465
466/// `FFA_ID_GET` specific success argument structure.
467#[derive(Debug, Eq, PartialEq, Clone, Copy)]
468pub struct SuccessArgsIdGet {
469    pub id: u16,
470}
471
472impl From<SuccessArgsIdGet> for SuccessArgs {
473    fn from(value: SuccessArgsIdGet) -> Self {
474        SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
475    }
476}
477
478impl TryFrom<SuccessArgs> for SuccessArgsIdGet {
479    type Error = Error;
480
481    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
482        let args = value.try_get_args32()?;
483        Ok(Self { id: args[0] as u16 })
484    }
485}
486
487/// `FFA_SPM_ID_GET` specific success argument structure.
488#[derive(Debug, Eq, PartialEq, Clone, Copy)]
489pub struct SuccessArgsSpmIdGet {
490    pub id: u16,
491}
492
493impl From<SuccessArgsSpmIdGet> for SuccessArgs {
494    fn from(value: SuccessArgsSpmIdGet) -> Self {
495        SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
496    }
497}
498
499impl TryFrom<SuccessArgs> for SuccessArgsSpmIdGet {
500    type Error = Error;
501
502    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
503        let args = value.try_get_args32()?;
504        Ok(Self { id: args[0] as u16 })
505    }
506}
507
508/// Flags of the `FFA_PARTITION_INFO_GET` interface.
509#[derive(Debug, Eq, PartialEq, Clone, Copy)]
510pub struct PartitionInfoGetFlags {
511    pub count_only: bool,
512}
513
514impl PartitionInfoGetFlags {
515    const RETURN_INFORMATION_TYPE_FLAG: u32 = 1 << 0;
516    const MBZ_BITS: u32 = 0xffff_fffe;
517}
518
519impl TryFrom<u32> for PartitionInfoGetFlags {
520    type Error = Error;
521
522    fn try_from(val: u32) -> Result<Self, Self::Error> {
523        if (val & Self::MBZ_BITS) != 0 {
524            Err(Error::InvalidPartitionInfoGetFlag(val))
525        } else {
526            Ok(Self {
527                count_only: val & Self::RETURN_INFORMATION_TYPE_FLAG != 0,
528            })
529        }
530    }
531}
532
533impl From<PartitionInfoGetFlags> for u32 {
534    fn from(flags: PartitionInfoGetFlags) -> Self {
535        let mut bits: u32 = 0;
536        if flags.count_only {
537            bits |= PartitionInfoGetFlags::RETURN_INFORMATION_TYPE_FLAG;
538        }
539        bits
540    }
541}
542
543/// Flags field of the `FFA_MSG_SEND2` interface.
544#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
545pub struct MsgSend2Flags {
546    pub delay_schedule_receiver: bool,
547}
548
549impl MsgSend2Flags {
550    const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
551    const MBZ_BITS: u32 = 0xffff_fffd;
552}
553
554impl TryFrom<u32> for MsgSend2Flags {
555    type Error = Error;
556
557    fn try_from(val: u32) -> Result<Self, Self::Error> {
558        if (val & Self::MBZ_BITS) != 0 {
559            Err(Error::InvalidMsgSend2Flag(val))
560        } else {
561            Ok(MsgSend2Flags {
562                delay_schedule_receiver: val & Self::DELAY_SCHEDULE_RECEIVER != 0,
563            })
564        }
565    }
566}
567
568impl From<MsgSend2Flags> for u32 {
569    fn from(flags: MsgSend2Flags) -> Self {
570        let mut bits: u32 = 0;
571        if flags.delay_schedule_receiver {
572            bits |= MsgSend2Flags::DELAY_SCHEDULE_RECEIVER;
573        }
574        bits
575    }
576}
577
578/// Composite type for capturing success and error return codes for the VM availability messages.
579///
580/// Error codes are handled by the `FfaError` type. Having a separate type for errors helps using
581/// `Result<(), FfaError>`. If a single type would include both success and error values,
582/// then `Err(FfaError::Success)` would be incomprehensible.
583#[derive(Debug, Eq, PartialEq, Clone, Copy)]
584pub enum VmAvailabilityStatus {
585    Success,
586    Error(FfaError),
587}
588
589impl TryFrom<i32> for VmAvailabilityStatus {
590    type Error = Error;
591    fn try_from(value: i32) -> Result<Self, <Self as TryFrom<i32>>::Error> {
592        Ok(match value {
593            0 => Self::Success,
594            error_code => Self::Error(FfaError::try_from(error_code)?),
595        })
596    }
597}
598
599impl From<VmAvailabilityStatus> for i32 {
600    fn from(value: VmAvailabilityStatus) -> Self {
601        match value {
602            VmAvailabilityStatus::Success => 0,
603            VmAvailabilityStatus::Error(error_code) => error_code.into(),
604        }
605    }
606}
607
608/// Arguments for the Power Warm Boot `FFA_MSG_SEND_DIRECT_REQ` interface.
609#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
610#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedWarmBootType))]
611#[repr(u32)]
612pub enum WarmBootType {
613    ExitFromSuspend = 0,
614    ExitFromLowPower = 1,
615}
616
617/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
618#[derive(Debug, Eq, PartialEq, Clone, Copy)]
619pub enum DirectMsgArgs {
620    Args32([u32; 5]),
621    Args64([u64; 5]),
622    /// Message for forwarding FFA_VERSION call from Normal world to the SPMC
623    VersionReq {
624        version: Version,
625    },
626    /// Response message to forwarded FFA_VERSION call from the Normal world
627    /// Contains the version returned by the SPMC or None
628    VersionResp {
629        version: Option<Version>,
630    },
631    /// Message for a power management operation initiated by a PSCI function
632    PowerPsciReq32 {
633        // params[i]: Input parameter in w[i] in PSCI function invocation at EL3.
634        // params[0]: Function ID.
635        params: [u32; 4],
636    },
637    /// Message for a power management operation initiated by a PSCI function
638    PowerPsciReq64 {
639        // params[i]: Input parameter in x[i] in PSCI function invocation at EL3.
640        // params[0]: Function ID.
641        params: [u64; 4],
642    },
643    /// Message for a warm boot
644    PowerWarmBootReq {
645        boot_type: WarmBootType,
646    },
647    /// Response message to indicate return status of the last power management request message
648    /// Return error code SUCCESS or DENIED as defined in PSCI spec. Caller is left to do the
649    /// parsing of the return status.
650    PowerPsciResp {
651        psci_status: i32,
652    },
653    /// Message to signal creation of a VM
654    VmCreated {
655        // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
656        // information associated with the created VM.
657        // The invalid memory region handle must be specified by the Hypervisor if this field is not
658        //  used.
659        handle: memory_management::Handle,
660        vm_id: u16,
661    },
662    /// Message to acknowledge creation of a VM
663    VmCreatedAck {
664        sp_status: VmAvailabilityStatus,
665    },
666    /// Message to signal destruction of a VM
667    VmDestructed {
668        // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
669        // information associated with the created VM.
670        // The invalid memory region handle must be specified by the Hypervisor if this field is not
671        //  used.
672        handle: memory_management::Handle,
673        vm_id: u16,
674    },
675    /// Message to acknowledge destruction of a VM
676    VmDestructedAck {
677        sp_status: VmAvailabilityStatus,
678    },
679}
680
681impl DirectMsgArgs {
682    // Flags for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
683
684    const FWK_MSG_BITS: u32 = 1 << 31;
685    const VERSION_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1000;
686    const VERSION_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1001;
687    const POWER_PSCI_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS;
688    const POWER_WARM_BOOT_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0001;
689    const POWER_PSCI_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0010;
690    const VM_CREATED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0100;
691    const VM_CREATED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0101;
692    const VM_DESTRUCTED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0110;
693    const VM_DESTRUCTED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0111;
694}
695
696/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
697#[derive(Debug, Eq, PartialEq, Clone, Copy)]
698pub struct DirectMsg2Args(pub [u64; 14]);
699
700/// Flags field of the `FFA_MSG_WAIT` interface.
701#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
702pub struct MsgWaitFlags {
703    pub retain_rx_buffer: bool,
704}
705
706impl MsgWaitFlags {
707    const RETAIN_RX_BUFFER: u32 = 0x01;
708    const MBZ_BITS: u32 = 0xfffe;
709}
710
711impl TryFrom<u32> for MsgWaitFlags {
712    type Error = Error;
713
714    fn try_from(val: u32) -> Result<Self, Self::Error> {
715        if (val & Self::MBZ_BITS) != 0 {
716            Err(Error::InvalidMsgWaitFlag(val))
717        } else {
718            Ok(MsgWaitFlags {
719                retain_rx_buffer: val & Self::RETAIN_RX_BUFFER != 0,
720            })
721        }
722    }
723}
724
725impl From<MsgWaitFlags> for u32 {
726    fn from(flags: MsgWaitFlags) -> Self {
727        let mut bits: u32 = 0;
728        if flags.retain_rx_buffer {
729            bits |= MsgWaitFlags::RETAIN_RX_BUFFER;
730        }
731        bits
732    }
733}
734
735/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
736/// descriptor.
737///
738/// Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX buffer is not
739/// used to transmit the transaction descriptor.
740#[derive(Debug, Eq, PartialEq, Clone, Copy)]
741pub enum MemOpBuf {
742    Buf32 { addr: u32, page_cnt: u32 },
743    Buf64 { addr: u64, page_cnt: u32 },
744}
745
746/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
747#[derive(Debug, Eq, PartialEq, Clone, Copy)]
748pub enum MemAddr {
749    Addr32(u32),
750    Addr64(u64),
751}
752
753impl MemAddr {
754    /// Returns the contained address.
755    pub fn address(&self) -> u64 {
756        match self {
757            MemAddr::Addr32(a) => (*a).into(),
758            MemAddr::Addr64(a) => *a,
759        }
760    }
761}
762
763/// Argument for the `FFA_CONSOLE_LOG` interface.
764#[derive(Debug, Eq, PartialEq, Clone, Copy)]
765pub enum ConsoleLogChars {
766    Chars32(ConsoleLogChars32),
767    Chars64(ConsoleLogChars64),
768}
769
770/// Generic type for storing `FFA_CONSOLE_LOG` character payload and its length in bytes.
771#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
772pub struct LogChars<T>
773where
774    T: IntoBytes + FromBytes + Immutable,
775{
776    char_cnt: u8,
777    char_lists: T,
778}
779
780impl<T> LogChars<T>
781where
782    T: IntoBytes + FromBytes + Immutable,
783{
784    const MAX_LENGTH: u8 = core::mem::size_of::<T>() as u8;
785
786    /// Returns true if there are no characters in the structure.
787    pub fn empty(&self) -> bool {
788        self.char_cnt == 0
789    }
790
791    /// Returns true if the structure is full.
792    pub fn full(&self) -> bool {
793        self.char_cnt as usize >= core::mem::size_of::<T>()
794    }
795
796    /// Returns the payload bytes.
797    pub fn bytes(&self) -> &[u8] {
798        &self.char_lists.as_bytes()[..self.char_cnt as usize]
799    }
800
801    /// Append byte slice to the end of the characters.
802    pub fn push(&mut self, source: &[u8]) -> usize {
803        let empty_area = &mut self.char_lists.as_mut_bytes()[self.char_cnt.into()..];
804        let len = empty_area.len().min(source.len());
805
806        empty_area[..len].copy_from_slice(&source[..len]);
807        self.char_cnt += len as u8;
808
809        len
810    }
811}
812
813/// Specialized type for 32-bit `FFA_CONSOLE_LOG` payload.
814pub type ConsoleLogChars32 = LogChars<[u32; 6]>;
815
816/// Specialized type for 64-bit `FFA_CONSOLE_LOG` payload.
817pub type ConsoleLogChars64 = LogChars<[u64; 16]>;
818
819/// Flags field of the `FFA_NOTIFICATION_BIND` interface.
820#[derive(Debug, Eq, PartialEq, Clone, Copy)]
821pub struct NotificationBindFlags {
822    pub per_vcpu_notification: bool,
823}
824
825impl NotificationBindFlags {
826    const PER_VCPU_NOTIFICATION: u32 = 1;
827}
828
829impl From<NotificationBindFlags> for u32 {
830    fn from(flags: NotificationBindFlags) -> Self {
831        let mut bits: u32 = 0;
832        if flags.per_vcpu_notification {
833            bits |= NotificationBindFlags::PER_VCPU_NOTIFICATION;
834        }
835        bits
836    }
837}
838
839impl From<u32> for NotificationBindFlags {
840    fn from(flags: u32) -> Self {
841        Self {
842            per_vcpu_notification: flags & Self::PER_VCPU_NOTIFICATION != 0,
843        }
844    }
845}
846
847/// Flags field of the `FFA_NOTIFICATION_SET` interface.
848#[derive(Debug, Eq, PartialEq, Clone, Copy)]
849pub struct NotificationSetFlags {
850    pub delay_schedule_receiver: bool,
851    pub vcpu_id: Option<u16>,
852}
853
854impl NotificationSetFlags {
855    const PER_VCP_NOTIFICATION: u32 = 1 << 0;
856    const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
857    const VCPU_ID_SHIFT: u32 = 16;
858
859    const MBZ_BITS: u32 = 0xfffc;
860}
861
862impl From<NotificationSetFlags> for u32 {
863    fn from(flags: NotificationSetFlags) -> Self {
864        let mut bits: u32 = 0;
865
866        if flags.delay_schedule_receiver {
867            bits |= NotificationSetFlags::DELAY_SCHEDULE_RECEIVER;
868        }
869        if let Some(vcpu_id) = flags.vcpu_id {
870            bits |= NotificationSetFlags::PER_VCP_NOTIFICATION;
871            bits |= u32::from(vcpu_id) << NotificationSetFlags::VCPU_ID_SHIFT;
872        }
873
874        bits
875    }
876}
877
878impl TryFrom<u32> for NotificationSetFlags {
879    type Error = Error;
880
881    fn try_from(flags: u32) -> Result<Self, Self::Error> {
882        if (flags & Self::MBZ_BITS) != 0 {
883            return Err(Error::InvalidNotificationSetFlag(flags));
884        }
885
886        let tentative_vcpu_id = (flags >> Self::VCPU_ID_SHIFT) as u16;
887
888        let vcpu_id = if (flags & Self::PER_VCP_NOTIFICATION) != 0 {
889            Some(tentative_vcpu_id)
890        } else {
891            if tentative_vcpu_id != 0 {
892                return Err(Error::InvalidNotificationSetFlag(flags));
893            }
894            None
895        };
896
897        Ok(Self {
898            delay_schedule_receiver: (flags & Self::DELAY_SCHEDULE_RECEIVER) != 0,
899            vcpu_id,
900        })
901    }
902}
903
904/// Flags field of the `FFA_NOTIFICATION_GET` interface.
905#[derive(Debug, Eq, PartialEq, Clone, Copy)]
906pub struct NotificationGetFlags {
907    pub sp_bitmap_id: bool,
908    pub vm_bitmap_id: bool,
909    pub spm_bitmap_id: bool,
910    pub hyp_bitmap_id: bool,
911}
912
913impl NotificationGetFlags {
914    const SP_BITMAP_ID: u32 = 1;
915    const VM_BITMAP_ID: u32 = 1 << 1;
916    const SPM_BITMAP_ID: u32 = 1 << 2;
917    const HYP_BITMAP_ID: u32 = 1 << 3;
918}
919
920impl From<NotificationGetFlags> for u32 {
921    fn from(flags: NotificationGetFlags) -> Self {
922        let mut bits: u32 = 0;
923        if flags.sp_bitmap_id {
924            bits |= NotificationGetFlags::SP_BITMAP_ID;
925        }
926        if flags.vm_bitmap_id {
927            bits |= NotificationGetFlags::VM_BITMAP_ID;
928        }
929        if flags.spm_bitmap_id {
930            bits |= NotificationGetFlags::SPM_BITMAP_ID;
931        }
932        if flags.hyp_bitmap_id {
933            bits |= NotificationGetFlags::HYP_BITMAP_ID;
934        }
935        bits
936    }
937}
938
939impl From<u32> for NotificationGetFlags {
940    // This is a "from" instead of a "try_from" because Reserved Bits are SBZ, *not* MBZ.
941    fn from(flags: u32) -> Self {
942        Self {
943            sp_bitmap_id: (flags & Self::SP_BITMAP_ID) != 0,
944            vm_bitmap_id: (flags & Self::VM_BITMAP_ID) != 0,
945            spm_bitmap_id: (flags & Self::SPM_BITMAP_ID) != 0,
946            hyp_bitmap_id: (flags & Self::HYP_BITMAP_ID) != 0,
947        }
948    }
949}
950
951/// `FFA_NOTIFICATION_GET` specific success argument structure.
952#[derive(Debug, Eq, PartialEq, Clone, Copy)]
953pub struct SuccessArgsNotificationGet {
954    pub sp_notifications: Option<u64>,
955    pub vm_notifications: Option<u64>,
956    pub spm_notifications: Option<u32>,
957    pub hypervisor_notifications: Option<u32>,
958}
959
960impl From<SuccessArgsNotificationGet> for SuccessArgs {
961    fn from(value: SuccessArgsNotificationGet) -> Self {
962        let mut args = [0; 6];
963
964        if let Some(bitmap) = value.sp_notifications {
965            args[0] = bitmap as u32;
966            args[1] = (bitmap >> 32) as u32;
967        }
968
969        if let Some(bitmap) = value.vm_notifications {
970            args[2] = bitmap as u32;
971            args[3] = (bitmap >> 32) as u32;
972        }
973
974        if let Some(bitmap) = value.spm_notifications {
975            args[4] = bitmap;
976        }
977
978        if let Some(bitmap) = value.hypervisor_notifications {
979            args[5] = bitmap;
980        }
981
982        Self::Args32(args)
983    }
984}
985
986impl TryFrom<(NotificationGetFlags, SuccessArgs)> for SuccessArgsNotificationGet {
987    type Error = Error;
988
989    fn try_from(value: (NotificationGetFlags, SuccessArgs)) -> Result<Self, Self::Error> {
990        let (flags, value) = value;
991        let args = value.try_get_args32()?;
992
993        let sp_notifications = if flags.sp_bitmap_id {
994            Some(u64::from(args[0]) | (u64::from(args[1]) << 32))
995        } else {
996            None
997        };
998
999        let vm_notifications = if flags.vm_bitmap_id {
1000            Some(u64::from(args[2]) | (u64::from(args[3]) << 32))
1001        } else {
1002            None
1003        };
1004
1005        let spm_notifications = if flags.spm_bitmap_id {
1006            Some(args[4])
1007        } else {
1008            None
1009        };
1010
1011        let hypervisor_notifications = if flags.hyp_bitmap_id {
1012            Some(args[5])
1013        } else {
1014            None
1015        };
1016
1017        Ok(Self {
1018            sp_notifications,
1019            vm_notifications,
1020            spm_notifications,
1021            hypervisor_notifications,
1022        })
1023    }
1024}
1025
1026/// `FFA_NOTIFICATION_INFO_GET` specific success argument structure. The `MAX_COUNT` parameter
1027/// depends on the 32-bit or 64-bit packing.
1028#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1029pub struct SuccessArgsNotificationInfoGet<const MAX_COUNT: usize> {
1030    pub more_pending_notifications: bool,
1031    list_count: usize,
1032    id_counts: [u8; MAX_COUNT],
1033    ids: [u16; MAX_COUNT],
1034}
1035
1036impl<const MAX_COUNT: usize> Default for SuccessArgsNotificationInfoGet<MAX_COUNT> {
1037    fn default() -> Self {
1038        Self {
1039            more_pending_notifications: false,
1040            list_count: 0,
1041            id_counts: [0; MAX_COUNT],
1042            ids: [0; MAX_COUNT],
1043        }
1044    }
1045}
1046
1047impl<const MAX_COUNT: usize> SuccessArgsNotificationInfoGet<MAX_COUNT> {
1048    const MORE_PENDING_NOTIFICATIONS_FLAG: u64 = 1 << 0;
1049    const LIST_COUNT_SHIFT: usize = 7;
1050    const LIST_COUNT_MASK: u64 = 0x1f;
1051    const ID_COUNT_SHIFT: usize = 12;
1052    const ID_COUNT_MASK: u64 = 0x03;
1053    const ID_COUNT_BITS: usize = 2;
1054
1055    pub fn add_list(&mut self, endpoint: u16, vcpu_ids: &[u16]) -> Result<(), Error> {
1056        if self.list_count >= MAX_COUNT || vcpu_ids.len() > Self::ID_COUNT_MASK as usize {
1057            return Err(Error::InvalidNotificationCount);
1058        }
1059
1060        // Each list contains at least one ID: the partition ID, followed by vCPU IDs. The number
1061        // of vCPU IDs is recorded in `id_counts`.
1062        let mut current_id_index = self.list_count + self.id_counts.iter().sum::<u8>() as usize;
1063        if current_id_index + 1 + vcpu_ids.len() > MAX_COUNT {
1064            // The new list does not fit into the available space for IDs.
1065            return Err(Error::InvalidNotificationCount);
1066        }
1067
1068        self.id_counts[self.list_count] = vcpu_ids.len() as u8;
1069        self.list_count += 1;
1070
1071        // The first ID is the endpoint ID.
1072        self.ids[current_id_index] = endpoint;
1073        current_id_index += 1;
1074
1075        // Insert the vCPU IDs.
1076        self.ids[current_id_index..current_id_index + vcpu_ids.len()].copy_from_slice(vcpu_ids);
1077
1078        Ok(())
1079    }
1080
1081    pub fn iter(&self) -> NotificationInfoGetIterator<'_> {
1082        NotificationInfoGetIterator {
1083            list_index: 0,
1084            id_index: 0,
1085            id_count: &self.id_counts[0..self.list_count],
1086            ids: &self.ids,
1087        }
1088    }
1089
1090    /// Pack flags field and IDs.
1091    fn pack(self) -> (u64, [u16; MAX_COUNT]) {
1092        let mut flags = if self.more_pending_notifications {
1093            Self::MORE_PENDING_NOTIFICATIONS_FLAG
1094        } else {
1095            0
1096        };
1097
1098        flags |= (self.list_count as u64) << Self::LIST_COUNT_SHIFT;
1099        for (count, shift) in self.id_counts.iter().take(self.list_count).zip(
1100            (Self::ID_COUNT_SHIFT..Self::ID_COUNT_SHIFT + Self::ID_COUNT_BITS * MAX_COUNT)
1101                .step_by(Self::ID_COUNT_BITS),
1102        ) {
1103            flags |= u64::from(*count) << shift;
1104        }
1105
1106        (flags, self.ids)
1107    }
1108
1109    /// Unpack flags field and IDs.
1110    fn unpack(flags: u64, ids: [u16; MAX_COUNT]) -> Result<Self, Error> {
1111        let count_of_lists = ((flags >> Self::LIST_COUNT_SHIFT) & Self::LIST_COUNT_MASK) as usize;
1112
1113        if count_of_lists > MAX_COUNT {
1114            return Err(Error::InvalidNotificationCount);
1115        }
1116
1117        let mut count_of_ids = [0; MAX_COUNT];
1118        let mut count_of_ids_bits = flags >> Self::ID_COUNT_SHIFT;
1119
1120        for id in count_of_ids.iter_mut().take(count_of_lists) {
1121            *id = (count_of_ids_bits & Self::ID_COUNT_MASK) as u8;
1122            count_of_ids_bits >>= Self::ID_COUNT_BITS;
1123        }
1124
1125        let id_field_count = count_of_lists + count_of_ids.iter().sum::<u8>() as usize;
1126        if id_field_count > MAX_COUNT {
1127            return Err(Error::InvalidNotificationCount);
1128        }
1129
1130        Ok(Self {
1131            more_pending_notifications: (flags & Self::MORE_PENDING_NOTIFICATIONS_FLAG) != 0,
1132            list_count: count_of_lists,
1133            id_counts: count_of_ids,
1134            ids,
1135        })
1136    }
1137}
1138
1139/// `FFA_NOTIFICATION_INFO_GET_32` specific success argument structure.
1140pub type SuccessArgsNotificationInfoGet32 = SuccessArgsNotificationInfoGet<10>;
1141
1142impl From<SuccessArgsNotificationInfoGet32> for SuccessArgs {
1143    fn from(value: SuccessArgsNotificationInfoGet32) -> Self {
1144        let (flags, ids) = value.pack();
1145        let id_regs: [u32; 5] = transmute!(ids);
1146
1147        let mut args = [0; 6];
1148        args[0] = flags as u32;
1149        args[1..6].copy_from_slice(&id_regs);
1150
1151        SuccessArgs::Args32(args)
1152    }
1153}
1154
1155impl TryFrom<SuccessArgs> for SuccessArgsNotificationInfoGet32 {
1156    type Error = Error;
1157
1158    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1159        let args = value.try_get_args32()?;
1160        let flags = args[0].into();
1161        let id_regs: [u32; 5] = args[1..6].try_into().unwrap();
1162        Self::unpack(flags, transmute!(id_regs))
1163    }
1164}
1165
1166/// `FFA_NOTIFICATION_INFO_GET_64` specific success argument structure.
1167pub type SuccessArgsNotificationInfoGet64 = SuccessArgsNotificationInfoGet<20>;
1168
1169impl From<SuccessArgsNotificationInfoGet64> for SuccessArgs {
1170    fn from(value: SuccessArgsNotificationInfoGet64) -> Self {
1171        let (flags, ids) = value.pack();
1172        let id_regs: [u64; 5] = transmute!(ids);
1173
1174        let mut args = [0; 6];
1175        args[0] = flags;
1176        args[1..6].copy_from_slice(&id_regs);
1177
1178        SuccessArgs::Args64(args)
1179    }
1180}
1181
1182impl TryFrom<SuccessArgs> for SuccessArgsNotificationInfoGet64 {
1183    type Error = Error;
1184
1185    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1186        let args = value.try_get_args64()?;
1187        let flags = args[0];
1188        let id_regs: [u64; 5] = args[1..6].try_into().unwrap();
1189        Self::unpack(flags, transmute!(id_regs))
1190    }
1191}
1192
1193/// Iterator implementation for parsing the (partition ID, vCPU ID list) pairs of the `FFA_SUCCESS`
1194/// of an `FFA_NOTIFICATION_INFO_GET` call.
1195pub struct NotificationInfoGetIterator<'a> {
1196    list_index: usize,
1197    id_index: usize,
1198    id_count: &'a [u8],
1199    ids: &'a [u16],
1200}
1201
1202impl<'a> Iterator for NotificationInfoGetIterator<'a> {
1203    type Item = (u16, &'a [u16]);
1204
1205    fn next(&mut self) -> Option<Self::Item> {
1206        if self.list_index < self.id_count.len() {
1207            let partition_id = self.ids[self.id_index];
1208            let id_range =
1209                (self.id_index + 1)..=(self.id_index + self.id_count[self.list_index] as usize);
1210
1211            self.id_index += 1 + self.id_count[self.list_index] as usize;
1212            self.list_index += 1;
1213
1214            Some((partition_id, &self.ids[id_range]))
1215        } else {
1216            None
1217        }
1218    }
1219}
1220
1221/// FF-A "message types", the terminology used by the spec is "interfaces".
1222///
1223/// The interfaces are used by FF-A components for communication at an FF-A instance. The spec also
1224/// describes the valid FF-A instances and conduits for each interface.
1225#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1226pub enum Interface {
1227    Error {
1228        target_info: TargetInfo,
1229        error_code: FfaError,
1230        error_arg: u32,
1231    },
1232    Success {
1233        target_info: TargetInfo,
1234        args: SuccessArgs,
1235    },
1236    Interrupt {
1237        target_info: TargetInfo,
1238        interrupt_id: u32,
1239    },
1240    Version {
1241        input_version: Version,
1242    },
1243    VersionOut {
1244        output_version: Version,
1245    },
1246    Features {
1247        feat_id: Feature,
1248        input_properties: u32,
1249    },
1250    RxAcquire {
1251        vm_id: u16,
1252    },
1253    RxRelease {
1254        vm_id: u16,
1255    },
1256    RxTxMap {
1257        addr: RxTxAddr,
1258        page_cnt: u32,
1259    },
1260    RxTxUnmap {
1261        id: u16,
1262    },
1263    PartitionInfoGet {
1264        uuid: Uuid,
1265        flags: PartitionInfoGetFlags,
1266    },
1267    PartitionInfoGetRegs {
1268        uuid: Uuid,
1269        start_index: u16,
1270        info_tag: u16,
1271    },
1272    IdGet,
1273    SpmIdGet,
1274    MsgWait {
1275        flags: Option<MsgWaitFlags>,
1276    },
1277    Yield,
1278    Run {
1279        target_info: TargetInfo,
1280    },
1281    NormalWorldResume,
1282    SecondaryEpRegister {
1283        entrypoint: SecondaryEpRegisterAddr,
1284    },
1285    MsgSend2 {
1286        sender_vm_id: u16,
1287        flags: MsgSend2Flags,
1288    },
1289    MsgSendDirectReq {
1290        src_id: u16,
1291        dst_id: u16,
1292        args: DirectMsgArgs,
1293    },
1294    MsgSendDirectResp {
1295        src_id: u16,
1296        dst_id: u16,
1297        args: DirectMsgArgs,
1298    },
1299    MsgSendDirectReq2 {
1300        src_id: u16,
1301        dst_id: u16,
1302        uuid: Uuid,
1303        args: DirectMsg2Args,
1304    },
1305    MsgSendDirectResp2 {
1306        src_id: u16,
1307        dst_id: u16,
1308        args: DirectMsg2Args,
1309    },
1310    MemDonate {
1311        total_len: u32,
1312        frag_len: u32,
1313        buf: Option<MemOpBuf>,
1314    },
1315    MemLend {
1316        total_len: u32,
1317        frag_len: u32,
1318        buf: Option<MemOpBuf>,
1319    },
1320    MemShare {
1321        total_len: u32,
1322        frag_len: u32,
1323        buf: Option<MemOpBuf>,
1324    },
1325    MemRetrieveReq {
1326        total_len: u32,
1327        frag_len: u32,
1328        buf: Option<MemOpBuf>,
1329    },
1330    MemRetrieveResp {
1331        total_len: u32,
1332        frag_len: u32,
1333    },
1334    MemRelinquish,
1335    MemReclaim {
1336        handle: memory_management::Handle,
1337        flags: memory_management::MemReclaimFlags,
1338    },
1339    MemPermGet {
1340        addr: MemAddr,
1341        /// The actual number of pages queried by the call.  It is calculated by adding one to the
1342        /// corresponding register's value, i.e. zero in the register means one page. For FF-A v1.2
1343        /// and lower the register value MBZ, so the page count is always 1. For higher versions the
1344        /// page count can be any nonzero value.
1345        page_cnt: u32,
1346    },
1347    MemPermSet {
1348        addr: MemAddr,
1349        page_cnt: u32,
1350        mem_perm: memory_management::MemPermissionsGetSet,
1351    },
1352    ConsoleLog {
1353        chars: ConsoleLogChars,
1354    },
1355    NotificationBitmapCreate {
1356        vm_id: u16,
1357        vcpu_cnt: u32,
1358    },
1359    NotificationBitmapDestroy {
1360        vm_id: u16,
1361    },
1362    NotificationBind {
1363        sender_id: u16,
1364        receiver_id: u16,
1365        flags: NotificationBindFlags,
1366        bitmap: u64,
1367    },
1368    NotificationUnbind {
1369        sender_id: u16,
1370        receiver_id: u16,
1371        bitmap: u64,
1372    },
1373    NotificationSet {
1374        sender_id: u16,
1375        receiver_id: u16,
1376        flags: NotificationSetFlags,
1377        bitmap: u64,
1378    },
1379    NotificationGet {
1380        vcpu_id: u16,
1381        endpoint_id: u16,
1382        flags: NotificationGetFlags,
1383    },
1384    NotificationInfoGet {
1385        is_32bit: bool,
1386    },
1387    El3IntrHandle,
1388}
1389
1390impl Interface {
1391    /// Returns the function ID for the call, if it has one.
1392    pub fn function_id(&self) -> Option<FuncId> {
1393        match self {
1394            Interface::Error { .. } => Some(FuncId::Error),
1395            Interface::Success { args, .. } => match args {
1396                SuccessArgs::Args32(..) => Some(FuncId::Success32),
1397                SuccessArgs::Args64(..) | SuccessArgs::Args64_2(..) => Some(FuncId::Success64),
1398            },
1399            Interface::Interrupt { .. } => Some(FuncId::Interrupt),
1400            Interface::Version { .. } => Some(FuncId::Version),
1401            Interface::VersionOut { .. } => None,
1402            Interface::Features { .. } => Some(FuncId::Features),
1403            Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
1404            Interface::RxRelease { .. } => Some(FuncId::RxRelease),
1405            Interface::RxTxMap { addr, .. } => match addr {
1406                RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
1407                RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
1408            },
1409            Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
1410            Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
1411            Interface::PartitionInfoGetRegs { .. } => Some(FuncId::PartitionInfoGetRegs),
1412            Interface::IdGet => Some(FuncId::IdGet),
1413            Interface::SpmIdGet => Some(FuncId::SpmIdGet),
1414            Interface::MsgWait { .. } => Some(FuncId::MsgWait),
1415            Interface::Yield => Some(FuncId::Yield),
1416            Interface::Run { .. } => Some(FuncId::Run),
1417            Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
1418            Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
1419                SecondaryEpRegisterAddr::Addr32 { .. } => Some(FuncId::SecondaryEpRegister32),
1420                SecondaryEpRegisterAddr::Addr64 { .. } => Some(FuncId::SecondaryEpRegister64),
1421            },
1422            Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
1423            Interface::MsgSendDirectReq { args, .. } => match args {
1424                DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
1425                DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
1426                DirectMsgArgs::VersionReq { .. } => Some(FuncId::MsgSendDirectReq32),
1427                DirectMsgArgs::PowerPsciReq32 { .. } => Some(FuncId::MsgSendDirectReq32),
1428                DirectMsgArgs::PowerPsciReq64 { .. } => Some(FuncId::MsgSendDirectReq64),
1429                DirectMsgArgs::PowerWarmBootReq { .. } => Some(FuncId::MsgSendDirectReq32),
1430                DirectMsgArgs::VmCreated { .. } => Some(FuncId::MsgSendDirectReq32),
1431                DirectMsgArgs::VmDestructed { .. } => Some(FuncId::MsgSendDirectReq32),
1432                _ => panic!("Invalid direct request arguments: {:#?}", args),
1433            },
1434            Interface::MsgSendDirectResp { args, .. } => match args {
1435                DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
1436                DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
1437                DirectMsgArgs::VersionResp { .. } => Some(FuncId::MsgSendDirectResp32),
1438                DirectMsgArgs::PowerPsciResp { .. } => Some(FuncId::MsgSendDirectResp32),
1439                DirectMsgArgs::VmCreatedAck { .. } => Some(FuncId::MsgSendDirectResp32),
1440                DirectMsgArgs::VmDestructedAck { .. } => Some(FuncId::MsgSendDirectResp32),
1441                _ => panic!("Invalid direct response arguments: {:#?}", args),
1442            },
1443            Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
1444            Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
1445            Interface::MemDonate { buf, .. } => match buf {
1446                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
1447                _ => Some(FuncId::MemDonate32),
1448            },
1449            Interface::MemLend { buf, .. } => match buf {
1450                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
1451                _ => Some(FuncId::MemLend32),
1452            },
1453            Interface::MemShare { buf, .. } => match buf {
1454                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
1455                _ => Some(FuncId::MemShare32),
1456            },
1457            Interface::MemRetrieveReq { buf, .. } => match buf {
1458                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
1459                _ => Some(FuncId::MemRetrieveReq32),
1460            },
1461            Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
1462            Interface::MemRelinquish => Some(FuncId::MemRelinquish),
1463            Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
1464            Interface::MemPermGet { addr, .. } => match addr {
1465                MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
1466                MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
1467            },
1468            Interface::MemPermSet { addr, .. } => match addr {
1469                MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
1470                MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
1471            },
1472            Interface::ConsoleLog { chars, .. } => match chars {
1473                ConsoleLogChars::Chars32(_) => Some(FuncId::ConsoleLog32),
1474                ConsoleLogChars::Chars64(_) => Some(FuncId::ConsoleLog64),
1475            },
1476            Interface::NotificationBitmapCreate { .. } => Some(FuncId::NotificationBitmapCreate),
1477            Interface::NotificationBitmapDestroy { .. } => Some(FuncId::NotificationBitmapDestroy),
1478            Interface::NotificationBind { .. } => Some(FuncId::NotificationBind),
1479            Interface::NotificationUnbind { .. } => Some(FuncId::NotificationUnbind),
1480            Interface::NotificationSet { .. } => Some(FuncId::NotificationSet),
1481            Interface::NotificationGet { .. } => Some(FuncId::NotificationGet),
1482            Interface::NotificationInfoGet { is_32bit } => match is_32bit {
1483                true => Some(FuncId::NotificationInfoGet32),
1484                false => Some(FuncId::NotificationInfoGet64),
1485            },
1486            Interface::El3IntrHandle => Some(FuncId::El3IntrHandle),
1487        }
1488    }
1489
1490    /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
1491    pub fn is_32bit(&self) -> bool {
1492        if matches!(self, Self::VersionOut { .. }) {
1493            return true;
1494        }
1495
1496        self.function_id().unwrap().is_32bit()
1497    }
1498
1499    /// Returns the FF-A version that has introduced the function ID.
1500    pub fn minimum_ffa_version(&self) -> Version {
1501        if matches!(self, Self::VersionOut { .. }) {
1502            return Version(1, 0);
1503        }
1504
1505        self.function_id().unwrap().minimum_ffa_version()
1506    }
1507
1508    /// Parse interface from register contents. The caller must ensure that the `regs` argument has
1509    /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
1510    pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
1511        let func_id = FuncId::try_from(regs[0] as u32)?;
1512        if version < func_id.minimum_ffa_version() {
1513            return Err(Error::InvalidVersionForFunctionId(version, func_id));
1514        }
1515
1516        let reg_cnt = regs.len();
1517
1518        let msg = match reg_cnt {
1519            8 => {
1520                assert!(version <= Version(1, 1));
1521                Interface::unpack_regs8(version, regs.try_into().unwrap())?
1522            }
1523            18 => {
1524                assert!(version >= Version(1, 2));
1525                match func_id {
1526                    FuncId::ConsoleLog64
1527                    | FuncId::Success64
1528                    | FuncId::MsgSendDirectReq64_2
1529                    | FuncId::MsgSendDirectResp64_2
1530                    | FuncId::PartitionInfoGetRegs => {
1531                        Interface::unpack_regs18(version, regs.try_into().unwrap())?
1532                    }
1533                    _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
1534                }
1535            }
1536            _ => panic!(
1537                "Invalid number of registers ({}) for FF-A version {}",
1538                reg_cnt, version
1539            ),
1540        };
1541
1542        Ok(msg)
1543    }
1544
1545    fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
1546        let fid = FuncId::try_from(regs[0] as u32)?;
1547
1548        let msg = match fid {
1549            FuncId::Error => Self::Error {
1550                target_info: (regs[1] as u32).into(),
1551                error_code: FfaError::try_from(regs[2] as i32)?,
1552                error_arg: regs[3] as u32,
1553            },
1554            FuncId::Success32 => Self::Success {
1555                target_info: (regs[1] as u32).into(),
1556                args: SuccessArgs::Args32([
1557                    regs[2] as u32,
1558                    regs[3] as u32,
1559                    regs[4] as u32,
1560                    regs[5] as u32,
1561                    regs[6] as u32,
1562                    regs[7] as u32,
1563                ]),
1564            },
1565            FuncId::Success64 => Self::Success {
1566                target_info: (regs[1] as u32).into(),
1567                args: SuccessArgs::Args64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
1568            },
1569            FuncId::Interrupt => Self::Interrupt {
1570                target_info: (regs[1] as u32).into(),
1571                interrupt_id: regs[2] as u32,
1572            },
1573            FuncId::Version => Self::Version {
1574                input_version: (regs[1] as u32).try_into()?,
1575            },
1576            FuncId::Features => Self::Features {
1577                feat_id: (regs[1] as u32).into(),
1578                input_properties: regs[2] as u32,
1579            },
1580            FuncId::RxAcquire => Self::RxAcquire {
1581                vm_id: regs[1] as u16,
1582            },
1583            FuncId::RxRelease => Self::RxRelease {
1584                vm_id: regs[1] as u16,
1585            },
1586            FuncId::RxTxMap32 => {
1587                let addr = RxTxAddr::Addr32 {
1588                    rx: regs[2] as u32,
1589                    tx: regs[1] as u32,
1590                };
1591                let page_cnt = regs[3] as u32;
1592
1593                Self::RxTxMap { addr, page_cnt }
1594            }
1595            FuncId::RxTxMap64 => {
1596                let addr = RxTxAddr::Addr64 {
1597                    rx: regs[2],
1598                    tx: regs[1],
1599                };
1600                let page_cnt = regs[3] as u32;
1601
1602                Self::RxTxMap { addr, page_cnt }
1603            }
1604            FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
1605            FuncId::PartitionInfoGet => {
1606                let uuid_words = [
1607                    regs[1] as u32,
1608                    regs[2] as u32,
1609                    regs[3] as u32,
1610                    regs[4] as u32,
1611                ];
1612                let mut bytes: [u8; 16] = [0; 16];
1613                for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
1614                    bytes[i] = b;
1615                }
1616                Self::PartitionInfoGet {
1617                    uuid: Uuid::from_bytes(bytes),
1618                    flags: PartitionInfoGetFlags::try_from(regs[5] as u32)?,
1619                }
1620            }
1621            FuncId::IdGet => Self::IdGet,
1622            FuncId::SpmIdGet => Self::SpmIdGet,
1623            FuncId::MsgWait => Self::MsgWait {
1624                flags: if version >= Version(1, 2) {
1625                    Some(MsgWaitFlags::try_from(regs[2] as u32)?)
1626                } else {
1627                    None
1628                },
1629            },
1630            FuncId::Yield => Self::Yield,
1631            FuncId::Run => Self::Run {
1632                target_info: (regs[1] as u32).into(),
1633            },
1634            FuncId::NormalWorldResume => Self::NormalWorldResume,
1635            FuncId::SecondaryEpRegister32 => Self::SecondaryEpRegister {
1636                entrypoint: SecondaryEpRegisterAddr::Addr32(regs[1] as u32),
1637            },
1638            FuncId::SecondaryEpRegister64 => Self::SecondaryEpRegister {
1639                entrypoint: SecondaryEpRegisterAddr::Addr64(regs[1]),
1640            },
1641            FuncId::MsgSend2 => Self::MsgSend2 {
1642                sender_vm_id: regs[1] as u16,
1643                flags: (regs[2] as u32).try_into()?,
1644            },
1645            FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
1646                src_id: (regs[1] >> 16) as u16,
1647                dst_id: regs[1] as u16,
1648                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1649                    match regs[2] as u32 {
1650                        DirectMsgArgs::VERSION_REQ => DirectMsgArgs::VersionReq {
1651                            version: Version::try_from(regs[3] as u32)?,
1652                        },
1653                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq32 {
1654                            params: [
1655                                regs[3] as u32,
1656                                regs[4] as u32,
1657                                regs[5] as u32,
1658                                regs[6] as u32,
1659                            ],
1660                        },
1661                        DirectMsgArgs::POWER_WARM_BOOT_REQ => DirectMsgArgs::PowerWarmBootReq {
1662                            boot_type: WarmBootType::try_from(regs[3] as u32)?,
1663                        },
1664                        DirectMsgArgs::VM_CREATED => DirectMsgArgs::VmCreated {
1665                            handle: memory_management::Handle::from([
1666                                regs[3] as u32,
1667                                regs[4] as u32,
1668                            ]),
1669                            vm_id: regs[5] as u16,
1670                        },
1671                        DirectMsgArgs::VM_DESTRUCTED => DirectMsgArgs::VmDestructed {
1672                            handle: memory_management::Handle::from([
1673                                regs[3] as u32,
1674                                regs[4] as u32,
1675                            ]),
1676                            vm_id: regs[5] as u16,
1677                        },
1678                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1679                    }
1680                } else {
1681                    DirectMsgArgs::Args32([
1682                        regs[3] as u32,
1683                        regs[4] as u32,
1684                        regs[5] as u32,
1685                        regs[6] as u32,
1686                        regs[7] as u32,
1687                    ])
1688                },
1689            },
1690            FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
1691                src_id: (regs[1] >> 16) as u16,
1692                dst_id: regs[1] as u16,
1693                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1694                    match regs[2] as u32 {
1695                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq64 {
1696                            params: [regs[3], regs[4], regs[5], regs[6]],
1697                        },
1698                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1699                    }
1700                } else {
1701                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1702                },
1703            },
1704            FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
1705                src_id: (regs[1] >> 16) as u16,
1706                dst_id: regs[1] as u16,
1707                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1708                    match regs[2] as u32 {
1709                        DirectMsgArgs::VERSION_RESP => {
1710                            if regs[3] as i32 == FfaError::NotSupported.into() {
1711                                DirectMsgArgs::VersionResp { version: None }
1712                            } else {
1713                                DirectMsgArgs::VersionResp {
1714                                    version: Some(Version::try_from(regs[3] as u32)?),
1715                                }
1716                            }
1717                        }
1718                        DirectMsgArgs::POWER_PSCI_RESP => DirectMsgArgs::PowerPsciResp {
1719                            psci_status: regs[3] as i32,
1720                        },
1721                        DirectMsgArgs::VM_CREATED_ACK => DirectMsgArgs::VmCreatedAck {
1722                            sp_status: (regs[3] as i32).try_into()?,
1723                        },
1724                        DirectMsgArgs::VM_DESTRUCTED_ACK => DirectMsgArgs::VmDestructedAck {
1725                            sp_status: (regs[3] as i32).try_into()?,
1726                        },
1727                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1728                    }
1729                } else {
1730                    DirectMsgArgs::Args32([
1731                        regs[3] as u32,
1732                        regs[4] as u32,
1733                        regs[5] as u32,
1734                        regs[6] as u32,
1735                        regs[7] as u32,
1736                    ])
1737                },
1738            },
1739            FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
1740                src_id: (regs[1] >> 16) as u16,
1741                dst_id: regs[1] as u16,
1742                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1743                    return Err(Error::UnrecognisedFwkMsg(regs[2] as u32));
1744                } else {
1745                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1746                },
1747            },
1748            FuncId::MemDonate32 => Self::MemDonate {
1749                total_len: regs[1] as u32,
1750                frag_len: regs[2] as u32,
1751                buf: if regs[3] != 0 && regs[4] != 0 {
1752                    Some(MemOpBuf::Buf32 {
1753                        addr: regs[3] as u32,
1754                        page_cnt: regs[4] as u32,
1755                    })
1756                } else {
1757                    None
1758                },
1759            },
1760            FuncId::MemDonate64 => Self::MemDonate {
1761                total_len: regs[1] as u32,
1762                frag_len: regs[2] as u32,
1763                buf: if regs[3] != 0 && regs[4] != 0 {
1764                    Some(MemOpBuf::Buf64 {
1765                        addr: regs[3],
1766                        page_cnt: regs[4] as u32,
1767                    })
1768                } else {
1769                    None
1770                },
1771            },
1772            FuncId::MemLend32 => Self::MemLend {
1773                total_len: regs[1] as u32,
1774                frag_len: regs[2] as u32,
1775                buf: if regs[3] != 0 && regs[4] != 0 {
1776                    Some(MemOpBuf::Buf32 {
1777                        addr: regs[3] as u32,
1778                        page_cnt: regs[4] as u32,
1779                    })
1780                } else {
1781                    None
1782                },
1783            },
1784            FuncId::MemLend64 => Self::MemLend {
1785                total_len: regs[1] as u32,
1786                frag_len: regs[2] as u32,
1787                buf: if regs[3] != 0 && regs[4] != 0 {
1788                    Some(MemOpBuf::Buf64 {
1789                        addr: regs[3],
1790                        page_cnt: regs[4] as u32,
1791                    })
1792                } else {
1793                    None
1794                },
1795            },
1796            FuncId::MemShare32 => Self::MemShare {
1797                total_len: regs[1] as u32,
1798                frag_len: regs[2] as u32,
1799                buf: if regs[3] != 0 && regs[4] != 0 {
1800                    Some(MemOpBuf::Buf32 {
1801                        addr: regs[3] as u32,
1802                        page_cnt: regs[4] as u32,
1803                    })
1804                } else {
1805                    None
1806                },
1807            },
1808            FuncId::MemShare64 => Self::MemShare {
1809                total_len: regs[1] as u32,
1810                frag_len: regs[2] as u32,
1811                buf: if regs[3] != 0 && regs[4] != 0 {
1812                    Some(MemOpBuf::Buf64 {
1813                        addr: regs[3],
1814                        page_cnt: regs[4] as u32,
1815                    })
1816                } else {
1817                    None
1818                },
1819            },
1820            FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
1821                total_len: regs[1] as u32,
1822                frag_len: regs[2] as u32,
1823                buf: if regs[3] != 0 && regs[4] != 0 {
1824                    Some(MemOpBuf::Buf32 {
1825                        addr: regs[3] as u32,
1826                        page_cnt: regs[4] as u32,
1827                    })
1828                } else {
1829                    None
1830                },
1831            },
1832            FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
1833                total_len: regs[1] as u32,
1834                frag_len: regs[2] as u32,
1835                buf: if regs[3] != 0 && regs[4] != 0 {
1836                    Some(MemOpBuf::Buf64 {
1837                        addr: regs[3],
1838                        page_cnt: regs[4] as u32,
1839                    })
1840                } else {
1841                    None
1842                },
1843            },
1844            FuncId::MemRetrieveResp => Self::MemRetrieveResp {
1845                total_len: regs[1] as u32,
1846                frag_len: regs[2] as u32,
1847            },
1848            FuncId::MemRelinquish => Self::MemRelinquish,
1849            FuncId::MemReclaim => Self::MemReclaim {
1850                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
1851                flags: (regs[3] as u32).try_into()?,
1852            },
1853            FuncId::MemPermGet32 => {
1854                if (version <= Version(1, 2) && regs[2] != 0)
1855                    || (regs[2] as u32).checked_add(1).is_none()
1856                {
1857                    return Err(Error::MemoryManagementError(
1858                        memory_management::Error::InvalidPageCount,
1859                    ));
1860                }
1861
1862                Self::MemPermGet {
1863                    addr: MemAddr::Addr32(regs[1] as u32),
1864                    page_cnt: regs[2] as u32 + 1,
1865                }
1866            }
1867            FuncId::MemPermGet64 => {
1868                if (version <= Version(1, 2) && regs[2] != 0)
1869                    || (regs[2] as u32).checked_add(1).is_none()
1870                {
1871                    return Err(Error::MemoryManagementError(
1872                        memory_management::Error::InvalidPageCount,
1873                    ));
1874                }
1875
1876                Self::MemPermGet {
1877                    addr: MemAddr::Addr64(regs[1]),
1878                    page_cnt: regs[2] as u32 + 1,
1879                }
1880            }
1881            FuncId::MemPermSet32 => Self::MemPermSet {
1882                addr: MemAddr::Addr32(regs[1] as u32),
1883                page_cnt: regs[2] as u32,
1884                mem_perm: (regs[3] as u32).try_into()?,
1885            },
1886            FuncId::MemPermSet64 => Self::MemPermSet {
1887                addr: MemAddr::Addr64(regs[1]),
1888                page_cnt: regs[2] as u32,
1889                mem_perm: (regs[3] as u32).try_into()?,
1890            },
1891            FuncId::ConsoleLog32 => {
1892                let char_cnt = regs[1] as u8;
1893                if char_cnt > ConsoleLogChars32::MAX_LENGTH {
1894                    return Err(Error::InvalidCharacterCount(char_cnt));
1895                }
1896
1897                Self::ConsoleLog {
1898                    chars: ConsoleLogChars::Chars32(ConsoleLogChars32 {
1899                        char_cnt,
1900                        char_lists: [
1901                            regs[2] as u32,
1902                            regs[3] as u32,
1903                            regs[4] as u32,
1904                            regs[5] as u32,
1905                            regs[6] as u32,
1906                            regs[7] as u32,
1907                        ],
1908                    }),
1909                }
1910            }
1911            FuncId::NotificationBitmapCreate => {
1912                let tentative_vm_id = regs[1] as u32;
1913                if (tentative_vm_id >> 16) != 0 {
1914                    return Err(Error::InvalidVmId(tentative_vm_id));
1915                }
1916                Self::NotificationBitmapCreate {
1917                    vm_id: tentative_vm_id as u16,
1918                    vcpu_cnt: regs[2] as u32,
1919                }
1920            }
1921            FuncId::NotificationBitmapDestroy => {
1922                let tentative_vm_id = regs[1] as u32;
1923                if (tentative_vm_id >> 16) != 0 {
1924                    return Err(Error::InvalidVmId(tentative_vm_id));
1925                }
1926                Self::NotificationBitmapDestroy {
1927                    vm_id: tentative_vm_id as u16,
1928                }
1929            }
1930            FuncId::NotificationBind => Self::NotificationBind {
1931                sender_id: (regs[1] >> 16) as u16,
1932                receiver_id: regs[1] as u16,
1933                flags: (regs[2] as u32).into(),
1934                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
1935            },
1936            FuncId::NotificationUnbind => Self::NotificationUnbind {
1937                sender_id: (regs[1] >> 16) as u16,
1938                receiver_id: regs[1] as u16,
1939                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
1940            },
1941            FuncId::NotificationSet => Self::NotificationSet {
1942                sender_id: (regs[1] >> 16) as u16,
1943                receiver_id: regs[1] as u16,
1944                flags: (regs[2] as u32).try_into()?,
1945                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
1946            },
1947            FuncId::NotificationGet => Self::NotificationGet {
1948                vcpu_id: (regs[1] >> 16) as u16,
1949                endpoint_id: regs[1] as u16,
1950                flags: (regs[2] as u32).into(),
1951            },
1952            FuncId::NotificationInfoGet32 => Self::NotificationInfoGet { is_32bit: true },
1953            FuncId::NotificationInfoGet64 => Self::NotificationInfoGet { is_32bit: false },
1954            FuncId::El3IntrHandle => Self::El3IntrHandle,
1955            _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
1956        };
1957
1958        Ok(msg)
1959    }
1960
1961    fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
1962        assert!(version >= Version(1, 2));
1963
1964        let fid = FuncId::try_from(regs[0] as u32)?;
1965
1966        let msg = match fid {
1967            FuncId::Success64 => Self::Success {
1968                target_info: (regs[1] as u32).into(),
1969                args: SuccessArgs::Args64_2(regs[2..18].try_into().unwrap()),
1970            },
1971            FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
1972                src_id: (regs[1] >> 16) as u16,
1973                dst_id: regs[1] as u16,
1974                uuid: Uuid::from_u64_pair(regs[2].swap_bytes(), regs[3].swap_bytes()),
1975                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
1976            },
1977            FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
1978                src_id: (regs[1] >> 16) as u16,
1979                dst_id: regs[1] as u16,
1980                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
1981            },
1982            FuncId::ConsoleLog64 => {
1983                let char_cnt = regs[1] as u8;
1984                if char_cnt > ConsoleLogChars64::MAX_LENGTH {
1985                    return Err(Error::InvalidCharacterCount(char_cnt));
1986                }
1987
1988                Self::ConsoleLog {
1989                    chars: ConsoleLogChars::Chars64(ConsoleLogChars64 {
1990                        char_cnt,
1991                        char_lists: regs[2..18].try_into().unwrap(),
1992                    }),
1993                }
1994            }
1995            FuncId::PartitionInfoGetRegs => {
1996                // Bits[15:0]: Start index
1997                let start_index = (regs[3] & 0xffff) as u16;
1998                let info_tag = ((regs[3] >> 16) & 0xffff) as u16;
1999                Self::PartitionInfoGetRegs {
2000                    uuid: Uuid::from_u64_pair(regs[1].swap_bytes(), regs[2].swap_bytes()),
2001                    start_index,
2002                    info_tag: if start_index == 0 && info_tag != 0 {
2003                        return Err(Error::InvalidInformationTag(info_tag));
2004                    } else {
2005                        info_tag
2006                    },
2007                }
2008            }
2009            _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
2010        };
2011
2012        Ok(msg)
2013    }
2014
2015    /// Create register contents for an interface.
2016    pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
2017        assert!(self.minimum_ffa_version() <= version);
2018
2019        let reg_cnt = regs.len();
2020
2021        match reg_cnt {
2022            8 => {
2023                assert!(version <= Version(1, 1));
2024                regs.fill(0);
2025
2026                self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
2027            }
2028            18 => {
2029                assert!(version >= Version(1, 2));
2030                regs.fill(0);
2031
2032                match self {
2033                    Interface::ConsoleLog {
2034                        chars: ConsoleLogChars::Chars64(_),
2035                        ..
2036                    }
2037                    | Interface::Success {
2038                        args: SuccessArgs::Args64_2(_),
2039                        ..
2040                    }
2041                    | Interface::MsgSendDirectReq2 { .. }
2042                    | Interface::MsgSendDirectResp2 { .. }
2043                    | Interface::PartitionInfoGetRegs { .. } => {
2044                        self.pack_regs18(version, regs.try_into().unwrap());
2045                    }
2046                    _ => {
2047                        self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
2048                    }
2049                }
2050            }
2051            _ => panic!("Invalid number of registers {}", reg_cnt),
2052        }
2053    }
2054
2055    fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
2056        if let Some(function_id) = self.function_id() {
2057            a[0] = function_id as u64;
2058        }
2059
2060        match *self {
2061            Interface::Error {
2062                target_info,
2063                error_code,
2064                error_arg,
2065            } => {
2066                a[1] = u32::from(target_info).into();
2067                a[2] = (error_code as u32).into();
2068                a[3] = error_arg.into();
2069            }
2070            Interface::Success { target_info, args } => {
2071                a[1] = u32::from(target_info).into();
2072                match args {
2073                    SuccessArgs::Args32(regs) => {
2074                        a[2] = regs[0].into();
2075                        a[3] = regs[1].into();
2076                        a[4] = regs[2].into();
2077                        a[5] = regs[3].into();
2078                        a[6] = regs[4].into();
2079                        a[7] = regs[5].into();
2080                    }
2081                    SuccessArgs::Args64(regs) => {
2082                        a[2] = regs[0];
2083                        a[3] = regs[1];
2084                        a[4] = regs[2];
2085                        a[5] = regs[3];
2086                        a[6] = regs[4];
2087                        a[7] = regs[5];
2088                    }
2089                    _ => panic!("{:#x?} requires 18 registers", args),
2090                }
2091            }
2092            Interface::Interrupt {
2093                target_info,
2094                interrupt_id,
2095            } => {
2096                a[1] = u32::from(target_info).into();
2097                a[2] = interrupt_id.into();
2098            }
2099            Interface::Version { input_version } => {
2100                a[1] = u32::from(input_version).into();
2101            }
2102            Interface::VersionOut { output_version } => {
2103                a[0] = u32::from(output_version).into();
2104            }
2105            Interface::Features {
2106                feat_id,
2107                input_properties,
2108            } => {
2109                a[1] = u32::from(feat_id).into();
2110                a[2] = input_properties.into();
2111            }
2112            Interface::RxAcquire { vm_id } => {
2113                a[1] = vm_id.into();
2114            }
2115            Interface::RxRelease { vm_id } => {
2116                a[1] = vm_id.into();
2117            }
2118            Interface::RxTxMap { addr, page_cnt } => {
2119                match addr {
2120                    RxTxAddr::Addr32 { rx, tx } => {
2121                        a[1] = tx.into();
2122                        a[2] = rx.into();
2123                    }
2124                    RxTxAddr::Addr64 { rx, tx } => {
2125                        a[1] = tx;
2126                        a[2] = rx;
2127                    }
2128                }
2129                a[3] = page_cnt.into();
2130            }
2131            Interface::RxTxUnmap { id } => {
2132                a[1] = id.into();
2133            }
2134            Interface::PartitionInfoGet { uuid, flags } => {
2135                let bytes = uuid.into_bytes();
2136                a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
2137                a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
2138                a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
2139                a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
2140                a[5] = u32::from(flags).into();
2141            }
2142            Interface::MsgWait { flags } => {
2143                if version >= Version(1, 2) {
2144                    if let Some(flags) = flags {
2145                        a[2] = u32::from(flags).into();
2146                    }
2147                }
2148            }
2149            Interface::IdGet | Interface::SpmIdGet | Interface::Yield => {}
2150            Interface::Run { target_info } => {
2151                a[1] = u32::from(target_info).into();
2152            }
2153            Interface::NormalWorldResume => {}
2154            Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
2155                SecondaryEpRegisterAddr::Addr32(addr) => a[1] = addr as u64,
2156                SecondaryEpRegisterAddr::Addr64(addr) => a[1] = addr,
2157            },
2158            Interface::MsgSend2 {
2159                sender_vm_id,
2160                flags,
2161            } => {
2162                a[1] = sender_vm_id.into();
2163                a[2] = u32::from(flags).into();
2164            }
2165            Interface::MsgSendDirectReq {
2166                src_id,
2167                dst_id,
2168                args,
2169            } => {
2170                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2171                match args {
2172                    DirectMsgArgs::Args32(args) => {
2173                        a[3] = args[0].into();
2174                        a[4] = args[1].into();
2175                        a[5] = args[2].into();
2176                        a[6] = args[3].into();
2177                        a[7] = args[4].into();
2178                    }
2179                    DirectMsgArgs::Args64(args) => {
2180                        a[3] = args[0];
2181                        a[4] = args[1];
2182                        a[5] = args[2];
2183                        a[6] = args[3];
2184                        a[7] = args[4];
2185                    }
2186                    DirectMsgArgs::VersionReq { version } => {
2187                        a[2] = DirectMsgArgs::VERSION_REQ.into();
2188                        a[3] = u32::from(version).into();
2189                    }
2190                    DirectMsgArgs::PowerPsciReq32 { params } => {
2191                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2192                        a[3] = params[0].into();
2193                        a[4] = params[1].into();
2194                        a[5] = params[2].into();
2195                        a[6] = params[3].into();
2196                    }
2197                    DirectMsgArgs::PowerPsciReq64 { params } => {
2198                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2199                        a[3] = params[0];
2200                        a[4] = params[1];
2201                        a[5] = params[2];
2202                        a[6] = params[3];
2203                    }
2204                    DirectMsgArgs::PowerWarmBootReq { boot_type } => {
2205                        a[2] = DirectMsgArgs::POWER_WARM_BOOT_REQ.into();
2206                        a[3] = u32::from(boot_type).into();
2207                    }
2208                    DirectMsgArgs::VmCreated { handle, vm_id } => {
2209                        a[2] = DirectMsgArgs::VM_CREATED.into();
2210                        let handle_regs: [u32; 2] = handle.into();
2211                        a[3] = handle_regs[0].into();
2212                        a[4] = handle_regs[1].into();
2213                        a[5] = vm_id.into();
2214                    }
2215                    DirectMsgArgs::VmDestructed { handle, vm_id } => {
2216                        a[2] = DirectMsgArgs::VM_DESTRUCTED.into();
2217                        let handle_regs: [u32; 2] = handle.into();
2218                        a[3] = handle_regs[0].into();
2219                        a[4] = handle_regs[1].into();
2220                        a[5] = vm_id.into();
2221                    }
2222                    _ => panic!("Malformed MsgSendDirectReq interface"),
2223                }
2224            }
2225            Interface::MsgSendDirectResp {
2226                src_id,
2227                dst_id,
2228                args,
2229            } => {
2230                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2231                match args {
2232                    DirectMsgArgs::Args32(args) => {
2233                        a[3] = args[0].into();
2234                        a[4] = args[1].into();
2235                        a[5] = args[2].into();
2236                        a[6] = args[3].into();
2237                        a[7] = args[4].into();
2238                    }
2239                    DirectMsgArgs::Args64(args) => {
2240                        a[3] = args[0];
2241                        a[4] = args[1];
2242                        a[5] = args[2];
2243                        a[6] = args[3];
2244                        a[7] = args[4];
2245                    }
2246                    DirectMsgArgs::VersionResp { version } => {
2247                        a[2] = DirectMsgArgs::VERSION_RESP.into();
2248                        match version {
2249                            None => a[3] = (i32::from(FfaError::NotSupported) as u32).into(),
2250                            Some(ver) => a[3] = u32::from(ver).into(),
2251                        }
2252                    }
2253                    DirectMsgArgs::PowerPsciResp { psci_status } => {
2254                        a[2] = DirectMsgArgs::POWER_PSCI_RESP.into();
2255                        a[3] = (psci_status as u32).into();
2256                    }
2257                    DirectMsgArgs::VmCreatedAck { sp_status } => {
2258                        a[2] = DirectMsgArgs::VM_CREATED_ACK.into();
2259                        a[3] = (i32::from(sp_status) as u32).into();
2260                    }
2261                    DirectMsgArgs::VmDestructedAck { sp_status } => {
2262                        a[2] = DirectMsgArgs::VM_DESTRUCTED_ACK.into();
2263                        a[3] = (i32::from(sp_status) as u32).into();
2264                    }
2265                    _ => panic!("Malformed MsgSendDirectResp interface"),
2266                }
2267            }
2268            Interface::MemDonate {
2269                total_len,
2270                frag_len,
2271                buf,
2272            } => {
2273                a[1] = total_len.into();
2274                a[2] = frag_len.into();
2275                (a[3], a[4]) = match buf {
2276                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2277                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2278                    None => (0, 0),
2279                };
2280            }
2281            Interface::MemLend {
2282                total_len,
2283                frag_len,
2284                buf,
2285            } => {
2286                a[1] = total_len.into();
2287                a[2] = frag_len.into();
2288                (a[3], a[4]) = match buf {
2289                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2290                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2291                    None => (0, 0),
2292                };
2293            }
2294            Interface::MemShare {
2295                total_len,
2296                frag_len,
2297                buf,
2298            } => {
2299                a[1] = total_len.into();
2300                a[2] = frag_len.into();
2301                (a[3], a[4]) = match buf {
2302                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2303                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2304                    None => (0, 0),
2305                };
2306            }
2307            Interface::MemRetrieveReq {
2308                total_len,
2309                frag_len,
2310                buf,
2311            } => {
2312                a[1] = total_len.into();
2313                a[2] = frag_len.into();
2314                (a[3], a[4]) = match buf {
2315                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2316                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2317                    None => (0, 0),
2318                };
2319            }
2320            Interface::MemRetrieveResp {
2321                total_len,
2322                frag_len,
2323            } => {
2324                a[1] = total_len.into();
2325                a[2] = frag_len.into();
2326            }
2327            Interface::MemRelinquish => {}
2328            Interface::MemReclaim { handle, flags } => {
2329                let handle_regs: [u32; 2] = handle.into();
2330                a[1] = handle_regs[0].into();
2331                a[2] = handle_regs[1].into();
2332                a[3] = u32::from(flags).into();
2333            }
2334            Interface::MemPermGet { addr, page_cnt } => {
2335                a[1] = match addr {
2336                    MemAddr::Addr32(addr) => addr.into(),
2337                    MemAddr::Addr64(addr) => addr,
2338                };
2339                a[2] = if version <= Version(1, 2) {
2340                    assert_eq!(page_cnt, 1);
2341                    0
2342                } else {
2343                    assert_ne!(page_cnt, 0);
2344                    (page_cnt - 1).into()
2345                }
2346            }
2347            Interface::MemPermSet {
2348                addr,
2349                page_cnt,
2350                mem_perm,
2351            } => {
2352                a[1] = match addr {
2353                    MemAddr::Addr32(addr) => addr.into(),
2354                    MemAddr::Addr64(addr) => addr,
2355                };
2356                a[2] = page_cnt.into();
2357                a[3] = u32::from(mem_perm).into();
2358            }
2359            Interface::ConsoleLog { chars } => match chars {
2360                ConsoleLogChars::Chars32(ConsoleLogChars32 {
2361                    char_cnt,
2362                    char_lists,
2363                }) => {
2364                    a[1] = char_cnt.into();
2365                    a[2] = char_lists[0].into();
2366                    a[3] = char_lists[1].into();
2367                    a[4] = char_lists[2].into();
2368                    a[5] = char_lists[3].into();
2369                    a[6] = char_lists[4].into();
2370                    a[7] = char_lists[5].into();
2371                }
2372                _ => panic!("{:#x?} requires 18 registers", chars),
2373            },
2374            Interface::NotificationBitmapCreate { vm_id, vcpu_cnt } => {
2375                a[1] = vm_id.into();
2376                a[2] = vcpu_cnt.into();
2377            }
2378            Interface::NotificationBitmapDestroy { vm_id } => {
2379                a[1] = vm_id.into();
2380            }
2381            Interface::NotificationBind {
2382                sender_id,
2383                receiver_id,
2384                flags,
2385                bitmap,
2386            } => {
2387                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2388                a[2] = u32::from(flags).into();
2389                a[3] = bitmap & 0xffff_ffff;
2390                a[4] = bitmap >> 32;
2391            }
2392            Interface::NotificationUnbind {
2393                sender_id,
2394                receiver_id,
2395                bitmap,
2396            } => {
2397                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2398                a[3] = bitmap & 0xffff_ffff;
2399                a[4] = bitmap >> 32;
2400            }
2401            Interface::NotificationSet {
2402                sender_id,
2403                receiver_id,
2404                flags,
2405                bitmap,
2406            } => {
2407                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2408                a[2] = u32::from(flags).into();
2409                a[3] = bitmap & 0xffff_ffff;
2410                a[4] = bitmap >> 32;
2411            }
2412            Interface::NotificationGet {
2413                vcpu_id,
2414                endpoint_id,
2415                flags,
2416            } => {
2417                a[1] = (u64::from(vcpu_id) << 16) | u64::from(endpoint_id);
2418                a[2] = u32::from(flags).into();
2419            }
2420            Interface::NotificationInfoGet { .. } => {}
2421            Interface::El3IntrHandle => {}
2422            _ => panic!("{:#x?} requires 18 registers", self),
2423        }
2424    }
2425
2426    fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
2427        assert!(version >= Version(1, 2));
2428
2429        if let Some(function_id) = self.function_id() {
2430            a[0] = function_id as u64;
2431        }
2432
2433        match *self {
2434            Interface::Success { target_info, args } => {
2435                a[1] = u32::from(target_info).into();
2436                match args {
2437                    SuccessArgs::Args64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
2438                    _ => panic!("{:#x?} requires 8 registers", args),
2439                }
2440            }
2441            Interface::MsgSendDirectReq2 {
2442                src_id,
2443                dst_id,
2444                uuid,
2445                args,
2446            } => {
2447                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2448                let (uuid_msb, uuid_lsb) = uuid.as_u64_pair();
2449                (a[2], a[3]) = (uuid_msb.swap_bytes(), uuid_lsb.swap_bytes());
2450                a[4..18].copy_from_slice(&args.0[..14]);
2451            }
2452            Interface::MsgSendDirectResp2 {
2453                src_id,
2454                dst_id,
2455                args,
2456            } => {
2457                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2458                a[2] = 0;
2459                a[3] = 0;
2460                a[4..18].copy_from_slice(&args.0[..14]);
2461            }
2462            Interface::ConsoleLog { chars: char_lists } => match char_lists {
2463                ConsoleLogChars::Chars64(ConsoleLogChars64 {
2464                    char_cnt,
2465                    char_lists,
2466                }) => {
2467                    a[1] = char_cnt.into();
2468                    a[2..18].copy_from_slice(&char_lists[..16])
2469                }
2470                _ => panic!("{:#x?} requires 8 registers", char_lists),
2471            },
2472            Interface::PartitionInfoGetRegs {
2473                uuid,
2474                start_index,
2475                info_tag,
2476            } => {
2477                if start_index == 0 && info_tag != 0 {
2478                    panic!("Information Tag MBZ if start index is 0: {:#x?}", self);
2479                }
2480                let (uuid_msb, uuid_lsb) = uuid.as_u64_pair();
2481                (a[1], a[2]) = (uuid_msb.swap_bytes(), uuid_lsb.swap_bytes());
2482                a[3] = (u64::from(info_tag) << 16) | u64::from(start_index);
2483            }
2484            _ => panic!("{:#x?} requires 8 registers", self),
2485        }
2486    }
2487
2488    /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
2489    pub fn success32_noargs() -> Self {
2490        Self::Success {
2491            target_info: TargetInfo::default(),
2492            args: SuccessArgs::Args32([0; 6]),
2493        }
2494    }
2495
2496    /// Helper function to create an `FFA_ERROR` interface with an error code.
2497    pub fn error(error_code: FfaError) -> Self {
2498        Self::Error {
2499            target_info: TargetInfo::default(),
2500            error_code,
2501            error_arg: 0,
2502        }
2503    }
2504}
2505
2506#[cfg(test)]
2507mod tests {
2508    use super::*;
2509
2510    #[test]
2511    fn version_reg_count() {
2512        assert!(!Version(1, 1).needs_18_regs());
2513        assert!(Version(1, 2).needs_18_regs())
2514    }
2515
2516    #[test]
2517    fn part_info_get_regs() {
2518        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2519        let uuid_bytes = uuid.as_bytes();
2520        let test_info_tag = 0b1101_1101;
2521        let test_start_index = 0b1101;
2522        let start_index_and_tag = (test_info_tag << 16) | test_start_index;
2523        let version = Version(1, 2);
2524
2525        // From spec:
2526        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2527        let reg_x1 = ((uuid_bytes[7] as u64) << 56)
2528            | ((uuid_bytes[6] as u64) << 48)
2529            | ((uuid_bytes[5] as u64) << 40)
2530            | ((uuid_bytes[4] as u64) << 32)
2531            | ((uuid_bytes[3] as u64) << 24)
2532            | ((uuid_bytes[2] as u64) << 16)
2533            | ((uuid_bytes[1] as u64) << 8)
2534            | (uuid_bytes[0] as u64);
2535
2536        // From spec:
2537        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2538        let reg_x2 = ((uuid_bytes[15] as u64) << 56)
2539            | ((uuid_bytes[14] as u64) << 48)
2540            | ((uuid_bytes[13] as u64) << 40)
2541            | ((uuid_bytes[12] as u64) << 32)
2542            | ((uuid_bytes[11] as u64) << 24)
2543            | ((uuid_bytes[10] as u64) << 16)
2544            | ((uuid_bytes[9] as u64) << 8)
2545            | (uuid_bytes[8] as u64);
2546
2547        // First, test for wrong tag:
2548        {
2549            let mut regs = [0u64; 18];
2550            regs[0] = FuncId::PartitionInfoGetRegs as u64;
2551            regs[1] = reg_x1;
2552            regs[2] = reg_x2;
2553            regs[3] = test_info_tag << 16;
2554
2555            assert!(Interface::from_regs(version, &regs).is_err_and(
2556                |e| e == Error::InvalidInformationTag(test_info_tag.try_into().unwrap())
2557            ));
2558        }
2559
2560        // Test for regs -> Interface -> regs
2561        {
2562            let mut orig_regs = [0u64; 18];
2563            orig_regs[0] = FuncId::PartitionInfoGetRegs as u64;
2564            orig_regs[1] = reg_x1;
2565            orig_regs[2] = reg_x2;
2566            orig_regs[3] = start_index_and_tag;
2567
2568            let mut test_regs = orig_regs;
2569            let interface = Interface::from_regs(version, &test_regs).unwrap();
2570            match &interface {
2571                Interface::PartitionInfoGetRegs {
2572                    info_tag,
2573                    start_index,
2574                    uuid: int_uuid,
2575                } => {
2576                    assert_eq!(u64::from(*info_tag), test_info_tag);
2577                    assert_eq!(u64::from(*start_index), test_start_index);
2578                    assert_eq!(*int_uuid, uuid);
2579                }
2580                _ => panic!("Expecting Interface::PartitionInfoGetRegs!"),
2581            }
2582            test_regs.fill(0);
2583            interface.to_regs(version, &mut test_regs);
2584            assert_eq!(orig_regs, test_regs);
2585        }
2586
2587        // Test for Interface -> regs -> Interface
2588        {
2589            let interface = Interface::PartitionInfoGetRegs {
2590                info_tag: test_info_tag.try_into().unwrap(),
2591                start_index: test_start_index.try_into().unwrap(),
2592                uuid,
2593            };
2594
2595            let mut regs: [u64; 18] = [0; 18];
2596            interface.to_regs(version, &mut regs);
2597
2598            assert_eq!(Some(FuncId::PartitionInfoGetRegs), interface.function_id());
2599            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2600            assert_eq!(regs[1], reg_x1);
2601            assert_eq!(regs[2], reg_x2);
2602            assert_eq!(regs[3], (test_info_tag << 16) | test_start_index);
2603
2604            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2605        }
2606    }
2607
2608    #[test]
2609    fn msg_send_direct_req2() {
2610        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2611        let uuid_bytes = uuid.as_bytes();
2612
2613        // From spec:
2614        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2615        let reg_x2 = ((uuid_bytes[7] as u64) << 56)
2616            | ((uuid_bytes[6] as u64) << 48)
2617            | ((uuid_bytes[5] as u64) << 40)
2618            | ((uuid_bytes[4] as u64) << 32)
2619            | ((uuid_bytes[3] as u64) << 24)
2620            | ((uuid_bytes[2] as u64) << 16)
2621            | ((uuid_bytes[1] as u64) << 8)
2622            | (uuid_bytes[0] as u64);
2623
2624        // From spec:
2625        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2626        let reg_x3 = ((uuid_bytes[15] as u64) << 56)
2627            | ((uuid_bytes[14] as u64) << 48)
2628            | ((uuid_bytes[13] as u64) << 40)
2629            | ((uuid_bytes[12] as u64) << 32)
2630            | ((uuid_bytes[11] as u64) << 24)
2631            | ((uuid_bytes[10] as u64) << 16)
2632            | ((uuid_bytes[9] as u64) << 8)
2633            | (uuid_bytes[8] as u64);
2634
2635        let test_sender = 0b1101_1101;
2636        let test_receiver = 0b1101;
2637        let test_sender_receiver = (test_sender << 16) | test_receiver;
2638        let version = Version(1, 2);
2639
2640        // Test for regs -> Interface -> regs
2641        {
2642            let mut orig_regs = [0u64; 18];
2643            orig_regs[0] = FuncId::MsgSendDirectReq64_2 as u64;
2644            orig_regs[1] = test_sender_receiver;
2645            orig_regs[2] = reg_x2;
2646            orig_regs[3] = reg_x3;
2647
2648            let mut test_regs = orig_regs;
2649            let interface = Interface::from_regs(version, &test_regs).unwrap();
2650            match &interface {
2651                Interface::MsgSendDirectReq2 {
2652                    dst_id,
2653                    src_id,
2654                    args: _,
2655                    uuid: int_uuid,
2656                } => {
2657                    assert_eq!(u64::from(*src_id), test_sender);
2658                    assert_eq!(u64::from(*dst_id), test_receiver);
2659                    assert_eq!(*int_uuid, uuid);
2660                }
2661                _ => panic!("Expecting Interface::MsgSendDirectReq2!"),
2662            }
2663            test_regs.fill(0);
2664            interface.to_regs(version, &mut test_regs);
2665            assert_eq!(orig_regs, test_regs);
2666        }
2667
2668        // Test for Interface -> regs -> Interface
2669        {
2670            let rest_of_regs: [u64; 14] = [0; 14];
2671
2672            let interface = Interface::MsgSendDirectReq2 {
2673                src_id: test_sender.try_into().unwrap(),
2674                dst_id: test_receiver.try_into().unwrap(),
2675                uuid,
2676                args: DirectMsg2Args(rest_of_regs),
2677            };
2678
2679            let mut regs: [u64; 18] = [0; 18];
2680            interface.to_regs(version, &mut regs);
2681
2682            assert_eq!(Some(FuncId::MsgSendDirectReq64_2), interface.function_id());
2683            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2684            assert_eq!(regs[1], test_sender_receiver);
2685            assert_eq!(regs[2], reg_x2);
2686            assert_eq!(regs[3], reg_x3);
2687            assert_eq!(regs[4], 0);
2688
2689            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2690        }
2691    }
2692
2693    #[test]
2694    fn is_32bit() {
2695        let interface_64 = Interface::MsgSendDirectReq {
2696            src_id: 0,
2697            dst_id: 1,
2698            args: DirectMsgArgs::Args64([0, 0, 0, 0, 0]),
2699        };
2700        assert!(!interface_64.is_32bit());
2701
2702        let interface_32 = Interface::MsgSendDirectReq {
2703            src_id: 0,
2704            dst_id: 1,
2705            args: DirectMsgArgs::Args32([0, 0, 0, 0, 0]),
2706        };
2707        assert!(interface_32.is_32bit());
2708    }
2709
2710    #[test]
2711    fn success_args_notification_info_get32() {
2712        let mut notifications = SuccessArgsNotificationInfoGet32::default();
2713
2714        // 16.7.1.1 Example usage
2715        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2716        notifications.add_list(0x0000, &[4, 6]).unwrap();
2717        notifications.add_list(0x0002, &[]).unwrap();
2718        notifications.add_list(0x0003, &[1]).unwrap();
2719
2720        let args: SuccessArgs = notifications.into();
2721        assert_eq!(
2722            SuccessArgs::Args32([
2723                0x0004_b200,
2724                0x0000_0000,
2725                0x0003_0002,
2726                0x0004_0000,
2727                0x0002_0006,
2728                0x0001_0003
2729            ]),
2730            args
2731        );
2732
2733        let notifications = SuccessArgsNotificationInfoGet32::try_from(args).unwrap();
2734        let mut iter = notifications.iter();
2735        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2736        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2737        assert_eq!(Some((0x0002, &[][..])), iter.next());
2738        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2739    }
2740
2741    #[test]
2742    fn success_args_notification_info_get64() {
2743        let mut notifications = SuccessArgsNotificationInfoGet64::default();
2744
2745        // 16.7.1.1 Example usage
2746        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2747        notifications.add_list(0x0000, &[4, 6]).unwrap();
2748        notifications.add_list(0x0002, &[]).unwrap();
2749        notifications.add_list(0x0003, &[1]).unwrap();
2750
2751        let args: SuccessArgs = notifications.into();
2752        assert_eq!(
2753            SuccessArgs::Args64([
2754                0x0004_b200,
2755                0x0003_0002_0000_0000,
2756                0x0002_0006_0004_0000,
2757                0x0000_0000_0001_0003,
2758                0x0000_0000_0000_0000,
2759                0x0000_0000_0000_0000,
2760            ]),
2761            args
2762        );
2763
2764        let notifications = SuccessArgsNotificationInfoGet64::try_from(args).unwrap();
2765        let mut iter = notifications.iter();
2766        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2767        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2768        assert_eq!(Some((0x0002, &[][..])), iter.next());
2769        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2770    }
2771
2772    #[test]
2773    fn mem_perm_get_pack() {
2774        let mut expected_regs = [0u64; 18];
2775        let mut out_regs = [0u64; 18];
2776
2777        expected_regs[0] = u32::from(FuncId::MemPermGet32).into();
2778        expected_regs[1] = 0xabcd;
2779        expected_regs[2] = 5;
2780
2781        Interface::MemPermGet {
2782            addr: MemAddr::Addr32(0xabcd),
2783            page_cnt: 6,
2784        }
2785        .to_regs(Version(1, 3), &mut out_regs);
2786
2787        assert_eq!(expected_regs, out_regs);
2788
2789        expected_regs[2] = 0;
2790
2791        Interface::MemPermGet {
2792            addr: MemAddr::Addr32(0xabcd),
2793            page_cnt: 1,
2794        }
2795        .to_regs(Version(1, 2), &mut out_regs);
2796
2797        assert_eq!(expected_regs, out_regs);
2798    }
2799
2800    #[test]
2801    #[should_panic]
2802    fn mem_perm_get_pack_fail1() {
2803        let mut out_regs = [0u64; 18];
2804        Interface::MemPermGet {
2805            addr: MemAddr::Addr32(0xabcd),
2806            page_cnt: 2,
2807        }
2808        .to_regs(Version(1, 2), &mut out_regs);
2809    }
2810
2811    #[test]
2812    #[should_panic]
2813    fn mem_perm_get_pack_fail2() {
2814        let mut out_regs = [0u64; 18];
2815        Interface::MemPermGet {
2816            addr: MemAddr::Addr32(0xabcd),
2817            page_cnt: 0,
2818        }
2819        .to_regs(Version(1, 3), &mut out_regs);
2820    }
2821
2822    #[test]
2823    fn mem_perm_get_unpack() {
2824        let mut in_regs = [0u64; 18];
2825
2826        in_regs[0] = u32::from(FuncId::MemPermGet32).into();
2827        in_regs[1] = 0xabcd;
2828        in_regs[2] = 5;
2829
2830        assert_eq!(
2831            Interface::from_regs(Version(1, 3), &in_regs),
2832            Ok(Interface::MemPermGet {
2833                addr: MemAddr::Addr32(0xabcd),
2834                page_cnt: 6,
2835            }),
2836        );
2837
2838        assert_eq!(
2839            Interface::from_regs(Version(1, 2), &in_regs),
2840            Err(Error::MemoryManagementError(
2841                memory_management::Error::InvalidPageCount
2842            )),
2843        );
2844
2845        in_regs[2] = 0;
2846
2847        assert_eq!(
2848            Interface::from_regs(Version(1, 2), &in_regs),
2849            Ok(Interface::MemPermGet {
2850                addr: MemAddr::Addr32(0xabcd),
2851                page_cnt: 1,
2852            }),
2853        );
2854
2855        in_regs[2] = u32::MAX.into();
2856
2857        assert_eq!(
2858            Interface::from_regs(Version(1, 3), &in_regs),
2859            Err(Error::MemoryManagementError(
2860                memory_management::Error::InvalidPageCount
2861            )),
2862        );
2863    }
2864}