arm_ffa/
lib.rs

1// SPDX-FileCopyrightText: Copyright The arm-ffa Contributors.
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, Eq, Clone, Copy)]
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    MemOpPause = 0x84000078,
167    MemOpResume = 0x84000079,
168    MemFragRx = 0x8400007a,
169    MemFragTx = 0x8400007b,
170}
171
172impl FuncId {
173    /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
174    pub fn is_32bit(&self) -> bool {
175        u32::from(*self) & (1 << 30) == 0
176    }
177
178    /// Returns the FF-A version that has introduced the function ID.
179    pub fn minimum_ffa_version(&self) -> Version {
180        match self {
181            FuncId::Error
182            | FuncId::Success32
183            | FuncId::Success64
184            | FuncId::Interrupt
185            | FuncId::Version
186            | FuncId::Features
187            | FuncId::RxRelease
188            | FuncId::RxTxMap32
189            | FuncId::RxTxMap64
190            | FuncId::RxTxUnmap
191            | FuncId::PartitionInfoGet
192            | FuncId::IdGet
193            | FuncId::MsgWait
194            | FuncId::Yield
195            | FuncId::Run
196            | FuncId::NormalWorldResume
197            | FuncId::MsgSendDirectReq32
198            | FuncId::MsgSendDirectReq64
199            | FuncId::MsgSendDirectResp32
200            | FuncId::MsgSendDirectResp64
201            | FuncId::MemDonate32
202            | FuncId::MemDonate64
203            | FuncId::MemLend32
204            | FuncId::MemLend64
205            | FuncId::MemShare32
206            | FuncId::MemShare64
207            | FuncId::MemRetrieveReq32
208            | FuncId::MemRetrieveReq64
209            | FuncId::MemRetrieveResp
210            | FuncId::MemRelinquish
211            | FuncId::MemReclaim
212            | FuncId::MemOpPause
213            | FuncId::MemOpResume
214            | FuncId::MemFragRx
215            | FuncId::MemFragTx => Version(1, 0),
216
217            FuncId::RxAcquire
218            | FuncId::SpmIdGet
219            | FuncId::MsgSend2
220            | FuncId::MemPermGet32
221            | FuncId::MemPermGet64
222            | FuncId::MemPermSet32
223            | FuncId::MemPermSet64
224            | FuncId::NotificationBitmapCreate
225            | FuncId::NotificationBitmapDestroy
226            | FuncId::NotificationBind
227            | FuncId::NotificationUnbind
228            | FuncId::NotificationSet
229            | FuncId::NotificationGet
230            | FuncId::NotificationInfoGet32
231            | FuncId::NotificationInfoGet64
232            | FuncId::SecondaryEpRegister32
233            | FuncId::SecondaryEpRegister64 => Version(1, 1),
234
235            FuncId::PartitionInfoGetRegs
236            | FuncId::ConsoleLog32
237            | FuncId::ConsoleLog64
238            | FuncId::MsgSendDirectReq64_2
239            | FuncId::MsgSendDirectResp64_2
240            | FuncId::El3IntrHandle => Version(1, 2),
241        }
242    }
243}
244
245/// Error status codes used by the `FFA_ERROR` interface.
246#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
247#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
248#[repr(i32)]
249pub enum FfaError {
250    #[error("Not supported")]
251    NotSupported = -1,
252    #[error("Invalid parameters")]
253    InvalidParameters = -2,
254    #[error("No memory")]
255    NoMemory = -3,
256    #[error("Busy")]
257    Busy = -4,
258    #[error("Interrupted")]
259    Interrupted = -5,
260    #[error("Denied")]
261    Denied = -6,
262    #[error("Retry")]
263    Retry = -7,
264    #[error("Aborted")]
265    Aborted = -8,
266    #[error("No data")]
267    NoData = -9,
268}
269
270/// Collection of helper functions for converting between `Uuid` type and its representations in
271/// various FF-A containers.
272pub struct UuidHelper;
273
274impl UuidHelper {
275    /// Converts byte array into `Uuid`.
276    /// Example:
277    /// * Input `[a1, a2, a3, a4, b1, b2, c1, c2, d1, d2, d3, d4, d5, d6, d7, d8]`
278    /// * Output: `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`
279    pub fn from_bytes(value: [u8; 16]) -> Uuid {
280        Uuid::from_bytes(value)
281    }
282
283    /// Converts `Uuid` into byte array.
284    /// Example:
285    /// * Input: `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`
286    /// * Output `[a1, a2, a3, a4, b1, b2, c1, c2, d1, d2, d3, d4, d5, d6, d7, d8]`
287    pub fn to_bytes(value: Uuid) -> [u8; 16] {
288        value.into_bytes()
289    }
290
291    /// Creates `Uuid` from four 32 bit register values.
292    /// Example:
293    /// * Input `[a4a3a2a1, c2c1b2b1, d4d3d2d1, d8d7d6d5]`
294    /// * Output: `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`
295    pub fn from_u32_regs(value: [u32; 4]) -> Uuid {
296        Uuid::from_u128_le(
297            value[0] as u128
298                | (value[1] as u128) << 32
299                | (value[2] as u128) << 64
300                | (value[3] as u128) << 96,
301        )
302    }
303
304    /// Converts `Uuid` into four 32 bit register values.
305    /// Example:
306    /// * Input: `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`
307    /// * Output `[a4a3a2a1, c2c1b2b1, d4d3d2d1, d8d7d6d5]`
308    pub fn to_u32_regs(value: Uuid) -> [u32; 4] {
309        let bits = value.to_u128_le();
310
311        [
312            bits as u32,
313            (bits >> 32) as u32,
314            (bits >> 64) as u32,
315            (bits >> 96) as u32,
316        ]
317    }
318
319    /// Creates `Uuid` from a 64 bit register pair.
320    /// Example:
321    /// * Input `[c2c1b2b1a4a3a2a1, d8d7d6d5d4d3d2d1]`
322    /// * Output: `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`
323    pub fn from_u64_regs(value: [u64; 2]) -> Uuid {
324        Uuid::from_u128_le(value[0] as u128 | (value[1] as u128) << 64)
325    }
326
327    /// Converts `Uuid` into a 64 bit register pair.
328    /// Example:
329    /// * Input `[c2c1b2b1a4a3a2a1, d8d7d6d5d4d3d2d1]`
330    /// * Output: `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`
331    pub fn to_u64_regs(value: Uuid) -> [u64; 2] {
332        let bits = value.to_u128_le();
333        [bits as u64, (bits >> 64) as u64]
334    }
335}
336
337/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
338#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
339pub struct TargetInfo {
340    pub endpoint_id: u16,
341    pub vcpu_id: u16,
342}
343
344impl From<u32> for TargetInfo {
345    fn from(value: u32) -> Self {
346        Self {
347            endpoint_id: (value >> 16) as u16,
348            vcpu_id: value as u16,
349        }
350    }
351}
352
353impl From<TargetInfo> for u32 {
354    fn from(value: TargetInfo) -> Self {
355        ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
356    }
357}
358
359/// Generic arguments of the `FFA_SUCCESS` interface. The interpretation of the arguments depends on
360/// the interface that initiated the request. The application code has knowledge of the request, so
361/// it has to convert `SuccessArgs` into/from a specific success args structure that matches the
362/// request.
363///
364/// The current specialized success arguments types are:
365/// * `FFA_FEATURES` - [`SuccessArgsFeatures`]
366/// * `FFA_ID_GET` - [`SuccessArgsIdGet`]
367/// * `FFA_SPM_ID_GET` - [`SuccessArgsSpmIdGet`]
368/// * `FFA_PARTITION_INFO_GET` - [`partition_info::SuccessArgsPartitionInfoGet`]
369/// * `FFA_PARTITION_INFO_GET_REGS` - [`partition_info::SuccessArgsPartitionInfoGetRegs`]
370/// * `FFA_NOTIFICATION_GET` - [`SuccessArgsNotificationGet`]
371/// * `FFA_NOTIFICATION_INFO_GET_32` - [`SuccessArgsNotificationInfoGet32`]
372/// * `FFA_NOTIFICATION_INFO_GET_64` - [`SuccessArgsNotificationInfoGet64`]
373#[derive(Debug, Eq, PartialEq, Clone, Copy)]
374pub enum SuccessArgs {
375    Args32([u32; 6]),
376    Args64([u64; 6]),
377    Args64_2([u64; 16]),
378}
379
380impl SuccessArgs {
381    fn try_get_args32(self) -> Result<[u32; 6], Error> {
382        match self {
383            SuccessArgs::Args32(args) => Ok(args),
384            SuccessArgs::Args64(_) | SuccessArgs::Args64_2(_) => {
385                Err(Error::InvalidSuccessArgsVariant)
386            }
387        }
388    }
389
390    fn try_get_args64(self) -> Result<[u64; 6], Error> {
391        match self {
392            SuccessArgs::Args64(args) => Ok(args),
393            SuccessArgs::Args32(_) | SuccessArgs::Args64_2(_) => {
394                Err(Error::InvalidSuccessArgsVariant)
395            }
396        }
397    }
398
399    fn try_get_args64_2(self) -> Result<[u64; 16], Error> {
400        match self {
401            SuccessArgs::Args64_2(args) => Ok(args),
402            SuccessArgs::Args32(_) | SuccessArgs::Args64(_) => {
403                Err(Error::InvalidSuccessArgsVariant)
404            }
405        }
406    }
407}
408
409/// Entrypoint address argument for `FFA_SECONDARY_EP_REGISTER` interface.
410#[derive(Debug, Eq, PartialEq, Clone, Copy)]
411pub enum SecondaryEpRegisterAddr {
412    Addr32(u32),
413    Addr64(u64),
414}
415
416/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
417#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
418pub struct Version(pub u16, pub u16);
419
420impl Version {
421    // The FF-A spec mandates that bit[31] of a version number must be 0
422    const MBZ_BITS: u32 = 1 << 31;
423
424    /// Returns whether the caller's version (self) is compatible with the callee's version (input
425    /// parameter)
426    pub fn is_compatible_to(&self, callee_version: &Version) -> bool {
427        self.0 == callee_version.0 && self.1 <= callee_version.1
428    }
429
430    /// Returns true if the specified FF-A version uses 18 registers for calls, false if it uses 8.
431    pub fn needs_18_regs(&self) -> bool {
432        *self >= Version(1, 2)
433    }
434}
435
436impl TryFrom<u32> for Version {
437    type Error = Error;
438
439    fn try_from(val: u32) -> Result<Self, Self::Error> {
440        if (val & Self::MBZ_BITS) != 0 {
441            Err(Error::InvalidVersion(val))
442        } else {
443            Ok(Self((val >> 16) as u16, val as u16))
444        }
445    }
446}
447
448impl From<Version> for u32 {
449    fn from(v: Version) -> Self {
450        let v_u32 = ((v.0 as u32) << 16) | v.1 as u32;
451        assert!(v_u32 & Version::MBZ_BITS == 0);
452        v_u32
453    }
454}
455
456impl Display for Version {
457    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
458        write!(f, "{}.{}", self.0, self.1)
459    }
460}
461
462impl Debug for Version {
463    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
464        Display::fmt(self, f)
465    }
466}
467
468/// Enum for storing the response of an FFA_VERSION request. It can either contain a `Version` or
469/// a `NOT_SUPPORTED` error code.
470#[derive(Debug, Eq, PartialEq, Clone, Copy)]
471pub enum VersionOut {
472    Version(Version),
473    NotSupported,
474}
475
476impl TryFrom<u32> for VersionOut {
477    type Error = Error;
478
479    fn try_from(value: u32) -> Result<Self, Self::Error> {
480        if value == i32::from(FfaError::NotSupported) as u32 {
481            Ok(Self::NotSupported)
482        } else {
483            Ok(Self::Version(Version::try_from(value)?))
484        }
485    }
486}
487
488impl From<VersionOut> for u32 {
489    fn from(value: VersionOut) -> Self {
490        match value {
491            VersionOut::Version(version) => version.into(),
492            VersionOut::NotSupported => i32::from(FfaError::NotSupported) as u32,
493        }
494    }
495}
496
497/// Feature IDs used by the `FFA_FEATURES` interface.
498#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
499#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
500#[repr(u8)]
501pub enum FeatureId {
502    NotificationPendingInterrupt = 0x1,
503    ScheduleReceiverInterrupt = 0x2,
504    ManagedExitInterrupt = 0x3,
505}
506
507/// Arguments for the `FFA_FEATURES` interface.
508#[derive(Debug, Eq, PartialEq, Clone, Copy)]
509pub enum Feature {
510    FuncId(FuncId),
511    FeatureId(FeatureId),
512    Unknown(u32),
513}
514
515impl From<u32> for Feature {
516    fn from(value: u32) -> Self {
517        // Bit[31] is set for all valid FF-A function IDs so we don't have to check it separately
518        if let Ok(func_id) = value.try_into() {
519            Self::FuncId(func_id)
520        } else if let Ok(feat_id) = (value as u8).try_into() {
521            Self::FeatureId(feat_id)
522        } else {
523            Self::Unknown(value)
524        }
525    }
526}
527
528impl From<Feature> for u32 {
529    fn from(value: Feature) -> Self {
530        match value {
531            Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
532            Feature::FeatureId(feature_id) => feature_id as u32,
533            Feature::Unknown(id) => id,
534        }
535    }
536}
537
538/// `FFA_FEATURES` specific success argument structure. This type needs further specialization based
539/// on 'FF-A function ID or Feature ID' field of the preceeding `FFA_FEATURES` request.
540#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
541pub struct SuccessArgsFeatures {
542    pub properties: [u32; 2],
543}
544
545impl From<SuccessArgsFeatures> for SuccessArgs {
546    fn from(value: SuccessArgsFeatures) -> Self {
547        Self::Args32([value.properties[0], value.properties[1], 0, 0, 0, 0])
548    }
549}
550
551impl TryFrom<SuccessArgs> for SuccessArgsFeatures {
552    type Error = Error;
553
554    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
555        let args = value.try_get_args32()?;
556
557        Ok(Self {
558            properties: [args[0], args[1]],
559        })
560    }
561}
562
563/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
564#[derive(Debug, Eq, PartialEq, Clone, Copy)]
565pub enum RxTxAddr {
566    Addr32 { rx: u32, tx: u32 },
567    Addr64 { rx: u64, tx: u64 },
568}
569
570/// `FFA_ID_GET` specific success argument structure.
571#[derive(Debug, Eq, PartialEq, Clone, Copy)]
572pub struct SuccessArgsIdGet {
573    pub id: u16,
574}
575
576impl From<SuccessArgsIdGet> for SuccessArgs {
577    fn from(value: SuccessArgsIdGet) -> Self {
578        SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
579    }
580}
581
582impl TryFrom<SuccessArgs> for SuccessArgsIdGet {
583    type Error = Error;
584
585    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
586        let args = value.try_get_args32()?;
587        Ok(Self { id: args[0] as u16 })
588    }
589}
590
591/// `FFA_SPM_ID_GET` specific success argument structure.
592#[derive(Debug, Eq, PartialEq, Clone, Copy)]
593pub struct SuccessArgsSpmIdGet {
594    pub id: u16,
595}
596
597impl From<SuccessArgsSpmIdGet> for SuccessArgs {
598    fn from(value: SuccessArgsSpmIdGet) -> Self {
599        SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
600    }
601}
602
603impl TryFrom<SuccessArgs> for SuccessArgsSpmIdGet {
604    type Error = Error;
605
606    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
607        let args = value.try_get_args32()?;
608        Ok(Self { id: args[0] as u16 })
609    }
610}
611
612/// Flags of the `FFA_PARTITION_INFO_GET` interface.
613#[derive(Debug, Eq, PartialEq, Clone, Copy)]
614pub struct PartitionInfoGetFlags {
615    pub count_only: bool,
616}
617
618impl PartitionInfoGetFlags {
619    const RETURN_INFORMATION_TYPE_FLAG: u32 = 1 << 0;
620    const MBZ_BITS: u32 = 0xffff_fffe;
621}
622
623impl TryFrom<u32> for PartitionInfoGetFlags {
624    type Error = Error;
625
626    fn try_from(val: u32) -> Result<Self, Self::Error> {
627        if (val & Self::MBZ_BITS) != 0 {
628            Err(Error::InvalidPartitionInfoGetFlag(val))
629        } else {
630            Ok(Self {
631                count_only: val & Self::RETURN_INFORMATION_TYPE_FLAG != 0,
632            })
633        }
634    }
635}
636
637impl From<PartitionInfoGetFlags> for u32 {
638    fn from(flags: PartitionInfoGetFlags) -> Self {
639        let mut bits: u32 = 0;
640        if flags.count_only {
641            bits |= PartitionInfoGetFlags::RETURN_INFORMATION_TYPE_FLAG;
642        }
643        bits
644    }
645}
646
647/// Flags field of the `FFA_MSG_SEND2` interface.
648#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
649pub struct MsgSend2Flags {
650    pub delay_schedule_receiver: bool,
651}
652
653impl MsgSend2Flags {
654    const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
655    const MBZ_BITS: u32 = 0xffff_fffd;
656}
657
658impl TryFrom<u32> for MsgSend2Flags {
659    type Error = Error;
660
661    fn try_from(val: u32) -> Result<Self, Self::Error> {
662        if (val & Self::MBZ_BITS) != 0 {
663            Err(Error::InvalidMsgSend2Flag(val))
664        } else {
665            Ok(MsgSend2Flags {
666                delay_schedule_receiver: val & Self::DELAY_SCHEDULE_RECEIVER != 0,
667            })
668        }
669    }
670}
671
672impl From<MsgSend2Flags> for u32 {
673    fn from(flags: MsgSend2Flags) -> Self {
674        let mut bits: u32 = 0;
675        if flags.delay_schedule_receiver {
676            bits |= MsgSend2Flags::DELAY_SCHEDULE_RECEIVER;
677        }
678        bits
679    }
680}
681
682/// Composite type for capturing success and error return codes for the VM availability messages.
683///
684/// Error codes are handled by the `FfaError` type. Having a separate type for errors helps using
685/// `Result<(), FfaError>`. If a single type would include both success and error values,
686/// then `Err(FfaError::Success)` would be incomprehensible.
687#[derive(Debug, Eq, PartialEq, Clone, Copy)]
688pub enum VmAvailabilityStatus {
689    Success,
690    Error(FfaError),
691}
692
693impl TryFrom<i32> for VmAvailabilityStatus {
694    type Error = Error;
695    fn try_from(value: i32) -> Result<Self, <Self as TryFrom<i32>>::Error> {
696        Ok(match value {
697            0 => Self::Success,
698            error_code => Self::Error(FfaError::try_from(error_code)?),
699        })
700    }
701}
702
703impl From<VmAvailabilityStatus> for i32 {
704    fn from(value: VmAvailabilityStatus) -> Self {
705        match value {
706            VmAvailabilityStatus::Success => 0,
707            VmAvailabilityStatus::Error(error_code) => error_code.into(),
708        }
709    }
710}
711
712/// Arguments for the Power Warm Boot `FFA_MSG_SEND_DIRECT_REQ` interface.
713#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
714#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedWarmBootType))]
715#[repr(u32)]
716pub enum WarmBootType {
717    ExitFromSuspend = 0,
718    ExitFromLowPower = 1,
719}
720
721/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
722#[derive(Debug, Eq, PartialEq, Clone, Copy)]
723pub enum DirectMsgArgs {
724    Args32([u32; 5]),
725    Args64([u64; 5]),
726    /// Message for forwarding FFA_VERSION call from Normal world to the SPMC
727    VersionReq {
728        version: Version,
729    },
730    /// Response message to forwarded FFA_VERSION call from the Normal world
731    /// Contains the version returned by the SPMC or None
732    VersionResp {
733        version: Option<Version>,
734    },
735    /// Message for a power management operation initiated by a PSCI function
736    PowerPsciReq32 {
737        // params[i]: Input parameter in w[i] in PSCI function invocation at EL3.
738        // params[0]: Function ID.
739        params: [u32; 4],
740    },
741    /// Message for a power management operation initiated by a PSCI function
742    PowerPsciReq64 {
743        // params[i]: Input parameter in x[i] in PSCI function invocation at EL3.
744        // params[0]: Function ID.
745        params: [u64; 4],
746    },
747    /// Message for a warm boot
748    PowerWarmBootReq {
749        boot_type: WarmBootType,
750    },
751    /// Response message to indicate return status of the last power management request message
752    /// Return error code SUCCESS or DENIED as defined in PSCI spec. Caller is left to do the
753    /// parsing of the return status.
754    PowerPsciResp {
755        psci_status: i32,
756    },
757    /// Message to signal creation of a VM
758    VmCreated {
759        // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
760        // information associated with the created VM.
761        // The invalid memory region handle must be specified by the Hypervisor if this field is not
762        //  used.
763        handle: memory_management::Handle,
764        vm_id: u16,
765    },
766    /// Message to acknowledge creation of a VM
767    VmCreatedAck {
768        sp_status: VmAvailabilityStatus,
769    },
770    /// Message to signal destruction of a VM
771    VmDestructed {
772        // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
773        // information associated with the created VM.
774        // The invalid memory region handle must be specified by the Hypervisor if this field is not
775        //  used.
776        handle: memory_management::Handle,
777        vm_id: u16,
778    },
779    /// Message to acknowledge destruction of a VM
780    VmDestructedAck {
781        sp_status: VmAvailabilityStatus,
782    },
783}
784
785impl DirectMsgArgs {
786    // Flags for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
787
788    const FWK_MSG_BITS: u32 = 1 << 31;
789    const VERSION_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1000;
790    const VERSION_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1001;
791    const POWER_PSCI_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS;
792    const POWER_WARM_BOOT_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0001;
793    const POWER_PSCI_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0010;
794    const VM_CREATED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0100;
795    const VM_CREATED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0101;
796    const VM_DESTRUCTED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0110;
797    const VM_DESTRUCTED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0111;
798}
799
800/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
801#[derive(Debug, Eq, PartialEq, Clone, Copy)]
802pub struct DirectMsg2Args(pub [u64; 14]);
803
804/// Flags field of the `FFA_MSG_WAIT` interface.
805#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
806pub struct MsgWaitFlags {
807    pub retain_rx_buffer: bool,
808}
809
810impl MsgWaitFlags {
811    const RETAIN_RX_BUFFER: u32 = 0x01;
812    const MBZ_BITS: u32 = 0xfffe;
813}
814
815impl TryFrom<u32> for MsgWaitFlags {
816    type Error = Error;
817
818    fn try_from(val: u32) -> Result<Self, Self::Error> {
819        if (val & Self::MBZ_BITS) != 0 {
820            Err(Error::InvalidMsgWaitFlag(val))
821        } else {
822            Ok(MsgWaitFlags {
823                retain_rx_buffer: val & Self::RETAIN_RX_BUFFER != 0,
824            })
825        }
826    }
827}
828
829impl From<MsgWaitFlags> for u32 {
830    fn from(flags: MsgWaitFlags) -> Self {
831        let mut bits: u32 = 0;
832        if flags.retain_rx_buffer {
833            bits |= MsgWaitFlags::RETAIN_RX_BUFFER;
834        }
835        bits
836    }
837}
838
839/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
840/// descriptor.
841///
842/// Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX buffer is not
843/// used to transmit the transaction descriptor.
844#[derive(Debug, Eq, PartialEq, Clone, Copy)]
845pub enum MemOpBuf {
846    Buf32 { addr: u32, page_cnt: u32 },
847    Buf64 { addr: u64, page_cnt: u32 },
848}
849
850/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
851#[derive(Debug, Eq, PartialEq, Clone, Copy)]
852pub enum MemAddr {
853    Addr32(u32),
854    Addr64(u64),
855}
856
857impl MemAddr {
858    /// Returns the contained address.
859    pub fn address(&self) -> u64 {
860        match self {
861            MemAddr::Addr32(a) => (*a).into(),
862            MemAddr::Addr64(a) => *a,
863        }
864    }
865}
866
867/// Argument for the `FFA_CONSOLE_LOG` interface.
868#[derive(Debug, Eq, PartialEq, Clone, Copy)]
869pub enum ConsoleLogChars {
870    Chars32(ConsoleLogChars32),
871    Chars64(ConsoleLogChars64),
872}
873
874/// Generic type for storing `FFA_CONSOLE_LOG` character payload and its length in bytes.
875#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
876pub struct LogChars<T>
877where
878    T: IntoBytes + FromBytes + Immutable,
879{
880    char_cnt: u8,
881    char_lists: T,
882}
883
884impl<T> LogChars<T>
885where
886    T: IntoBytes + FromBytes + Immutable,
887{
888    const MAX_LENGTH: u8 = core::mem::size_of::<T>() as u8;
889
890    /// Returns true if there are no characters in the structure.
891    pub fn empty(&self) -> bool {
892        self.char_cnt == 0
893    }
894
895    /// Returns true if the structure is full.
896    pub fn full(&self) -> bool {
897        self.char_cnt as usize >= core::mem::size_of::<T>()
898    }
899
900    /// Returns the payload bytes.
901    pub fn bytes(&self) -> &[u8] {
902        &self.char_lists.as_bytes()[..self.char_cnt as usize]
903    }
904
905    /// Append byte slice to the end of the characters.
906    pub fn push(&mut self, source: &[u8]) -> usize {
907        let empty_area = &mut self.char_lists.as_mut_bytes()[self.char_cnt.into()..];
908        let len = empty_area.len().min(source.len());
909
910        empty_area[..len].copy_from_slice(&source[..len]);
911        self.char_cnt += len as u8;
912
913        len
914    }
915}
916
917/// Specialized type for 32-bit `FFA_CONSOLE_LOG` payload.
918pub type ConsoleLogChars32 = LogChars<[u32; 6]>;
919
920/// Specialized type for 64-bit `FFA_CONSOLE_LOG` payload.
921pub type ConsoleLogChars64 = LogChars<[u64; 16]>;
922
923/// Flags field of the `FFA_NOTIFICATION_BIND` interface.
924#[derive(Debug, Eq, PartialEq, Clone, Copy)]
925pub struct NotificationBindFlags {
926    pub per_vcpu_notification: bool,
927}
928
929impl NotificationBindFlags {
930    const PER_VCPU_NOTIFICATION: u32 = 1;
931}
932
933impl From<NotificationBindFlags> for u32 {
934    fn from(flags: NotificationBindFlags) -> Self {
935        let mut bits: u32 = 0;
936        if flags.per_vcpu_notification {
937            bits |= NotificationBindFlags::PER_VCPU_NOTIFICATION;
938        }
939        bits
940    }
941}
942
943impl From<u32> for NotificationBindFlags {
944    fn from(flags: u32) -> Self {
945        Self {
946            per_vcpu_notification: flags & Self::PER_VCPU_NOTIFICATION != 0,
947        }
948    }
949}
950
951/// Flags field of the `FFA_NOTIFICATION_SET` interface.
952#[derive(Debug, Eq, PartialEq, Clone, Copy)]
953pub struct NotificationSetFlags {
954    pub delay_schedule_receiver: bool,
955    pub vcpu_id: Option<u16>,
956}
957
958impl NotificationSetFlags {
959    const PER_VCP_NOTIFICATION: u32 = 1 << 0;
960    const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
961    const VCPU_ID_SHIFT: u32 = 16;
962
963    const MBZ_BITS: u32 = 0xfffc;
964}
965
966impl From<NotificationSetFlags> for u32 {
967    fn from(flags: NotificationSetFlags) -> Self {
968        let mut bits: u32 = 0;
969
970        if flags.delay_schedule_receiver {
971            bits |= NotificationSetFlags::DELAY_SCHEDULE_RECEIVER;
972        }
973        if let Some(vcpu_id) = flags.vcpu_id {
974            bits |= NotificationSetFlags::PER_VCP_NOTIFICATION;
975            bits |= u32::from(vcpu_id) << NotificationSetFlags::VCPU_ID_SHIFT;
976        }
977
978        bits
979    }
980}
981
982impl TryFrom<u32> for NotificationSetFlags {
983    type Error = Error;
984
985    fn try_from(flags: u32) -> Result<Self, Self::Error> {
986        if (flags & Self::MBZ_BITS) != 0 {
987            return Err(Error::InvalidNotificationSetFlag(flags));
988        }
989
990        let tentative_vcpu_id = (flags >> Self::VCPU_ID_SHIFT) as u16;
991
992        let vcpu_id = if (flags & Self::PER_VCP_NOTIFICATION) != 0 {
993            Some(tentative_vcpu_id)
994        } else {
995            if tentative_vcpu_id != 0 {
996                return Err(Error::InvalidNotificationSetFlag(flags));
997            }
998            None
999        };
1000
1001        Ok(Self {
1002            delay_schedule_receiver: (flags & Self::DELAY_SCHEDULE_RECEIVER) != 0,
1003            vcpu_id,
1004        })
1005    }
1006}
1007
1008/// Flags field of the `FFA_NOTIFICATION_GET` interface.
1009#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1010pub struct NotificationGetFlags {
1011    pub sp_bitmap_id: bool,
1012    pub vm_bitmap_id: bool,
1013    pub spm_bitmap_id: bool,
1014    pub hyp_bitmap_id: bool,
1015}
1016
1017impl NotificationGetFlags {
1018    const SP_BITMAP_ID: u32 = 1;
1019    const VM_BITMAP_ID: u32 = 1 << 1;
1020    const SPM_BITMAP_ID: u32 = 1 << 2;
1021    const HYP_BITMAP_ID: u32 = 1 << 3;
1022}
1023
1024impl From<NotificationGetFlags> for u32 {
1025    fn from(flags: NotificationGetFlags) -> Self {
1026        let mut bits: u32 = 0;
1027        if flags.sp_bitmap_id {
1028            bits |= NotificationGetFlags::SP_BITMAP_ID;
1029        }
1030        if flags.vm_bitmap_id {
1031            bits |= NotificationGetFlags::VM_BITMAP_ID;
1032        }
1033        if flags.spm_bitmap_id {
1034            bits |= NotificationGetFlags::SPM_BITMAP_ID;
1035        }
1036        if flags.hyp_bitmap_id {
1037            bits |= NotificationGetFlags::HYP_BITMAP_ID;
1038        }
1039        bits
1040    }
1041}
1042
1043impl From<u32> for NotificationGetFlags {
1044    // This is a "from" instead of a "try_from" because Reserved Bits are SBZ, *not* MBZ.
1045    fn from(flags: u32) -> Self {
1046        Self {
1047            sp_bitmap_id: (flags & Self::SP_BITMAP_ID) != 0,
1048            vm_bitmap_id: (flags & Self::VM_BITMAP_ID) != 0,
1049            spm_bitmap_id: (flags & Self::SPM_BITMAP_ID) != 0,
1050            hyp_bitmap_id: (flags & Self::HYP_BITMAP_ID) != 0,
1051        }
1052    }
1053}
1054
1055/// `FFA_NOTIFICATION_GET` specific success argument structure.
1056#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1057pub struct SuccessArgsNotificationGet {
1058    pub sp_notifications: Option<u64>,
1059    pub vm_notifications: Option<u64>,
1060    pub spm_notifications: Option<u32>,
1061    pub hypervisor_notifications: Option<u32>,
1062}
1063
1064impl From<SuccessArgsNotificationGet> for SuccessArgs {
1065    fn from(value: SuccessArgsNotificationGet) -> Self {
1066        let mut args = [0; 6];
1067
1068        if let Some(bitmap) = value.sp_notifications {
1069            args[0] = bitmap as u32;
1070            args[1] = (bitmap >> 32) as u32;
1071        }
1072
1073        if let Some(bitmap) = value.vm_notifications {
1074            args[2] = bitmap as u32;
1075            args[3] = (bitmap >> 32) as u32;
1076        }
1077
1078        if let Some(bitmap) = value.spm_notifications {
1079            args[4] = bitmap;
1080        }
1081
1082        if let Some(bitmap) = value.hypervisor_notifications {
1083            args[5] = bitmap;
1084        }
1085
1086        Self::Args32(args)
1087    }
1088}
1089
1090impl TryFrom<(NotificationGetFlags, SuccessArgs)> for SuccessArgsNotificationGet {
1091    type Error = Error;
1092
1093    fn try_from(value: (NotificationGetFlags, SuccessArgs)) -> Result<Self, Self::Error> {
1094        let (flags, value) = value;
1095        let args = value.try_get_args32()?;
1096
1097        let sp_notifications = if flags.sp_bitmap_id {
1098            Some(u64::from(args[0]) | (u64::from(args[1]) << 32))
1099        } else {
1100            None
1101        };
1102
1103        let vm_notifications = if flags.vm_bitmap_id {
1104            Some(u64::from(args[2]) | (u64::from(args[3]) << 32))
1105        } else {
1106            None
1107        };
1108
1109        let spm_notifications = if flags.spm_bitmap_id {
1110            Some(args[4])
1111        } else {
1112            None
1113        };
1114
1115        let hypervisor_notifications = if flags.hyp_bitmap_id {
1116            Some(args[5])
1117        } else {
1118            None
1119        };
1120
1121        Ok(Self {
1122            sp_notifications,
1123            vm_notifications,
1124            spm_notifications,
1125            hypervisor_notifications,
1126        })
1127    }
1128}
1129
1130/// `FFA_NOTIFICATION_INFO_GET` specific success argument structure. The `MAX_COUNT` parameter
1131/// depends on the 32-bit or 64-bit packing.
1132#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1133pub struct SuccessArgsNotificationInfoGet<const MAX_COUNT: usize> {
1134    pub more_pending_notifications: bool,
1135    list_count: usize,
1136    id_counts: [u8; MAX_COUNT],
1137    ids: [u16; MAX_COUNT],
1138}
1139
1140impl<const MAX_COUNT: usize> Default for SuccessArgsNotificationInfoGet<MAX_COUNT> {
1141    fn default() -> Self {
1142        Self {
1143            more_pending_notifications: false,
1144            list_count: 0,
1145            id_counts: [0; MAX_COUNT],
1146            ids: [0; MAX_COUNT],
1147        }
1148    }
1149}
1150
1151impl<const MAX_COUNT: usize> SuccessArgsNotificationInfoGet<MAX_COUNT> {
1152    const MORE_PENDING_NOTIFICATIONS_FLAG: u64 = 1 << 0;
1153    const LIST_COUNT_SHIFT: usize = 7;
1154    const LIST_COUNT_MASK: u64 = 0x1f;
1155    const ID_COUNT_SHIFT: usize = 12;
1156    const ID_COUNT_MASK: u64 = 0x03;
1157    const ID_COUNT_BITS: usize = 2;
1158
1159    pub fn add_list(&mut self, endpoint: u16, vcpu_ids: &[u16]) -> Result<(), Error> {
1160        if self.list_count >= MAX_COUNT || vcpu_ids.len() > Self::ID_COUNT_MASK as usize {
1161            return Err(Error::InvalidNotificationCount);
1162        }
1163
1164        // Each list contains at least one ID: the partition ID, followed by vCPU IDs. The number
1165        // of vCPU IDs is recorded in `id_counts`.
1166        let mut current_id_index = self.list_count + self.id_counts.iter().sum::<u8>() as usize;
1167        if current_id_index + 1 + vcpu_ids.len() > MAX_COUNT {
1168            // The new list does not fit into the available space for IDs.
1169            return Err(Error::InvalidNotificationCount);
1170        }
1171
1172        self.id_counts[self.list_count] = vcpu_ids.len() as u8;
1173        self.list_count += 1;
1174
1175        // The first ID is the endpoint ID.
1176        self.ids[current_id_index] = endpoint;
1177        current_id_index += 1;
1178
1179        // Insert the vCPU IDs.
1180        self.ids[current_id_index..current_id_index + vcpu_ids.len()].copy_from_slice(vcpu_ids);
1181
1182        Ok(())
1183    }
1184
1185    pub fn iter(&self) -> NotificationInfoGetIterator<'_> {
1186        NotificationInfoGetIterator {
1187            list_index: 0,
1188            id_index: 0,
1189            id_count: &self.id_counts[0..self.list_count],
1190            ids: &self.ids,
1191        }
1192    }
1193
1194    /// Pack flags field and IDs.
1195    fn pack(self) -> (u64, [u16; MAX_COUNT]) {
1196        let mut flags = if self.more_pending_notifications {
1197            Self::MORE_PENDING_NOTIFICATIONS_FLAG
1198        } else {
1199            0
1200        };
1201
1202        flags |= (self.list_count as u64) << Self::LIST_COUNT_SHIFT;
1203        for (count, shift) in self.id_counts.iter().take(self.list_count).zip(
1204            (Self::ID_COUNT_SHIFT..Self::ID_COUNT_SHIFT + Self::ID_COUNT_BITS * MAX_COUNT)
1205                .step_by(Self::ID_COUNT_BITS),
1206        ) {
1207            flags |= u64::from(*count) << shift;
1208        }
1209
1210        (flags, self.ids)
1211    }
1212
1213    /// Unpack flags field and IDs.
1214    fn unpack(flags: u64, ids: [u16; MAX_COUNT]) -> Result<Self, Error> {
1215        let count_of_lists = ((flags >> Self::LIST_COUNT_SHIFT) & Self::LIST_COUNT_MASK) as usize;
1216
1217        if count_of_lists > MAX_COUNT {
1218            return Err(Error::InvalidNotificationCount);
1219        }
1220
1221        let mut count_of_ids = [0; MAX_COUNT];
1222        let mut count_of_ids_bits = flags >> Self::ID_COUNT_SHIFT;
1223
1224        for id in count_of_ids.iter_mut().take(count_of_lists) {
1225            *id = (count_of_ids_bits & Self::ID_COUNT_MASK) as u8;
1226            count_of_ids_bits >>= Self::ID_COUNT_BITS;
1227        }
1228
1229        let id_field_count = count_of_lists + count_of_ids.iter().sum::<u8>() as usize;
1230        if id_field_count > MAX_COUNT {
1231            return Err(Error::InvalidNotificationCount);
1232        }
1233
1234        Ok(Self {
1235            more_pending_notifications: (flags & Self::MORE_PENDING_NOTIFICATIONS_FLAG) != 0,
1236            list_count: count_of_lists,
1237            id_counts: count_of_ids,
1238            ids,
1239        })
1240    }
1241}
1242
1243/// `FFA_NOTIFICATION_INFO_GET_32` specific success argument structure.
1244pub type SuccessArgsNotificationInfoGet32 = SuccessArgsNotificationInfoGet<10>;
1245
1246impl From<SuccessArgsNotificationInfoGet32> for SuccessArgs {
1247    fn from(value: SuccessArgsNotificationInfoGet32) -> Self {
1248        let (flags, ids) = value.pack();
1249        let id_regs: [u32; 5] = transmute!(ids);
1250
1251        let mut args = [0; 6];
1252        args[0] = flags as u32;
1253        args[1..6].copy_from_slice(&id_regs);
1254
1255        SuccessArgs::Args32(args)
1256    }
1257}
1258
1259impl TryFrom<SuccessArgs> for SuccessArgsNotificationInfoGet32 {
1260    type Error = Error;
1261
1262    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1263        let args = value.try_get_args32()?;
1264        let flags = args[0].into();
1265        let id_regs: [u32; 5] = args[1..6].try_into().unwrap();
1266        Self::unpack(flags, transmute!(id_regs))
1267    }
1268}
1269
1270/// `FFA_NOTIFICATION_INFO_GET_64` specific success argument structure.
1271pub type SuccessArgsNotificationInfoGet64 = SuccessArgsNotificationInfoGet<20>;
1272
1273impl From<SuccessArgsNotificationInfoGet64> for SuccessArgs {
1274    fn from(value: SuccessArgsNotificationInfoGet64) -> Self {
1275        let (flags, ids) = value.pack();
1276        let id_regs: [u64; 5] = transmute!(ids);
1277
1278        let mut args = [0; 6];
1279        args[0] = flags;
1280        args[1..6].copy_from_slice(&id_regs);
1281
1282        SuccessArgs::Args64(args)
1283    }
1284}
1285
1286impl TryFrom<SuccessArgs> for SuccessArgsNotificationInfoGet64 {
1287    type Error = Error;
1288
1289    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
1290        let args = value.try_get_args64()?;
1291        let flags = args[0];
1292        let id_regs: [u64; 5] = args[1..6].try_into().unwrap();
1293        Self::unpack(flags, transmute!(id_regs))
1294    }
1295}
1296
1297/// Iterator implementation for parsing the (partition ID, vCPU ID list) pairs of the `FFA_SUCCESS`
1298/// of an `FFA_NOTIFICATION_INFO_GET` call.
1299pub struct NotificationInfoGetIterator<'a> {
1300    list_index: usize,
1301    id_index: usize,
1302    id_count: &'a [u8],
1303    ids: &'a [u16],
1304}
1305
1306impl<'a> Iterator for NotificationInfoGetIterator<'a> {
1307    type Item = (u16, &'a [u16]);
1308
1309    fn next(&mut self) -> Option<Self::Item> {
1310        if self.list_index < self.id_count.len() {
1311            let partition_id = self.ids[self.id_index];
1312            let id_range =
1313                (self.id_index + 1)..=(self.id_index + self.id_count[self.list_index] as usize);
1314
1315            self.id_index += 1 + self.id_count[self.list_index] as usize;
1316            self.list_index += 1;
1317
1318            Some((partition_id, &self.ids[id_range]))
1319        } else {
1320            None
1321        }
1322    }
1323}
1324
1325/// FF-A "message types", the terminology used by the spec is "interfaces".
1326///
1327/// The interfaces are used by FF-A components for communication at an FF-A instance. The spec also
1328/// describes the valid FF-A instances and conduits for each interface.
1329#[derive(Debug, Eq, PartialEq, Clone, Copy)]
1330pub enum Interface {
1331    Error {
1332        target_info: TargetInfo,
1333        error_code: FfaError,
1334        error_arg: u32,
1335    },
1336    Success {
1337        target_info: TargetInfo,
1338        args: SuccessArgs,
1339    },
1340    Interrupt {
1341        target_info: TargetInfo,
1342        interrupt_id: u32,
1343    },
1344    Version {
1345        input_version: Version,
1346    },
1347    VersionOut {
1348        output_version: VersionOut,
1349    },
1350    Features {
1351        feat_id: Feature,
1352        input_properties: u32,
1353    },
1354    RxAcquire {
1355        vm_id: u16,
1356    },
1357    RxRelease {
1358        vm_id: u16,
1359    },
1360    RxTxMap {
1361        addr: RxTxAddr,
1362        page_cnt: u32,
1363    },
1364    RxTxUnmap {
1365        id: u16,
1366    },
1367    PartitionInfoGet {
1368        uuid: Uuid,
1369        flags: PartitionInfoGetFlags,
1370    },
1371    PartitionInfoGetRegs {
1372        uuid: Uuid,
1373        start_index: u16,
1374        info_tag: u16,
1375    },
1376    IdGet,
1377    SpmIdGet,
1378    MsgWait {
1379        flags: Option<MsgWaitFlags>,
1380    },
1381    Yield,
1382    Run {
1383        target_info: TargetInfo,
1384    },
1385    NormalWorldResume,
1386    SecondaryEpRegister {
1387        entrypoint: SecondaryEpRegisterAddr,
1388    },
1389    MsgSend2 {
1390        sender_vm_id: u16,
1391        flags: MsgSend2Flags,
1392    },
1393    MsgSendDirectReq {
1394        src_id: u16,
1395        dst_id: u16,
1396        args: DirectMsgArgs,
1397    },
1398    MsgSendDirectResp {
1399        src_id: u16,
1400        dst_id: u16,
1401        args: DirectMsgArgs,
1402    },
1403    MsgSendDirectReq2 {
1404        src_id: u16,
1405        dst_id: u16,
1406        uuid: Uuid,
1407        args: DirectMsg2Args,
1408    },
1409    MsgSendDirectResp2 {
1410        src_id: u16,
1411        dst_id: u16,
1412        args: DirectMsg2Args,
1413    },
1414    MemDonate {
1415        total_len: u32,
1416        frag_len: u32,
1417        buf: Option<MemOpBuf>,
1418    },
1419    MemLend {
1420        total_len: u32,
1421        frag_len: u32,
1422        buf: Option<MemOpBuf>,
1423    },
1424    MemShare {
1425        total_len: u32,
1426        frag_len: u32,
1427        buf: Option<MemOpBuf>,
1428    },
1429    MemRetrieveReq {
1430        total_len: u32,
1431        frag_len: u32,
1432        buf: Option<MemOpBuf>,
1433    },
1434    MemRetrieveResp {
1435        total_len: u32,
1436        frag_len: u32,
1437    },
1438    MemRelinquish,
1439    MemReclaim {
1440        handle: memory_management::Handle,
1441        flags: memory_management::MemReclaimFlags,
1442    },
1443    MemPermGet {
1444        addr: MemAddr,
1445        /// The actual number of pages queried by the call.  It is calculated by adding one to the
1446        /// corresponding register's value, i.e. zero in the register means one page. For FF-A v1.2
1447        /// and lower the register value MBZ, so the page count is always 1. For higher versions the
1448        /// page count can be any nonzero value.
1449        page_cnt: u32,
1450    },
1451    MemPermSet {
1452        addr: MemAddr,
1453        page_cnt: u32,
1454        mem_perm: memory_management::MemPermissionsGetSet,
1455    },
1456    MemOpPause {
1457        handle: memory_management::Handle,
1458    },
1459    MemOpResume {
1460        handle: memory_management::Handle,
1461    },
1462    MemFragRx {
1463        handle: memory_management::Handle,
1464        frag_offset: u32,
1465        endpoint_id: u16,
1466    },
1467    MemFragTx {
1468        handle: memory_management::Handle,
1469        frag_len: u32,
1470        endpoint_id: u16,
1471    },
1472    ConsoleLog {
1473        chars: ConsoleLogChars,
1474    },
1475    NotificationBitmapCreate {
1476        vm_id: u16,
1477        vcpu_cnt: u32,
1478    },
1479    NotificationBitmapDestroy {
1480        vm_id: u16,
1481    },
1482    NotificationBind {
1483        sender_id: u16,
1484        receiver_id: u16,
1485        flags: NotificationBindFlags,
1486        bitmap: u64,
1487    },
1488    NotificationUnbind {
1489        sender_id: u16,
1490        receiver_id: u16,
1491        bitmap: u64,
1492    },
1493    NotificationSet {
1494        sender_id: u16,
1495        receiver_id: u16,
1496        flags: NotificationSetFlags,
1497        bitmap: u64,
1498    },
1499    NotificationGet {
1500        vcpu_id: u16,
1501        endpoint_id: u16,
1502        flags: NotificationGetFlags,
1503    },
1504    NotificationInfoGet {
1505        is_32bit: bool,
1506    },
1507    El3IntrHandle,
1508}
1509
1510impl Interface {
1511    /// Returns the function ID for the call, if it has one.
1512    pub fn function_id(&self) -> Option<FuncId> {
1513        match self {
1514            Interface::Error { .. } => Some(FuncId::Error),
1515            Interface::Success { args, .. } => match args {
1516                SuccessArgs::Args32(..) => Some(FuncId::Success32),
1517                SuccessArgs::Args64(..) | SuccessArgs::Args64_2(..) => Some(FuncId::Success64),
1518            },
1519            Interface::Interrupt { .. } => Some(FuncId::Interrupt),
1520            Interface::Version { .. } => Some(FuncId::Version),
1521            Interface::VersionOut { .. } => None,
1522            Interface::Features { .. } => Some(FuncId::Features),
1523            Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
1524            Interface::RxRelease { .. } => Some(FuncId::RxRelease),
1525            Interface::RxTxMap { addr, .. } => match addr {
1526                RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
1527                RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
1528            },
1529            Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
1530            Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
1531            Interface::PartitionInfoGetRegs { .. } => Some(FuncId::PartitionInfoGetRegs),
1532            Interface::IdGet => Some(FuncId::IdGet),
1533            Interface::SpmIdGet => Some(FuncId::SpmIdGet),
1534            Interface::MsgWait { .. } => Some(FuncId::MsgWait),
1535            Interface::Yield => Some(FuncId::Yield),
1536            Interface::Run { .. } => Some(FuncId::Run),
1537            Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
1538            Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
1539                SecondaryEpRegisterAddr::Addr32 { .. } => Some(FuncId::SecondaryEpRegister32),
1540                SecondaryEpRegisterAddr::Addr64 { .. } => Some(FuncId::SecondaryEpRegister64),
1541            },
1542            Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
1543            Interface::MsgSendDirectReq { args, .. } => match args {
1544                DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
1545                DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
1546                DirectMsgArgs::VersionReq { .. } => Some(FuncId::MsgSendDirectReq32),
1547                DirectMsgArgs::PowerPsciReq32 { .. } => Some(FuncId::MsgSendDirectReq32),
1548                DirectMsgArgs::PowerPsciReq64 { .. } => Some(FuncId::MsgSendDirectReq64),
1549                DirectMsgArgs::PowerWarmBootReq { .. } => Some(FuncId::MsgSendDirectReq32),
1550                DirectMsgArgs::VmCreated { .. } => Some(FuncId::MsgSendDirectReq32),
1551                DirectMsgArgs::VmDestructed { .. } => Some(FuncId::MsgSendDirectReq32),
1552                _ => panic!("Invalid direct request arguments: {:#?}", args),
1553            },
1554            Interface::MsgSendDirectResp { args, .. } => match args {
1555                DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
1556                DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
1557                DirectMsgArgs::VersionResp { .. } => Some(FuncId::MsgSendDirectResp32),
1558                DirectMsgArgs::PowerPsciResp { .. } => Some(FuncId::MsgSendDirectResp32),
1559                DirectMsgArgs::VmCreatedAck { .. } => Some(FuncId::MsgSendDirectResp32),
1560                DirectMsgArgs::VmDestructedAck { .. } => Some(FuncId::MsgSendDirectResp32),
1561                _ => panic!("Invalid direct response arguments: {:#?}", args),
1562            },
1563            Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
1564            Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
1565            Interface::MemDonate { buf, .. } => match buf {
1566                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
1567                _ => Some(FuncId::MemDonate32),
1568            },
1569            Interface::MemLend { buf, .. } => match buf {
1570                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
1571                _ => Some(FuncId::MemLend32),
1572            },
1573            Interface::MemShare { buf, .. } => match buf {
1574                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
1575                _ => Some(FuncId::MemShare32),
1576            },
1577            Interface::MemRetrieveReq { buf, .. } => match buf {
1578                Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
1579                _ => Some(FuncId::MemRetrieveReq32),
1580            },
1581            Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
1582            Interface::MemRelinquish => Some(FuncId::MemRelinquish),
1583            Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
1584            Interface::MemPermGet { addr, .. } => match addr {
1585                MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
1586                MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
1587            },
1588            Interface::MemPermSet { addr, .. } => match addr {
1589                MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
1590                MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
1591            },
1592            Interface::MemOpPause { .. } => Some(FuncId::MemOpPause),
1593            Interface::MemOpResume { .. } => Some(FuncId::MemOpResume),
1594            Interface::MemFragRx { .. } => Some(FuncId::MemFragRx),
1595            Interface::MemFragTx { .. } => Some(FuncId::MemFragTx),
1596            Interface::ConsoleLog { chars, .. } => match chars {
1597                ConsoleLogChars::Chars32(_) => Some(FuncId::ConsoleLog32),
1598                ConsoleLogChars::Chars64(_) => Some(FuncId::ConsoleLog64),
1599            },
1600            Interface::NotificationBitmapCreate { .. } => Some(FuncId::NotificationBitmapCreate),
1601            Interface::NotificationBitmapDestroy { .. } => Some(FuncId::NotificationBitmapDestroy),
1602            Interface::NotificationBind { .. } => Some(FuncId::NotificationBind),
1603            Interface::NotificationUnbind { .. } => Some(FuncId::NotificationUnbind),
1604            Interface::NotificationSet { .. } => Some(FuncId::NotificationSet),
1605            Interface::NotificationGet { .. } => Some(FuncId::NotificationGet),
1606            Interface::NotificationInfoGet { is_32bit } => match is_32bit {
1607                true => Some(FuncId::NotificationInfoGet32),
1608                false => Some(FuncId::NotificationInfoGet64),
1609            },
1610            Interface::El3IntrHandle => Some(FuncId::El3IntrHandle),
1611        }
1612    }
1613
1614    /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
1615    pub fn is_32bit(&self) -> bool {
1616        if matches!(self, Self::VersionOut { .. }) {
1617            return true;
1618        }
1619
1620        self.function_id().unwrap().is_32bit()
1621    }
1622
1623    /// Returns the FF-A version that has introduced the function ID.
1624    pub fn minimum_ffa_version(&self) -> Version {
1625        if matches!(self, Self::VersionOut { .. }) {
1626            return Version(1, 0);
1627        }
1628
1629        self.function_id().unwrap().minimum_ffa_version()
1630    }
1631
1632    /// Parse interface from register contents. The caller must ensure that the `regs` argument has
1633    /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
1634    pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
1635        let func_id = FuncId::try_from(regs[0] as u32)?;
1636        if version < func_id.minimum_ffa_version() {
1637            return Err(Error::InvalidVersionForFunctionId(version, func_id));
1638        }
1639
1640        let reg_cnt = regs.len();
1641
1642        match reg_cnt {
1643            8 => {
1644                assert!(version <= Version(1, 1));
1645                Interface::unpack_regs8(version, func_id, regs.try_into().unwrap())
1646            }
1647            18 => {
1648                assert!(version >= Version(1, 2));
1649                match func_id {
1650                    FuncId::ConsoleLog64
1651                    | FuncId::Success64
1652                    | FuncId::MsgSendDirectReq64_2
1653                    | FuncId::MsgSendDirectResp64_2
1654                    | FuncId::PartitionInfoGetRegs => {
1655                        Interface::unpack_regs18(version, func_id, regs.try_into().unwrap())
1656                    }
1657                    _ => Interface::unpack_regs8(version, func_id, regs[..8].try_into().unwrap()),
1658                }
1659            }
1660            _ => panic!(
1661                "Invalid number of registers ({}) for FF-A version {}",
1662                reg_cnt, version
1663            ),
1664        }
1665    }
1666
1667    fn unpack_regs8(version: Version, func_id: FuncId, regs: &[u64; 8]) -> Result<Self, Error> {
1668        let msg = match func_id {
1669            FuncId::Error => Self::Error {
1670                target_info: (regs[1] as u32).into(),
1671                error_code: FfaError::try_from(regs[2] as i32)?,
1672                error_arg: regs[3] as u32,
1673            },
1674            FuncId::Success32 => Self::Success {
1675                target_info: (regs[1] as u32).into(),
1676                args: SuccessArgs::Args32([
1677                    regs[2] as u32,
1678                    regs[3] as u32,
1679                    regs[4] as u32,
1680                    regs[5] as u32,
1681                    regs[6] as u32,
1682                    regs[7] as u32,
1683                ]),
1684            },
1685            FuncId::Success64 => Self::Success {
1686                target_info: (regs[1] as u32).into(),
1687                args: SuccessArgs::Args64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
1688            },
1689            FuncId::Interrupt => Self::Interrupt {
1690                target_info: (regs[1] as u32).into(),
1691                interrupt_id: regs[2] as u32,
1692            },
1693            FuncId::Version => Self::Version {
1694                input_version: (regs[1] as u32).try_into()?,
1695            },
1696            FuncId::Features => Self::Features {
1697                feat_id: (regs[1] as u32).into(),
1698                input_properties: regs[2] as u32,
1699            },
1700            FuncId::RxAcquire => Self::RxAcquire {
1701                vm_id: regs[1] as u16,
1702            },
1703            FuncId::RxRelease => Self::RxRelease {
1704                vm_id: regs[1] as u16,
1705            },
1706            FuncId::RxTxMap32 => {
1707                let addr = RxTxAddr::Addr32 {
1708                    rx: regs[2] as u32,
1709                    tx: regs[1] as u32,
1710                };
1711                let page_cnt = regs[3] as u32;
1712
1713                Self::RxTxMap { addr, page_cnt }
1714            }
1715            FuncId::RxTxMap64 => {
1716                let addr = RxTxAddr::Addr64 {
1717                    rx: regs[2],
1718                    tx: regs[1],
1719                };
1720                let page_cnt = regs[3] as u32;
1721
1722                Self::RxTxMap { addr, page_cnt }
1723            }
1724            FuncId::RxTxUnmap => Self::RxTxUnmap {
1725                id: (regs[1] >> 16) as u16,
1726            },
1727            FuncId::PartitionInfoGet => {
1728                let uuid_words = [
1729                    regs[1] as u32,
1730                    regs[2] as u32,
1731                    regs[3] as u32,
1732                    regs[4] as u32,
1733                ];
1734
1735                Self::PartitionInfoGet {
1736                    uuid: UuidHelper::from_u32_regs(uuid_words),
1737                    flags: PartitionInfoGetFlags::try_from(regs[5] as u32)?,
1738                }
1739            }
1740            FuncId::IdGet => Self::IdGet,
1741            FuncId::SpmIdGet => Self::SpmIdGet,
1742            FuncId::MsgWait => Self::MsgWait {
1743                flags: if version >= Version(1, 2) {
1744                    Some(MsgWaitFlags::try_from(regs[2] as u32)?)
1745                } else {
1746                    None
1747                },
1748            },
1749            FuncId::Yield => Self::Yield,
1750            FuncId::Run => Self::Run {
1751                target_info: (regs[1] as u32).into(),
1752            },
1753            FuncId::NormalWorldResume => Self::NormalWorldResume,
1754            FuncId::SecondaryEpRegister32 => Self::SecondaryEpRegister {
1755                entrypoint: SecondaryEpRegisterAddr::Addr32(regs[1] as u32),
1756            },
1757            FuncId::SecondaryEpRegister64 => Self::SecondaryEpRegister {
1758                entrypoint: SecondaryEpRegisterAddr::Addr64(regs[1]),
1759            },
1760            FuncId::MsgSend2 => Self::MsgSend2 {
1761                sender_vm_id: (regs[1] >> 16) as u16,
1762                flags: (regs[2] as u32).try_into()?,
1763            },
1764            FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
1765                src_id: (regs[1] >> 16) as u16,
1766                dst_id: regs[1] as u16,
1767                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1768                    match regs[2] as u32 {
1769                        DirectMsgArgs::VERSION_REQ => DirectMsgArgs::VersionReq {
1770                            version: Version::try_from(regs[3] as u32)?,
1771                        },
1772                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq32 {
1773                            params: [
1774                                regs[3] as u32,
1775                                regs[4] as u32,
1776                                regs[5] as u32,
1777                                regs[6] as u32,
1778                            ],
1779                        },
1780                        DirectMsgArgs::POWER_WARM_BOOT_REQ => DirectMsgArgs::PowerWarmBootReq {
1781                            boot_type: WarmBootType::try_from(regs[3] as u32)?,
1782                        },
1783                        DirectMsgArgs::VM_CREATED => DirectMsgArgs::VmCreated {
1784                            handle: memory_management::Handle::from([
1785                                regs[3] as u32,
1786                                regs[4] as u32,
1787                            ]),
1788                            vm_id: regs[5] as u16,
1789                        },
1790                        DirectMsgArgs::VM_DESTRUCTED => DirectMsgArgs::VmDestructed {
1791                            handle: memory_management::Handle::from([
1792                                regs[3] as u32,
1793                                regs[4] as u32,
1794                            ]),
1795                            vm_id: regs[5] as u16,
1796                        },
1797                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1798                    }
1799                } else {
1800                    DirectMsgArgs::Args32([
1801                        regs[3] as u32,
1802                        regs[4] as u32,
1803                        regs[5] as u32,
1804                        regs[6] as u32,
1805                        regs[7] as u32,
1806                    ])
1807                },
1808            },
1809            FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
1810                src_id: (regs[1] >> 16) as u16,
1811                dst_id: regs[1] as u16,
1812                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1813                    match regs[2] as u32 {
1814                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq64 {
1815                            params: [regs[3], regs[4], regs[5], regs[6]],
1816                        },
1817                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1818                    }
1819                } else {
1820                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1821                },
1822            },
1823            FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
1824                src_id: (regs[1] >> 16) as u16,
1825                dst_id: regs[1] as u16,
1826                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1827                    match regs[2] as u32 {
1828                        DirectMsgArgs::VERSION_RESP => {
1829                            if regs[3] as i32 == FfaError::NotSupported.into() {
1830                                DirectMsgArgs::VersionResp { version: None }
1831                            } else {
1832                                DirectMsgArgs::VersionResp {
1833                                    version: Some(Version::try_from(regs[3] as u32)?),
1834                                }
1835                            }
1836                        }
1837                        DirectMsgArgs::POWER_PSCI_RESP => DirectMsgArgs::PowerPsciResp {
1838                            psci_status: regs[3] as i32,
1839                        },
1840                        DirectMsgArgs::VM_CREATED_ACK => DirectMsgArgs::VmCreatedAck {
1841                            sp_status: (regs[3] as i32).try_into()?,
1842                        },
1843                        DirectMsgArgs::VM_DESTRUCTED_ACK => DirectMsgArgs::VmDestructedAck {
1844                            sp_status: (regs[3] as i32).try_into()?,
1845                        },
1846                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1847                    }
1848                } else {
1849                    DirectMsgArgs::Args32([
1850                        regs[3] as u32,
1851                        regs[4] as u32,
1852                        regs[5] as u32,
1853                        regs[6] as u32,
1854                        regs[7] as u32,
1855                    ])
1856                },
1857            },
1858            FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
1859                src_id: (regs[1] >> 16) as u16,
1860                dst_id: regs[1] as u16,
1861                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1862                    return Err(Error::UnrecognisedFwkMsg(regs[2] as u32));
1863                } else {
1864                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1865                },
1866            },
1867            FuncId::MemDonate32 => Self::MemDonate {
1868                total_len: regs[1] as u32,
1869                frag_len: regs[2] as u32,
1870                buf: if regs[3] != 0 && regs[4] != 0 {
1871                    Some(MemOpBuf::Buf32 {
1872                        addr: regs[3] as u32,
1873                        page_cnt: regs[4] as u32,
1874                    })
1875                } else {
1876                    None
1877                },
1878            },
1879            FuncId::MemDonate64 => Self::MemDonate {
1880                total_len: regs[1] as u32,
1881                frag_len: regs[2] as u32,
1882                buf: if regs[3] != 0 && regs[4] != 0 {
1883                    Some(MemOpBuf::Buf64 {
1884                        addr: regs[3],
1885                        page_cnt: regs[4] as u32,
1886                    })
1887                } else {
1888                    None
1889                },
1890            },
1891            FuncId::MemLend32 => Self::MemLend {
1892                total_len: regs[1] as u32,
1893                frag_len: regs[2] as u32,
1894                buf: if regs[3] != 0 && regs[4] != 0 {
1895                    Some(MemOpBuf::Buf32 {
1896                        addr: regs[3] as u32,
1897                        page_cnt: regs[4] as u32,
1898                    })
1899                } else {
1900                    None
1901                },
1902            },
1903            FuncId::MemLend64 => Self::MemLend {
1904                total_len: regs[1] as u32,
1905                frag_len: regs[2] as u32,
1906                buf: if regs[3] != 0 && regs[4] != 0 {
1907                    Some(MemOpBuf::Buf64 {
1908                        addr: regs[3],
1909                        page_cnt: regs[4] as u32,
1910                    })
1911                } else {
1912                    None
1913                },
1914            },
1915            FuncId::MemShare32 => Self::MemShare {
1916                total_len: regs[1] as u32,
1917                frag_len: regs[2] as u32,
1918                buf: if regs[3] != 0 && regs[4] != 0 {
1919                    Some(MemOpBuf::Buf32 {
1920                        addr: regs[3] as u32,
1921                        page_cnt: regs[4] as u32,
1922                    })
1923                } else {
1924                    None
1925                },
1926            },
1927            FuncId::MemShare64 => Self::MemShare {
1928                total_len: regs[1] as u32,
1929                frag_len: regs[2] as u32,
1930                buf: if regs[3] != 0 && regs[4] != 0 {
1931                    Some(MemOpBuf::Buf64 {
1932                        addr: regs[3],
1933                        page_cnt: regs[4] as u32,
1934                    })
1935                } else {
1936                    None
1937                },
1938            },
1939            FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
1940                total_len: regs[1] as u32,
1941                frag_len: regs[2] as u32,
1942                buf: if regs[3] != 0 && regs[4] != 0 {
1943                    Some(MemOpBuf::Buf32 {
1944                        addr: regs[3] as u32,
1945                        page_cnt: regs[4] as u32,
1946                    })
1947                } else {
1948                    None
1949                },
1950            },
1951            FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
1952                total_len: regs[1] as u32,
1953                frag_len: regs[2] as u32,
1954                buf: if regs[3] != 0 && regs[4] != 0 {
1955                    Some(MemOpBuf::Buf64 {
1956                        addr: regs[3],
1957                        page_cnt: regs[4] as u32,
1958                    })
1959                } else {
1960                    None
1961                },
1962            },
1963            FuncId::MemRetrieveResp => Self::MemRetrieveResp {
1964                total_len: regs[1] as u32,
1965                frag_len: regs[2] as u32,
1966            },
1967            FuncId::MemRelinquish => Self::MemRelinquish,
1968            FuncId::MemReclaim => Self::MemReclaim {
1969                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
1970                flags: (regs[3] as u32).try_into()?,
1971            },
1972            FuncId::MemPermGet32 => {
1973                if (version <= Version(1, 2) && regs[2] != 0)
1974                    || (regs[2] as u32).checked_add(1).is_none()
1975                {
1976                    return Err(Error::MemoryManagementError(
1977                        memory_management::Error::InvalidPageCount,
1978                    ));
1979                }
1980
1981                Self::MemPermGet {
1982                    addr: MemAddr::Addr32(regs[1] as u32),
1983                    page_cnt: regs[2] as u32 + 1,
1984                }
1985            }
1986            FuncId::MemPermGet64 => {
1987                if (version <= Version(1, 2) && regs[2] != 0)
1988                    || (regs[2] as u32).checked_add(1).is_none()
1989                {
1990                    return Err(Error::MemoryManagementError(
1991                        memory_management::Error::InvalidPageCount,
1992                    ));
1993                }
1994
1995                Self::MemPermGet {
1996                    addr: MemAddr::Addr64(regs[1]),
1997                    page_cnt: regs[2] as u32 + 1,
1998                }
1999            }
2000            FuncId::MemPermSet32 => Self::MemPermSet {
2001                addr: MemAddr::Addr32(regs[1] as u32),
2002                page_cnt: regs[2] as u32,
2003                mem_perm: (regs[3] as u32).try_into()?,
2004            },
2005            FuncId::MemPermSet64 => Self::MemPermSet {
2006                addr: MemAddr::Addr64(regs[1]),
2007                page_cnt: regs[2] as u32,
2008                mem_perm: (regs[3] as u32).try_into()?,
2009            },
2010            FuncId::MemOpPause => Self::MemOpPause {
2011                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2012            },
2013            FuncId::MemOpResume => Self::MemOpResume {
2014                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2015            },
2016            FuncId::MemFragRx => Self::MemFragRx {
2017                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2018                frag_offset: regs[3] as u32,
2019                endpoint_id: (regs[4] >> 16) as u16,
2020            },
2021            FuncId::MemFragTx => Self::MemFragTx {
2022                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2023                frag_len: regs[3] as u32,
2024                endpoint_id: (regs[4] >> 16) as u16,
2025            },
2026            FuncId::ConsoleLog32 => {
2027                let char_cnt = regs[1] as u8;
2028                if char_cnt > ConsoleLogChars32::MAX_LENGTH {
2029                    return Err(Error::InvalidCharacterCount(char_cnt));
2030                }
2031
2032                Self::ConsoleLog {
2033                    chars: ConsoleLogChars::Chars32(ConsoleLogChars32 {
2034                        char_cnt,
2035                        char_lists: [
2036                            regs[2] as u32,
2037                            regs[3] as u32,
2038                            regs[4] as u32,
2039                            regs[5] as u32,
2040                            regs[6] as u32,
2041                            regs[7] as u32,
2042                        ],
2043                    }),
2044                }
2045            }
2046            FuncId::NotificationBitmapCreate => {
2047                let tentative_vm_id = regs[1] as u32;
2048                if (tentative_vm_id >> 16) != 0 {
2049                    return Err(Error::InvalidVmId(tentative_vm_id));
2050                }
2051                Self::NotificationBitmapCreate {
2052                    vm_id: tentative_vm_id as u16,
2053                    vcpu_cnt: regs[2] as u32,
2054                }
2055            }
2056            FuncId::NotificationBitmapDestroy => {
2057                let tentative_vm_id = regs[1] as u32;
2058                if (tentative_vm_id >> 16) != 0 {
2059                    return Err(Error::InvalidVmId(tentative_vm_id));
2060                }
2061                Self::NotificationBitmapDestroy {
2062                    vm_id: tentative_vm_id as u16,
2063                }
2064            }
2065            FuncId::NotificationBind => Self::NotificationBind {
2066                sender_id: (regs[1] >> 16) as u16,
2067                receiver_id: regs[1] as u16,
2068                flags: (regs[2] as u32).into(),
2069                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
2070            },
2071            FuncId::NotificationUnbind => Self::NotificationUnbind {
2072                sender_id: (regs[1] >> 16) as u16,
2073                receiver_id: regs[1] as u16,
2074                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
2075            },
2076            FuncId::NotificationSet => Self::NotificationSet {
2077                sender_id: (regs[1] >> 16) as u16,
2078                receiver_id: regs[1] as u16,
2079                flags: (regs[2] as u32).try_into()?,
2080                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
2081            },
2082            FuncId::NotificationGet => Self::NotificationGet {
2083                vcpu_id: (regs[1] >> 16) as u16,
2084                endpoint_id: regs[1] as u16,
2085                flags: (regs[2] as u32).into(),
2086            },
2087            FuncId::NotificationInfoGet32 => Self::NotificationInfoGet { is_32bit: true },
2088            FuncId::NotificationInfoGet64 => Self::NotificationInfoGet { is_32bit: false },
2089            FuncId::El3IntrHandle => Self::El3IntrHandle,
2090            _ => panic!(
2091                "Invalid number of registers (8) for function {:#x?}",
2092                func_id
2093            ),
2094        };
2095
2096        Ok(msg)
2097    }
2098
2099    fn unpack_regs18(version: Version, func_id: FuncId, regs: &[u64; 18]) -> Result<Self, Error> {
2100        assert!(version >= Version(1, 2));
2101
2102        let msg = match func_id {
2103            FuncId::Success64 => Self::Success {
2104                target_info: (regs[1] as u32).into(),
2105                args: SuccessArgs::Args64_2(regs[2..18].try_into().unwrap()),
2106            },
2107            FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
2108                src_id: (regs[1] >> 16) as u16,
2109                dst_id: regs[1] as u16,
2110                uuid: UuidHelper::from_u64_regs([regs[2], regs[3]]),
2111                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
2112            },
2113            FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
2114                src_id: (regs[1] >> 16) as u16,
2115                dst_id: regs[1] as u16,
2116                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
2117            },
2118            FuncId::ConsoleLog64 => {
2119                let char_cnt = regs[1] as u8;
2120                if char_cnt > ConsoleLogChars64::MAX_LENGTH {
2121                    return Err(Error::InvalidCharacterCount(char_cnt));
2122                }
2123
2124                Self::ConsoleLog {
2125                    chars: ConsoleLogChars::Chars64(ConsoleLogChars64 {
2126                        char_cnt,
2127                        char_lists: regs[2..18].try_into().unwrap(),
2128                    }),
2129                }
2130            }
2131            FuncId::PartitionInfoGetRegs => {
2132                // Bits[15:0]: Start index
2133                let start_index = (regs[3] & 0xffff) as u16;
2134                let info_tag = ((regs[3] >> 16) & 0xffff) as u16;
2135                Self::PartitionInfoGetRegs {
2136                    uuid: UuidHelper::from_u64_regs([regs[1], regs[2]]),
2137                    start_index,
2138                    info_tag: if start_index == 0 && info_tag != 0 {
2139                        return Err(Error::InvalidInformationTag(info_tag));
2140                    } else {
2141                        info_tag
2142                    },
2143                }
2144            }
2145            _ => panic!(
2146                "Invalid number of registers (18) for function {:#x?}",
2147                func_id
2148            ),
2149        };
2150
2151        Ok(msg)
2152    }
2153
2154    /// Create register contents for an interface.
2155    pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
2156        assert!(self.minimum_ffa_version() <= version);
2157
2158        let reg_cnt = regs.len();
2159
2160        match reg_cnt {
2161            8 => {
2162                assert!(version <= Version(1, 1));
2163                self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
2164            }
2165            18 => {
2166                assert!(version >= Version(1, 2));
2167                match self {
2168                    Interface::ConsoleLog {
2169                        chars: ConsoleLogChars::Chars64(_),
2170                        ..
2171                    }
2172                    | Interface::Success {
2173                        args: SuccessArgs::Args64_2(_),
2174                        ..
2175                    }
2176                    | Interface::MsgSendDirectReq2 { .. }
2177                    | Interface::MsgSendDirectResp2 { .. }
2178                    | Interface::PartitionInfoGetRegs { .. } => {
2179                        self.pack_regs18(version, regs.try_into().unwrap());
2180                    }
2181                    _ => {
2182                        self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
2183                        regs[8..18].fill(0);
2184                    }
2185                }
2186            }
2187            _ => panic!("Invalid number of registers {}", reg_cnt),
2188        }
2189    }
2190
2191    fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
2192        a.fill(0);
2193
2194        if let Some(function_id) = self.function_id() {
2195            a[0] = function_id as u64;
2196        }
2197
2198        match *self {
2199            Interface::Error {
2200                target_info,
2201                error_code,
2202                error_arg,
2203            } => {
2204                a[1] = u32::from(target_info).into();
2205                a[2] = (error_code as u32).into();
2206                a[3] = error_arg.into();
2207            }
2208            Interface::Success { target_info, args } => {
2209                a[1] = u32::from(target_info).into();
2210                match args {
2211                    SuccessArgs::Args32(regs) => {
2212                        a[2] = regs[0].into();
2213                        a[3] = regs[1].into();
2214                        a[4] = regs[2].into();
2215                        a[5] = regs[3].into();
2216                        a[6] = regs[4].into();
2217                        a[7] = regs[5].into();
2218                    }
2219                    SuccessArgs::Args64(regs) => {
2220                        a[2] = regs[0];
2221                        a[3] = regs[1];
2222                        a[4] = regs[2];
2223                        a[5] = regs[3];
2224                        a[6] = regs[4];
2225                        a[7] = regs[5];
2226                    }
2227                    _ => panic!("{:#x?} requires 18 registers", args),
2228                }
2229            }
2230            Interface::Interrupt {
2231                target_info,
2232                interrupt_id,
2233            } => {
2234                a[1] = u32::from(target_info).into();
2235                a[2] = interrupt_id.into();
2236            }
2237            Interface::Version { input_version } => {
2238                a[1] = u32::from(input_version).into();
2239            }
2240            Interface::VersionOut { output_version } => {
2241                a[0] = u32::from(output_version).into();
2242            }
2243            Interface::Features {
2244                feat_id,
2245                input_properties,
2246            } => {
2247                a[1] = u32::from(feat_id).into();
2248                a[2] = input_properties.into();
2249            }
2250            Interface::RxAcquire { vm_id } => {
2251                a[1] = vm_id.into();
2252            }
2253            Interface::RxRelease { vm_id } => {
2254                a[1] = vm_id.into();
2255            }
2256            Interface::RxTxMap { addr, page_cnt } => {
2257                match addr {
2258                    RxTxAddr::Addr32 { rx, tx } => {
2259                        a[1] = tx.into();
2260                        a[2] = rx.into();
2261                    }
2262                    RxTxAddr::Addr64 { rx, tx } => {
2263                        a[1] = tx;
2264                        a[2] = rx;
2265                    }
2266                }
2267                a[3] = page_cnt.into();
2268            }
2269            Interface::RxTxUnmap { id } => {
2270                a[1] = (u32::from(id) << 16).into();
2271            }
2272            Interface::PartitionInfoGet { uuid, flags } => {
2273                let uuid_words: [u32; 4] = UuidHelper::to_u32_regs(uuid);
2274
2275                a[1] = uuid_words[0].into();
2276                a[2] = uuid_words[1].into();
2277                a[3] = uuid_words[2].into();
2278                a[4] = uuid_words[3].into();
2279                a[5] = u32::from(flags).into();
2280            }
2281            Interface::MsgWait { flags } => {
2282                if version >= Version(1, 2) {
2283                    if let Some(flags) = flags {
2284                        a[2] = u32::from(flags).into();
2285                    }
2286                }
2287            }
2288            Interface::IdGet | Interface::SpmIdGet | Interface::Yield => {}
2289            Interface::Run { target_info } => {
2290                a[1] = u32::from(target_info).into();
2291            }
2292            Interface::NormalWorldResume => {}
2293            Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
2294                SecondaryEpRegisterAddr::Addr32(addr) => a[1] = addr as u64,
2295                SecondaryEpRegisterAddr::Addr64(addr) => a[1] = addr,
2296            },
2297            Interface::MsgSend2 {
2298                sender_vm_id,
2299                flags,
2300            } => {
2301                a[1] = (sender_vm_id as u64) << 16;
2302                a[2] = u32::from(flags).into();
2303            }
2304            Interface::MsgSendDirectReq {
2305                src_id,
2306                dst_id,
2307                args,
2308            } => {
2309                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2310                match args {
2311                    DirectMsgArgs::Args32(args) => {
2312                        a[3] = args[0].into();
2313                        a[4] = args[1].into();
2314                        a[5] = args[2].into();
2315                        a[6] = args[3].into();
2316                        a[7] = args[4].into();
2317                    }
2318                    DirectMsgArgs::Args64(args) => {
2319                        a[3] = args[0];
2320                        a[4] = args[1];
2321                        a[5] = args[2];
2322                        a[6] = args[3];
2323                        a[7] = args[4];
2324                    }
2325                    DirectMsgArgs::VersionReq { version } => {
2326                        a[2] = DirectMsgArgs::VERSION_REQ.into();
2327                        a[3] = u32::from(version).into();
2328                    }
2329                    DirectMsgArgs::PowerPsciReq32 { params } => {
2330                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2331                        a[3] = params[0].into();
2332                        a[4] = params[1].into();
2333                        a[5] = params[2].into();
2334                        a[6] = params[3].into();
2335                    }
2336                    DirectMsgArgs::PowerPsciReq64 { params } => {
2337                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2338                        a[3] = params[0];
2339                        a[4] = params[1];
2340                        a[5] = params[2];
2341                        a[6] = params[3];
2342                    }
2343                    DirectMsgArgs::PowerWarmBootReq { boot_type } => {
2344                        a[2] = DirectMsgArgs::POWER_WARM_BOOT_REQ.into();
2345                        a[3] = u32::from(boot_type).into();
2346                    }
2347                    DirectMsgArgs::VmCreated { handle, vm_id } => {
2348                        a[2] = DirectMsgArgs::VM_CREATED.into();
2349                        let handle_regs: [u32; 2] = handle.into();
2350                        a[3] = handle_regs[0].into();
2351                        a[4] = handle_regs[1].into();
2352                        a[5] = vm_id.into();
2353                    }
2354                    DirectMsgArgs::VmDestructed { handle, vm_id } => {
2355                        a[2] = DirectMsgArgs::VM_DESTRUCTED.into();
2356                        let handle_regs: [u32; 2] = handle.into();
2357                        a[3] = handle_regs[0].into();
2358                        a[4] = handle_regs[1].into();
2359                        a[5] = vm_id.into();
2360                    }
2361                    _ => panic!("Malformed MsgSendDirectReq interface"),
2362                }
2363            }
2364            Interface::MsgSendDirectResp {
2365                src_id,
2366                dst_id,
2367                args,
2368            } => {
2369                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2370                match args {
2371                    DirectMsgArgs::Args32(args) => {
2372                        a[3] = args[0].into();
2373                        a[4] = args[1].into();
2374                        a[5] = args[2].into();
2375                        a[6] = args[3].into();
2376                        a[7] = args[4].into();
2377                    }
2378                    DirectMsgArgs::Args64(args) => {
2379                        a[3] = args[0];
2380                        a[4] = args[1];
2381                        a[5] = args[2];
2382                        a[6] = args[3];
2383                        a[7] = args[4];
2384                    }
2385                    DirectMsgArgs::VersionResp { version } => {
2386                        a[2] = DirectMsgArgs::VERSION_RESP.into();
2387                        match version {
2388                            None => a[3] = (i32::from(FfaError::NotSupported) as u32).into(),
2389                            Some(ver) => a[3] = u32::from(ver).into(),
2390                        }
2391                    }
2392                    DirectMsgArgs::PowerPsciResp { psci_status } => {
2393                        a[2] = DirectMsgArgs::POWER_PSCI_RESP.into();
2394                        a[3] = (psci_status as u32).into();
2395                    }
2396                    DirectMsgArgs::VmCreatedAck { sp_status } => {
2397                        a[2] = DirectMsgArgs::VM_CREATED_ACK.into();
2398                        a[3] = (i32::from(sp_status) as u32).into();
2399                    }
2400                    DirectMsgArgs::VmDestructedAck { sp_status } => {
2401                        a[2] = DirectMsgArgs::VM_DESTRUCTED_ACK.into();
2402                        a[3] = (i32::from(sp_status) as u32).into();
2403                    }
2404                    _ => panic!("Malformed MsgSendDirectResp interface"),
2405                }
2406            }
2407            Interface::MemDonate {
2408                total_len,
2409                frag_len,
2410                buf,
2411            } => {
2412                a[1] = total_len.into();
2413                a[2] = frag_len.into();
2414                (a[3], a[4]) = match buf {
2415                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2416                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2417                    None => (0, 0),
2418                };
2419            }
2420            Interface::MemLend {
2421                total_len,
2422                frag_len,
2423                buf,
2424            } => {
2425                a[1] = total_len.into();
2426                a[2] = frag_len.into();
2427                (a[3], a[4]) = match buf {
2428                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2429                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2430                    None => (0, 0),
2431                };
2432            }
2433            Interface::MemShare {
2434                total_len,
2435                frag_len,
2436                buf,
2437            } => {
2438                a[1] = total_len.into();
2439                a[2] = frag_len.into();
2440                (a[3], a[4]) = match buf {
2441                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2442                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2443                    None => (0, 0),
2444                };
2445            }
2446            Interface::MemRetrieveReq {
2447                total_len,
2448                frag_len,
2449                buf,
2450            } => {
2451                a[1] = total_len.into();
2452                a[2] = frag_len.into();
2453                (a[3], a[4]) = match buf {
2454                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2455                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2456                    None => (0, 0),
2457                };
2458            }
2459            Interface::MemRetrieveResp {
2460                total_len,
2461                frag_len,
2462            } => {
2463                a[1] = total_len.into();
2464                a[2] = frag_len.into();
2465            }
2466            Interface::MemRelinquish => {}
2467            Interface::MemReclaim { handle, flags } => {
2468                let handle_regs: [u32; 2] = handle.into();
2469                a[1] = handle_regs[0].into();
2470                a[2] = handle_regs[1].into();
2471                a[3] = u32::from(flags).into();
2472            }
2473            Interface::MemPermGet { addr, page_cnt } => {
2474                a[1] = match addr {
2475                    MemAddr::Addr32(addr) => addr.into(),
2476                    MemAddr::Addr64(addr) => addr,
2477                };
2478                a[2] = if version <= Version(1, 2) {
2479                    assert_eq!(page_cnt, 1);
2480                    0
2481                } else {
2482                    assert_ne!(page_cnt, 0);
2483                    (page_cnt - 1).into()
2484                }
2485            }
2486            Interface::MemPermSet {
2487                addr,
2488                page_cnt,
2489                mem_perm,
2490            } => {
2491                a[1] = match addr {
2492                    MemAddr::Addr32(addr) => addr.into(),
2493                    MemAddr::Addr64(addr) => addr,
2494                };
2495                a[2] = page_cnt.into();
2496                a[3] = u32::from(mem_perm).into();
2497            }
2498            Interface::MemOpPause { handle } => {
2499                let handle_regs: [u32; 2] = handle.into();
2500                a[1] = handle_regs[0].into();
2501                a[2] = handle_regs[1].into();
2502            }
2503            Interface::MemOpResume { handle } => {
2504                let handle_regs: [u32; 2] = handle.into();
2505                a[1] = handle_regs[0].into();
2506                a[2] = handle_regs[1].into();
2507            }
2508            Interface::MemFragRx {
2509                handle,
2510                frag_offset,
2511                endpoint_id,
2512            } => {
2513                let handle_regs: [u32; 2] = handle.into();
2514                a[1] = handle_regs[0].into();
2515                a[2] = handle_regs[1].into();
2516                a[3] = frag_offset.into();
2517                a[4] = (u32::from(endpoint_id) << 16).into();
2518            }
2519            Interface::MemFragTx {
2520                handle,
2521                frag_len,
2522                endpoint_id,
2523            } => {
2524                let handle_regs: [u32; 2] = handle.into();
2525                a[1] = handle_regs[0].into();
2526                a[2] = handle_regs[1].into();
2527                a[3] = frag_len.into();
2528                a[4] = (u32::from(endpoint_id) << 16).into();
2529            }
2530            Interface::ConsoleLog { chars } => match chars {
2531                ConsoleLogChars::Chars32(ConsoleLogChars32 {
2532                    char_cnt,
2533                    char_lists,
2534                }) => {
2535                    a[1] = char_cnt.into();
2536                    a[2] = char_lists[0].into();
2537                    a[3] = char_lists[1].into();
2538                    a[4] = char_lists[2].into();
2539                    a[5] = char_lists[3].into();
2540                    a[6] = char_lists[4].into();
2541                    a[7] = char_lists[5].into();
2542                }
2543                _ => panic!("{:#x?} requires 18 registers", chars),
2544            },
2545            Interface::NotificationBitmapCreate { vm_id, vcpu_cnt } => {
2546                a[1] = vm_id.into();
2547                a[2] = vcpu_cnt.into();
2548            }
2549            Interface::NotificationBitmapDestroy { vm_id } => {
2550                a[1] = vm_id.into();
2551            }
2552            Interface::NotificationBind {
2553                sender_id,
2554                receiver_id,
2555                flags,
2556                bitmap,
2557            } => {
2558                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2559                a[2] = u32::from(flags).into();
2560                a[3] = bitmap & 0xffff_ffff;
2561                a[4] = bitmap >> 32;
2562            }
2563            Interface::NotificationUnbind {
2564                sender_id,
2565                receiver_id,
2566                bitmap,
2567            } => {
2568                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2569                a[3] = bitmap & 0xffff_ffff;
2570                a[4] = bitmap >> 32;
2571            }
2572            Interface::NotificationSet {
2573                sender_id,
2574                receiver_id,
2575                flags,
2576                bitmap,
2577            } => {
2578                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2579                a[2] = u32::from(flags).into();
2580                a[3] = bitmap & 0xffff_ffff;
2581                a[4] = bitmap >> 32;
2582            }
2583            Interface::NotificationGet {
2584                vcpu_id,
2585                endpoint_id,
2586                flags,
2587            } => {
2588                a[1] = (u64::from(vcpu_id) << 16) | u64::from(endpoint_id);
2589                a[2] = u32::from(flags).into();
2590            }
2591            Interface::NotificationInfoGet { .. } => {}
2592            Interface::El3IntrHandle => {}
2593            _ => panic!("{:#x?} requires 18 registers", self),
2594        }
2595    }
2596
2597    fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
2598        assert!(version >= Version(1, 2));
2599
2600        a.fill(0);
2601
2602        if let Some(function_id) = self.function_id() {
2603            a[0] = function_id as u64;
2604        }
2605
2606        match *self {
2607            Interface::Success { target_info, args } => {
2608                a[1] = u32::from(target_info).into();
2609                match args {
2610                    SuccessArgs::Args64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
2611                    _ => panic!("{:#x?} requires 8 registers", args),
2612                }
2613            }
2614            Interface::MsgSendDirectReq2 {
2615                src_id,
2616                dst_id,
2617                uuid,
2618                args,
2619            } => {
2620                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2621                [a[2], a[3]] = UuidHelper::to_u64_regs(uuid);
2622                a[4..18].copy_from_slice(&args.0[..14]);
2623            }
2624            Interface::MsgSendDirectResp2 {
2625                src_id,
2626                dst_id,
2627                args,
2628            } => {
2629                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2630                a[2] = 0;
2631                a[3] = 0;
2632                a[4..18].copy_from_slice(&args.0[..14]);
2633            }
2634            Interface::ConsoleLog { chars: char_lists } => match char_lists {
2635                ConsoleLogChars::Chars64(ConsoleLogChars64 {
2636                    char_cnt,
2637                    char_lists,
2638                }) => {
2639                    a[1] = char_cnt.into();
2640                    a[2..18].copy_from_slice(&char_lists[..16])
2641                }
2642                _ => panic!("{:#x?} requires 8 registers", char_lists),
2643            },
2644            Interface::PartitionInfoGetRegs {
2645                uuid,
2646                start_index,
2647                info_tag,
2648            } => {
2649                if start_index == 0 && info_tag != 0 {
2650                    panic!("Information Tag MBZ if start index is 0: {:#x?}", self);
2651                }
2652                [a[1], a[2]] = UuidHelper::to_u64_regs(uuid);
2653                a[3] = (u64::from(info_tag) << 16) | u64::from(start_index);
2654            }
2655            _ => panic!("{:#x?} requires 8 registers", self),
2656        }
2657    }
2658
2659    /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
2660    pub fn success32_noargs() -> Self {
2661        Self::Success {
2662            target_info: TargetInfo::default(),
2663            args: SuccessArgs::Args32([0; 6]),
2664        }
2665    }
2666
2667    /// Helper function to create an `FFA_ERROR` interface with an error code.
2668    pub fn error(error_code: FfaError) -> Self {
2669        Self::Error {
2670            target_info: TargetInfo::default(),
2671            error_code,
2672            error_arg: 0,
2673        }
2674    }
2675}
2676
2677#[cfg(test)]
2678mod tests {
2679    use uuid::uuid;
2680
2681    use crate::{
2682        memory_management::Handle,
2683        partition_info::{SuccessArgsPartitionInfoGet, SuccessArgsPartitionInfoGetRegs},
2684    };
2685
2686    use super::*;
2687
2688    const fn error_code(code: i32) -> u64 {
2689        (code as u32) as u64
2690    }
2691
2692    #[test]
2693    fn version_reg_count() {
2694        assert!(!Version(1, 1).needs_18_regs());
2695        assert!(Version(1, 2).needs_18_regs())
2696    }
2697
2698    #[test]
2699    fn ffa_uuid_helpers() {
2700        const UUID: Uuid = uuid!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
2701
2702        let bytes = [
2703            0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
2704            0xd7, 0xd8,
2705        ];
2706
2707        assert_eq!(UUID, UuidHelper::from_bytes(bytes));
2708        assert_eq!(bytes, UuidHelper::to_bytes(UUID));
2709
2710        let words = [0xa4a3a2a1, 0xc2c1b2b1, 0xd4d3d2d1, 0xd8d7d6d5];
2711        assert_eq!(UUID, UuidHelper::from_u32_regs(words));
2712        assert_eq!(words, UuidHelper::to_u32_regs(UUID));
2713
2714        let pair = [0xc2c1b2b1a4a3a2a1, 0xd8d7d6d5d4d3d2d1];
2715        assert_eq!(UUID, UuidHelper::from_u64_regs(pair));
2716        assert_eq!(pair, UuidHelper::to_u64_regs(UUID));
2717    }
2718
2719    #[test]
2720    fn part_info_get_regs() {
2721        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2722        let uuid_bytes = uuid.as_bytes();
2723        let test_info_tag = 0b1101_1101;
2724        let test_start_index = 0b1101;
2725        let start_index_and_tag = (test_info_tag << 16) | test_start_index;
2726        let version = Version(1, 2);
2727
2728        // From spec:
2729        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2730        let reg_x1 = ((uuid_bytes[7] as u64) << 56)
2731            | ((uuid_bytes[6] as u64) << 48)
2732            | ((uuid_bytes[5] as u64) << 40)
2733            | ((uuid_bytes[4] as u64) << 32)
2734            | ((uuid_bytes[3] as u64) << 24)
2735            | ((uuid_bytes[2] as u64) << 16)
2736            | ((uuid_bytes[1] as u64) << 8)
2737            | (uuid_bytes[0] as u64);
2738
2739        // From spec:
2740        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2741        let reg_x2 = ((uuid_bytes[15] as u64) << 56)
2742            | ((uuid_bytes[14] as u64) << 48)
2743            | ((uuid_bytes[13] as u64) << 40)
2744            | ((uuid_bytes[12] as u64) << 32)
2745            | ((uuid_bytes[11] as u64) << 24)
2746            | ((uuid_bytes[10] as u64) << 16)
2747            | ((uuid_bytes[9] as u64) << 8)
2748            | (uuid_bytes[8] as u64);
2749
2750        // First, test for wrong tag:
2751        {
2752            let mut regs = [0u64; 18];
2753            regs[0] = FuncId::PartitionInfoGetRegs as u64;
2754            regs[1] = reg_x1;
2755            regs[2] = reg_x2;
2756            regs[3] = test_info_tag << 16;
2757
2758            assert!(Interface::from_regs(version, &regs).is_err_and(
2759                |e| e == Error::InvalidInformationTag(test_info_tag.try_into().unwrap())
2760            ));
2761        }
2762
2763        // Test for regs -> Interface -> regs
2764        {
2765            let mut orig_regs = [0u64; 18];
2766            orig_regs[0] = FuncId::PartitionInfoGetRegs as u64;
2767            orig_regs[1] = reg_x1;
2768            orig_regs[2] = reg_x2;
2769            orig_regs[3] = start_index_and_tag;
2770
2771            let mut test_regs = orig_regs;
2772            let interface = Interface::from_regs(version, &test_regs).unwrap();
2773            match &interface {
2774                Interface::PartitionInfoGetRegs {
2775                    info_tag,
2776                    start_index,
2777                    uuid: int_uuid,
2778                } => {
2779                    assert_eq!(u64::from(*info_tag), test_info_tag);
2780                    assert_eq!(u64::from(*start_index), test_start_index);
2781                    assert_eq!(*int_uuid, uuid);
2782                }
2783                _ => panic!("Expecting Interface::PartitionInfoGetRegs!"),
2784            }
2785            test_regs.fill(0);
2786            interface.to_regs(version, &mut test_regs);
2787            assert_eq!(orig_regs, test_regs);
2788        }
2789
2790        // Test for Interface -> regs -> Interface
2791        {
2792            let interface = Interface::PartitionInfoGetRegs {
2793                info_tag: test_info_tag.try_into().unwrap(),
2794                start_index: test_start_index.try_into().unwrap(),
2795                uuid,
2796            };
2797
2798            let mut regs: [u64; 18] = [0; 18];
2799            interface.to_regs(version, &mut regs);
2800
2801            assert_eq!(Some(FuncId::PartitionInfoGetRegs), interface.function_id());
2802            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2803            assert_eq!(regs[1], reg_x1);
2804            assert_eq!(regs[2], reg_x2);
2805            assert_eq!(regs[3], (test_info_tag << 16) | test_start_index);
2806
2807            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2808        }
2809    }
2810
2811    #[test]
2812    fn msg_send_direct_req2() {
2813        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2814        let uuid_bytes = uuid.as_bytes();
2815
2816        // From spec:
2817        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2818        let reg_x2 = ((uuid_bytes[7] as u64) << 56)
2819            | ((uuid_bytes[6] as u64) << 48)
2820            | ((uuid_bytes[5] as u64) << 40)
2821            | ((uuid_bytes[4] as u64) << 32)
2822            | ((uuid_bytes[3] as u64) << 24)
2823            | ((uuid_bytes[2] as u64) << 16)
2824            | ((uuid_bytes[1] as u64) << 8)
2825            | (uuid_bytes[0] as u64);
2826
2827        // From spec:
2828        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2829        let reg_x3 = ((uuid_bytes[15] as u64) << 56)
2830            | ((uuid_bytes[14] as u64) << 48)
2831            | ((uuid_bytes[13] as u64) << 40)
2832            | ((uuid_bytes[12] as u64) << 32)
2833            | ((uuid_bytes[11] as u64) << 24)
2834            | ((uuid_bytes[10] as u64) << 16)
2835            | ((uuid_bytes[9] as u64) << 8)
2836            | (uuid_bytes[8] as u64);
2837
2838        let test_sender = 0b1101_1101;
2839        let test_receiver = 0b1101;
2840        let test_sender_receiver = (test_sender << 16) | test_receiver;
2841        let version = Version(1, 2);
2842
2843        // Test for regs -> Interface -> regs
2844        {
2845            let mut orig_regs = [0u64; 18];
2846            orig_regs[0] = FuncId::MsgSendDirectReq64_2 as u64;
2847            orig_regs[1] = test_sender_receiver;
2848            orig_regs[2] = reg_x2;
2849            orig_regs[3] = reg_x3;
2850
2851            let mut test_regs = orig_regs;
2852            let interface = Interface::from_regs(version, &test_regs).unwrap();
2853            match &interface {
2854                Interface::MsgSendDirectReq2 {
2855                    dst_id,
2856                    src_id,
2857                    args: _,
2858                    uuid: int_uuid,
2859                } => {
2860                    assert_eq!(u64::from(*src_id), test_sender);
2861                    assert_eq!(u64::from(*dst_id), test_receiver);
2862                    assert_eq!(*int_uuid, uuid);
2863                }
2864                _ => panic!("Expecting Interface::MsgSendDirectReq2!"),
2865            }
2866            test_regs.fill(0);
2867            interface.to_regs(version, &mut test_regs);
2868            assert_eq!(orig_regs, test_regs);
2869        }
2870
2871        // Test for Interface -> regs -> Interface
2872        {
2873            let rest_of_regs: [u64; 14] = [0; 14];
2874
2875            let interface = Interface::MsgSendDirectReq2 {
2876                src_id: test_sender.try_into().unwrap(),
2877                dst_id: test_receiver.try_into().unwrap(),
2878                uuid,
2879                args: DirectMsg2Args(rest_of_regs),
2880            };
2881
2882            let mut regs: [u64; 18] = [0; 18];
2883            interface.to_regs(version, &mut regs);
2884
2885            assert_eq!(Some(FuncId::MsgSendDirectReq64_2), interface.function_id());
2886            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2887            assert_eq!(regs[1], test_sender_receiver);
2888            assert_eq!(regs[2], reg_x2);
2889            assert_eq!(regs[3], reg_x3);
2890            assert_eq!(regs[4], 0);
2891
2892            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2893        }
2894    }
2895
2896    #[test]
2897    fn is_32bit() {
2898        let interface_64 = Interface::MsgSendDirectReq {
2899            src_id: 0,
2900            dst_id: 1,
2901            args: DirectMsgArgs::Args64([0, 0, 0, 0, 0]),
2902        };
2903        assert!(!interface_64.is_32bit());
2904
2905        let interface_32 = Interface::MsgSendDirectReq {
2906            src_id: 0,
2907            dst_id: 1,
2908            args: DirectMsgArgs::Args32([0, 0, 0, 0, 0]),
2909        };
2910        assert!(interface_32.is_32bit());
2911    }
2912
2913    #[test]
2914    fn success_args_notification_info_get32() {
2915        let mut notifications = SuccessArgsNotificationInfoGet32::default();
2916
2917        // 16.7.1.1 Example usage
2918        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2919        notifications.add_list(0x0000, &[4, 6]).unwrap();
2920        notifications.add_list(0x0002, &[]).unwrap();
2921        notifications.add_list(0x0003, &[1]).unwrap();
2922
2923        let args: SuccessArgs = notifications.into();
2924        assert_eq!(
2925            SuccessArgs::Args32([
2926                0x0004_b200,
2927                0x0000_0000,
2928                0x0003_0002,
2929                0x0004_0000,
2930                0x0002_0006,
2931                0x0001_0003
2932            ]),
2933            args
2934        );
2935
2936        let notifications = SuccessArgsNotificationInfoGet32::try_from(args).unwrap();
2937        let mut iter = notifications.iter();
2938        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2939        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2940        assert_eq!(Some((0x0002, &[][..])), iter.next());
2941        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2942    }
2943
2944    #[test]
2945    fn success_args_notification_info_get64() {
2946        let mut notifications = SuccessArgsNotificationInfoGet64::default();
2947
2948        // 16.7.1.1 Example usage
2949        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2950        notifications.add_list(0x0000, &[4, 6]).unwrap();
2951        notifications.add_list(0x0002, &[]).unwrap();
2952        notifications.add_list(0x0003, &[1]).unwrap();
2953
2954        let args: SuccessArgs = notifications.into();
2955        assert_eq!(
2956            SuccessArgs::Args64([
2957                0x0004_b200,
2958                0x0003_0002_0000_0000,
2959                0x0002_0006_0004_0000,
2960                0x0000_0000_0001_0003,
2961                0x0000_0000_0000_0000,
2962                0x0000_0000_0000_0000,
2963            ]),
2964            args
2965        );
2966
2967        let notifications = SuccessArgsNotificationInfoGet64::try_from(args).unwrap();
2968        let mut iter = notifications.iter();
2969        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2970        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2971        assert_eq!(Some((0x0002, &[][..])), iter.next());
2972        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2973    }
2974
2975    #[test]
2976    fn mem_perm_get_pack() {
2977        let mut expected_regs = [0u64; 18];
2978        let mut out_regs = [0u64; 18];
2979
2980        expected_regs[0] = u32::from(FuncId::MemPermGet32).into();
2981        expected_regs[1] = 0xabcd;
2982        expected_regs[2] = 5;
2983
2984        Interface::MemPermGet {
2985            addr: MemAddr::Addr32(0xabcd),
2986            page_cnt: 6,
2987        }
2988        .to_regs(Version(1, 3), &mut out_regs);
2989
2990        assert_eq!(expected_regs, out_regs);
2991
2992        expected_regs[2] = 0;
2993
2994        Interface::MemPermGet {
2995            addr: MemAddr::Addr32(0xabcd),
2996            page_cnt: 1,
2997        }
2998        .to_regs(Version(1, 2), &mut out_regs);
2999
3000        assert_eq!(expected_regs, out_regs);
3001    }
3002
3003    #[test]
3004    #[should_panic]
3005    fn mem_perm_get_pack_fail1() {
3006        let mut out_regs = [0u64; 18];
3007        Interface::MemPermGet {
3008            addr: MemAddr::Addr32(0xabcd),
3009            page_cnt: 2,
3010        }
3011        .to_regs(Version(1, 2), &mut out_regs);
3012    }
3013
3014    #[test]
3015    #[should_panic]
3016    fn mem_perm_get_pack_fail2() {
3017        let mut out_regs = [0u64; 18];
3018        Interface::MemPermGet {
3019            addr: MemAddr::Addr32(0xabcd),
3020            page_cnt: 0,
3021        }
3022        .to_regs(Version(1, 3), &mut out_regs);
3023    }
3024
3025    #[test]
3026    fn mem_perm_get_unpack() {
3027        let mut in_regs = [0u64; 18];
3028
3029        in_regs[0] = u32::from(FuncId::MemPermGet32).into();
3030        in_regs[1] = 0xabcd;
3031        in_regs[2] = 5;
3032
3033        assert_eq!(
3034            Interface::from_regs(Version(1, 3), &in_regs),
3035            Ok(Interface::MemPermGet {
3036                addr: MemAddr::Addr32(0xabcd),
3037                page_cnt: 6,
3038            }),
3039        );
3040
3041        assert_eq!(
3042            Interface::from_regs(Version(1, 2), &in_regs),
3043            Err(Error::MemoryManagementError(
3044                memory_management::Error::InvalidPageCount
3045            )),
3046        );
3047
3048        in_regs[2] = 0;
3049
3050        assert_eq!(
3051            Interface::from_regs(Version(1, 2), &in_regs),
3052            Ok(Interface::MemPermGet {
3053                addr: MemAddr::Addr32(0xabcd),
3054                page_cnt: 1,
3055            }),
3056        );
3057
3058        in_regs[2] = u32::MAX.into();
3059
3060        assert_eq!(
3061            Interface::from_regs(Version(1, 3), &in_regs),
3062            Err(Error::MemoryManagementError(
3063                memory_management::Error::InvalidPageCount
3064            )),
3065        );
3066    }
3067
3068    macro_rules! test_regs_serde {
3069        ($value:expr, $bytes:expr) => {
3070            let mut regs = [0u64; 18];
3071            let mut bytes = [0u64; 18];
3072
3073            let b: &[u64] = &$bytes;
3074            bytes[0..(b.len())].copy_from_slice(&b);
3075
3076            $value.to_regs(Version(1, 2), &mut regs);
3077            assert_eq!(regs, bytes);
3078
3079            assert_eq!(Interface::from_regs(Version(1, 2), &bytes), Ok($value));
3080        };
3081    }
3082    pub(crate) use test_regs_serde;
3083
3084    macro_rules! test_args_serde {
3085        ($args:expr, $sa:expr) => {
3086            assert_eq!($args.try_into(), Ok($sa));
3087            assert_eq!($sa.try_into(), Ok($args));
3088        };
3089        ($args:expr, $sa:expr, $flags:expr) => {
3090            assert_eq!($args.try_into(), Ok($sa));
3091            assert_eq!(($flags, $sa).try_into(), Ok($args));
3092        };
3093    }
3094    pub(crate) use test_args_serde;
3095
3096    #[test]
3097    fn ffa_error_serde() {
3098        test_regs_serde!(
3099            Interface::Error {
3100                target_info: TargetInfo {
3101                    endpoint_id: 0x1234,
3102                    vcpu_id: 0xabcd
3103                },
3104                error_code: FfaError::Aborted,
3105                error_arg: 0xdead_beef
3106            },
3107            [0x84000060, 0x1234_abcd, error_code(-8), 0xdead_beef]
3108        );
3109    }
3110
3111    #[test]
3112    fn ffa_success_serde() {
3113        test_regs_serde!(
3114            Interface::Success {
3115                target_info: TargetInfo {
3116                    endpoint_id: 0x1234,
3117                    vcpu_id: 0xabcd
3118                },
3119                args: SuccessArgs::Args32([1, 2, 3, 4, 5, 6])
3120            },
3121            [0x84000061, 0x1234_abcd, 1, 2, 3, 4, 5, 6]
3122        );
3123        test_regs_serde!(
3124            Interface::Success {
3125                target_info: TargetInfo {
3126                    endpoint_id: 0x1234,
3127                    vcpu_id: 0xabcd
3128                },
3129                args: SuccessArgs::Args64_2([
3130                    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
3131                ])
3132            },
3133            [
3134                0xC4000061,
3135                0x1234_abcd,
3136                1,
3137                2,
3138                3,
3139                4,
3140                5,
3141                6,
3142                7,
3143                8,
3144                9,
3145                10,
3146                11,
3147                12,
3148                13,
3149                14,
3150                15,
3151                16
3152            ]
3153        );
3154    }
3155
3156    #[test]
3157    fn ffa_interrupt_serde() {
3158        test_regs_serde!(
3159            Interface::Interrupt {
3160                target_info: TargetInfo {
3161                    endpoint_id: 0x1234,
3162                    vcpu_id: 0xabcd
3163                },
3164                interrupt_id: 0xdead_beef
3165            },
3166            [0x84000062, 0x1234_abcd, 0xdead_beef]
3167        );
3168    }
3169
3170    #[test]
3171    fn ffa_version_serde() {
3172        test_regs_serde!(
3173            Interface::Version {
3174                input_version: Version(1, 2),
3175            },
3176            [0x84000063, 0x0001_0002]
3177        );
3178    }
3179
3180    #[test]
3181    fn ffa_feature_serde() {
3182        test_regs_serde!(
3183            Interface::Features {
3184                feat_id: Feature::FeatureId(FeatureId::NotificationPendingInterrupt),
3185                input_properties: 0
3186            },
3187            [0x84000064, 0x1]
3188        );
3189        test_regs_serde!(
3190            Interface::Features {
3191                feat_id: Feature::FeatureId(FeatureId::ScheduleReceiverInterrupt),
3192                input_properties: 0
3193            },
3194            [0x84000064, 0x2]
3195        );
3196        test_regs_serde!(
3197            Interface::Features {
3198                feat_id: Feature::FeatureId(FeatureId::ManagedExitInterrupt),
3199                input_properties: 0
3200            },
3201            [0x84000064, 0x3]
3202        );
3203        test_regs_serde!(
3204            Interface::Features {
3205                feat_id: Feature::FuncId(FuncId::Features),
3206                input_properties: 32
3207            },
3208            [0x84000064, 0x84000064, 32]
3209        );
3210        test_args_serde!(
3211            SuccessArgs::Args32([8, 8, 0, 0, 0, 0]),
3212            SuccessArgsFeatures { properties: [8, 8] }
3213        );
3214    }
3215
3216    #[test]
3217    fn ffa_rx_acquire_serde() {
3218        test_regs_serde!(Interface::RxAcquire { vm_id: 0xbeef }, [0x84000084, 0xbeef]);
3219    }
3220
3221    #[test]
3222    fn ffa_rx_release_serde() {
3223        test_regs_serde!(Interface::RxRelease { vm_id: 0xbeef }, [0x84000065, 0xbeef]);
3224    }
3225
3226    #[test]
3227    fn ffa_rxtx_map_serde() {
3228        test_regs_serde!(
3229            Interface::RxTxMap {
3230                addr: RxTxAddr::Addr32 {
3231                    rx: 0xbeef,
3232                    tx: 0xfeed_dead
3233                },
3234                page_cnt: 0x1234_abcd
3235            },
3236            [0x84000066, 0xfeed_dead, 0xbeef, 0x1234_abcd]
3237        );
3238        test_regs_serde!(
3239            Interface::RxTxMap {
3240                addr: RxTxAddr::Addr64 {
3241                    rx: 0xdead_1234_beef,
3242                    tx: 0xaaaa_bbbb_feed_dead
3243                },
3244                page_cnt: 0x1234_abcd
3245            },
3246            [
3247                0xC4000066,
3248                0xaaaa_bbbb_feed_dead,
3249                0xdead_1234_beef,
3250                0x1234_abcd
3251            ]
3252        );
3253    }
3254
3255    #[test]
3256    fn ffa_rxtx_unmap_serde() {
3257        test_regs_serde!(
3258            Interface::RxTxUnmap { id: 0x1234 },
3259            [0x84000067, 0x1234_0000]
3260        );
3261    }
3262
3263    #[test]
3264    fn ffa_partition_info_get_serde() {
3265        test_regs_serde!(
3266            Interface::PartitionInfoGet {
3267                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3268                flags: PartitionInfoGetFlags { count_only: false }
3269            },
3270            [0x84000068, 0x78563412, 0x12efcdab, 0x90785634, 0x00efcdab]
3271        );
3272        test_args_serde!(
3273            SuccessArgsPartitionInfoGet {
3274                count: 0x1234_5678,
3275                size: Some(0xabcd_beef)
3276            },
3277            SuccessArgs::Args32([0x1234_5678, 0xabcd_beef, 0, 0, 0, 0]),
3278            PartitionInfoGetFlags { count_only: false }
3279        );
3280        test_regs_serde!(
3281            Interface::PartitionInfoGet {
3282                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3283                flags: PartitionInfoGetFlags { count_only: true }
3284            },
3285            [0x84000068, 0x78563412, 0x12efcdab, 0x90785634, 0x00efcdab, 0b1]
3286        );
3287        test_args_serde!(
3288            SuccessArgsPartitionInfoGet {
3289                count: 0x1234_5678,
3290                size: None
3291            },
3292            SuccessArgs::Args32([0x1234_5678, 0, 0, 0, 0, 0]),
3293            PartitionInfoGetFlags { count_only: true }
3294        );
3295    }
3296
3297    #[test]
3298    fn ffa_partition_info_get_regs_serde() {
3299        test_regs_serde!(
3300            Interface::PartitionInfoGetRegs {
3301                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3302                start_index: 0xfeed,
3303                info_tag: 0xbeef
3304            },
3305            [
3306                0xC400008B,
3307                0x12ef_cdab_7856_3412,
3308                0x00ef_cdab_9078_5634,
3309                0xbeef_feed
3310            ]
3311        );
3312        test_args_serde!(
3313            SuccessArgs::Args64_2([
3314                0x0018_2222_0002_0004,
3315                0,
3316                0,
3317                0,
3318                0,
3319                0,
3320                0,
3321                0,
3322                0,
3323                0,
3324                0,
3325                0,
3326                0,
3327                0,
3328                0,
3329                0
3330            ]),
3331            SuccessArgsPartitionInfoGetRegs {
3332                last_index: 4,
3333                current_index: 2,
3334                info_tag: 0x2222,
3335                descriptor_data: [0; 120]
3336            }
3337        );
3338    }
3339
3340    #[test]
3341    fn ffa_id_get_serde() {
3342        test_regs_serde!(Interface::IdGet, [0x84000069]);
3343        test_args_serde!(
3344            SuccessArgs::Args32([0x1234, 0, 0, 0, 0, 0]),
3345            SuccessArgsIdGet { id: 0x1234 }
3346        );
3347    }
3348
3349    #[test]
3350    fn ffa_spm_id_get_serde() {
3351        test_regs_serde!(Interface::SpmIdGet, [0x84000085]);
3352        test_args_serde!(
3353            SuccessArgs::Args32([0x1234, 0, 0, 0, 0, 0]),
3354            SuccessArgsSpmIdGet { id: 0x1234 }
3355        );
3356    }
3357
3358    #[test]
3359    fn ffa_console_log_serde() {
3360        test_regs_serde!(
3361            Interface::ConsoleLog {
3362                chars: ConsoleLogChars::Chars32(LogChars {
3363                    char_cnt: 8,
3364                    char_lists: [0x6566_6768, 0x6970_7172, 0, 0, 0, 0,]
3365                })
3366            },
3367            [0x8400008A, 8, 0x6566_6768, 0x6970_7172]
3368        );
3369        test_regs_serde!(
3370            Interface::ConsoleLog {
3371                chars: ConsoleLogChars::Chars64(LogChars {
3372                    char_cnt: 8,
3373                    char_lists: [
3374                        0x6566_6768_6970_7172,
3375                        0,
3376                        0,
3377                        0,
3378                        0,
3379                        0,
3380                        0,
3381                        0,
3382                        0,
3383                        0,
3384                        0,
3385                        0,
3386                        0,
3387                        0,
3388                        0,
3389                        0
3390                    ]
3391                })
3392            },
3393            [0xC400008A, 8, 0x6566_6768_6970_7172]
3394        );
3395    }
3396
3397    #[test]
3398    fn ffa_msg_send2_serde() {
3399        test_regs_serde!(
3400            Interface::MsgSend2 {
3401                sender_vm_id: 0xfeed,
3402                flags: MsgSend2Flags {
3403                    delay_schedule_receiver: true
3404                }
3405            },
3406            [0x84000086, 0xfeed_0000, 0b10]
3407        );
3408    }
3409
3410    #[test]
3411    fn ffa_msg_send_direct_req_serde() {
3412        test_regs_serde!(
3413            Interface::MsgSendDirectReq {
3414                src_id: 0x8005,
3415                dst_id: 0x8003,
3416                args: DirectMsgArgs::Args32([1, 2, 3, 4, 5])
3417            },
3418            [0x8400006F, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3419        );
3420
3421        test_regs_serde!(
3422            Interface::MsgSendDirectReq {
3423                src_id: 0x8005,
3424                dst_id: 0x8003,
3425                args: DirectMsgArgs::Args64([1, 2, 3, 4, 5])
3426            },
3427            [0xC400006F, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3428        );
3429    }
3430
3431    #[test]
3432    fn ffa_msg_send_direct_resp_serde() {
3433        test_regs_serde!(
3434            Interface::MsgSendDirectResp {
3435                src_id: 0x8005,
3436                dst_id: 0x8003,
3437                args: DirectMsgArgs::Args32([1, 2, 3, 4, 5])
3438            },
3439            [0x84000070, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3440        );
3441
3442        test_regs_serde!(
3443            Interface::MsgSendDirectResp {
3444                src_id: 0x8005,
3445                dst_id: 0x8003,
3446                args: DirectMsgArgs::Args64([1, 2, 3, 4, 5])
3447            },
3448            [0xC4000070, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3449        );
3450    }
3451
3452    #[test]
3453    fn ffa_psci_req_serde() {
3454        test_regs_serde!(
3455            Interface::MsgSendDirectReq {
3456                src_id: 0xdead,
3457                dst_id: 0xbeef,
3458                args: DirectMsgArgs::PowerPsciReq32 {
3459                    params: [1, 2, 3, 4]
3460                }
3461            },
3462            [0x8400006F, 0xdead_beef, 0x8000_0000, 1, 2, 3, 4]
3463        );
3464        test_regs_serde!(
3465            Interface::MsgSendDirectReq {
3466                src_id: 0xdead,
3467                dst_id: 0xbeef,
3468                args: DirectMsgArgs::PowerPsciReq64 {
3469                    params: [0x1234_5678_90ab_cdef, 2, 3, 4]
3470                }
3471            },
3472            [
3473                0xC400006F,
3474                0xdead_beef,
3475                0x8000_0000,
3476                0x1234_5678_90ab_cdef,
3477                2,
3478                3,
3479                4
3480            ]
3481        );
3482    }
3483
3484    #[test]
3485    fn ffa_power_warm_boot_req_serde() {
3486        test_regs_serde!(
3487            Interface::MsgSendDirectReq {
3488                src_id: 0xdead,
3489                dst_id: 0xbeef,
3490                args: DirectMsgArgs::PowerWarmBootReq {
3491                    boot_type: WarmBootType::ExitFromLowPower
3492                }
3493            },
3494            [0x8400006F, 0xdead_beef, 0x80000001, 0b1]
3495        );
3496        test_regs_serde!(
3497            Interface::MsgSendDirectReq {
3498                src_id: 0xdead,
3499                dst_id: 0xbeef,
3500                args: DirectMsgArgs::PowerWarmBootReq {
3501                    boot_type: WarmBootType::ExitFromSuspend
3502                }
3503            },
3504            [0x8400006F, 0xdead_beef, 0x80000001, 0b0]
3505        );
3506    }
3507
3508    #[test]
3509    fn ffa_power_resp_serde() {
3510        test_regs_serde!(
3511            Interface::MsgSendDirectResp {
3512                src_id: 0xdead,
3513                dst_id: 0xbeef,
3514                args: DirectMsgArgs::PowerPsciResp {
3515                    psci_status: 0x1234
3516                }
3517            },
3518            [0x84000070, 0xdead_beef, 0x8000_0002, 0x1234]
3519        );
3520    }
3521
3522    #[test]
3523    fn ffa_vm_creation_req() {
3524        test_regs_serde!(
3525            Interface::MsgSendDirectReq {
3526                src_id: 0xdead,
3527                dst_id: 0xbeef,
3528                args: DirectMsgArgs::VmCreated {
3529                    handle: Handle(0x1234_5678_90ab_cdef),
3530                    vm_id: 0x1234
3531                }
3532            },
3533            [
3534                0x8400006F,
3535                0xdead_beef,
3536                0x8000_0004,
3537                0x90ab_cdef,
3538                0x1234_5678,
3539                0x1234
3540            ]
3541        );
3542    }
3543
3544    #[test]
3545    fn ffa_vm_creation_resp() {
3546        test_regs_serde!(
3547            Interface::MsgSendDirectResp {
3548                src_id: 0xdead,
3549                dst_id: 0xbeef,
3550                args: DirectMsgArgs::VmCreatedAck {
3551                    sp_status: VmAvailabilityStatus::Success
3552                }
3553            },
3554            [0x84000070, 0xdead_beef, 0x8000_0005]
3555        );
3556        test_regs_serde!(
3557            Interface::MsgSendDirectResp {
3558                src_id: 0xdead,
3559                dst_id: 0xbeef,
3560                args: DirectMsgArgs::VmCreatedAck {
3561                    sp_status: VmAvailabilityStatus::Error(FfaError::Retry)
3562                }
3563            },
3564            [0x84000070, 0xdead_beef, 0x8000_0005, error_code(-7)]
3565        );
3566    }
3567
3568    #[test]
3569    fn ffa_vm_destruction_req() {
3570        test_regs_serde!(
3571            Interface::MsgSendDirectReq {
3572                src_id: 0xdead,
3573                dst_id: 0xbeef,
3574                args: DirectMsgArgs::VmDestructed {
3575                    handle: Handle(0x1234_5678_90ab_cdef),
3576                    vm_id: 0x1234
3577                }
3578            },
3579            [
3580                0x8400006F,
3581                0xdead_beef,
3582                0x8000_0006,
3583                0x90ab_cdef,
3584                0x1234_5678,
3585                0x1234
3586            ]
3587        );
3588    }
3589
3590    #[test]
3591    fn ffa_vm_destruction_resp() {
3592        test_regs_serde!(
3593            Interface::MsgSendDirectResp {
3594                src_id: 0xdead,
3595                dst_id: 0xbeef,
3596                args: DirectMsgArgs::VmDestructedAck {
3597                    sp_status: VmAvailabilityStatus::Success
3598                }
3599            },
3600            [0x84000070, 0xdead_beef, 0x8000_0007]
3601        );
3602        test_regs_serde!(
3603            Interface::MsgSendDirectResp {
3604                src_id: 0xdead,
3605                dst_id: 0xbeef,
3606                args: DirectMsgArgs::VmDestructedAck {
3607                    sp_status: VmAvailabilityStatus::Error(FfaError::Denied)
3608                }
3609            },
3610            [0x84000070, 0xdead_beef, 0x8000_0007, error_code(-6)]
3611        );
3612    }
3613
3614    #[test]
3615    fn ffa_version_req() {
3616        test_regs_serde!(
3617            Interface::MsgSendDirectReq {
3618                src_id: 0xdead,
3619                dst_id: 0xbeef,
3620                args: DirectMsgArgs::VersionReq {
3621                    version: Version(1, 2)
3622                }
3623            },
3624            [0x8400006F, 0xdead_beef, 0x8000_0008, 0x0001_0002]
3625        );
3626    }
3627
3628    #[test]
3629    fn ffa_version_resp() {
3630        test_regs_serde!(
3631            Interface::MsgSendDirectResp {
3632                src_id: 0xdead,
3633                dst_id: 0xbeef,
3634                args: DirectMsgArgs::VersionResp {
3635                    version: Some(Version(1, 2))
3636                }
3637            },
3638            [0x84000070, 0xdead_beef, 0x8000_0009, 0x0001_0002]
3639        );
3640        test_regs_serde!(
3641            Interface::MsgSendDirectResp {
3642                src_id: 0xdead,
3643                dst_id: 0xbeef,
3644                args: DirectMsgArgs::VersionResp { version: None }
3645            },
3646            [0x84000070, 0xdead_beef, 0x8000_0009, u32::MAX as u64]
3647        );
3648    }
3649
3650    #[test]
3651    fn ffa_msg_send_direct_req2_serde() {
3652        test_regs_serde!(
3653            Interface::MsgSendDirectReq2 {
3654                src_id: 0x1234,
3655                dst_id: 0xdcba,
3656                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3657                args: DirectMsg2Args([4; 14])
3658            },
3659            [
3660                0xC400008D,
3661                0x1234_dcba,
3662                0x12ef_cdab_7856_3412,
3663                0x00ef_cdab_9078_5634,
3664                4,
3665                4,
3666                4,
3667                4,
3668                4,
3669                4,
3670                4,
3671                4,
3672                4,
3673                4,
3674                4,
3675                4,
3676                4,
3677                4,
3678            ]
3679        );
3680    }
3681
3682    #[test]
3683    fn ffa_msg_send_direct_resp2_serde() {
3684        test_regs_serde!(
3685            Interface::MsgSendDirectResp2 {
3686                src_id: 0xaaaa,
3687                dst_id: 0xbbbb,
3688                args: DirectMsg2Args([8; 14])
3689            },
3690            [
3691                0xC400008E,
3692                0xaaaa_bbbb,
3693                0,
3694                0,
3695                8,
3696                8,
3697                8,
3698                8,
3699                8,
3700                8,
3701                8,
3702                8,
3703                8,
3704                8,
3705                8,
3706                8,
3707                8,
3708                8
3709            ]
3710        );
3711    }
3712
3713    #[test]
3714    fn ffa_msg_wait_serde() {
3715        test_regs_serde!(
3716            Interface::MsgWait {
3717                flags: Some(MsgWaitFlags {
3718                    retain_rx_buffer: true
3719                })
3720            },
3721            [0x8400006B, 0, 0b1]
3722        );
3723    }
3724
3725    #[test]
3726    fn ffa_yield_serde() {
3727        test_regs_serde!(Interface::Yield, [0x8400006C]);
3728    }
3729
3730    #[test]
3731    fn ffa_run_serde() {
3732        test_regs_serde!(
3733            Interface::Run {
3734                target_info: TargetInfo {
3735                    endpoint_id: 0xaaaa,
3736                    vcpu_id: 0x1234
3737                }
3738            },
3739            [0x8400006D, 0xaaaa_1234]
3740        );
3741    }
3742
3743    #[test]
3744    fn ffa_normal_world_resume_serde() {
3745        test_regs_serde!(Interface::NormalWorldResume, [0x8400007C]);
3746    }
3747
3748    #[test]
3749    fn ffa_notification_bitmap_create_serde() {
3750        test_regs_serde!(
3751            Interface::NotificationBitmapCreate {
3752                vm_id: 0xabcd,
3753                vcpu_cnt: 16
3754            },
3755            [0x8400007D, 0xabcd, 16]
3756        );
3757    }
3758
3759    #[test]
3760    fn ffa_notification_bitmap_destroy_serde() {
3761        test_regs_serde!(
3762            Interface::NotificationBitmapDestroy { vm_id: 0xabcd },
3763            [0x8400007E, 0xabcd]
3764        );
3765    }
3766
3767    #[test]
3768    fn ffa_notification_bind_serde() {
3769        test_regs_serde!(
3770            Interface::NotificationBind {
3771                sender_id: 0xdead,
3772                receiver_id: 0xbeef,
3773                flags: NotificationBindFlags {
3774                    per_vcpu_notification: true
3775                },
3776                bitmap: 0x1234_abcd_5678_def0
3777            },
3778            [0x8400007F, 0xdead_beef, 0b1, 0x5678_def0, 0x1234_abcd]
3779        );
3780    }
3781
3782    #[test]
3783    fn ffa_notification_unbind_serde() {
3784        test_regs_serde!(
3785            Interface::NotificationUnbind {
3786                sender_id: 0xaaaa,
3787                receiver_id: 0xbbbb,
3788                bitmap: 0x1234_abcd_5678_def0
3789            },
3790            [0x84000080, 0xaaaa_bbbb, 0, 0x5678_def0, 0x1234_abcd]
3791        );
3792    }
3793
3794    #[test]
3795    fn ffa_notification_set_serde() {
3796        test_regs_serde!(
3797            Interface::NotificationSet {
3798                sender_id: 0xaaaa,
3799                receiver_id: 0xbbbb,
3800                flags: NotificationSetFlags {
3801                    delay_schedule_receiver: true,
3802                    vcpu_id: Some(7)
3803                },
3804                bitmap: 0x1234_abcd_5678_def0
3805            },
3806            [
3807                0x84000081,
3808                0xaaaa_bbbb,
3809                0x0007_0003,
3810                0x5678_def0,
3811                0x1234_abcd
3812            ]
3813        );
3814        test_regs_serde!(
3815            Interface::NotificationSet {
3816                sender_id: 0xaaaa,
3817                receiver_id: 0xbbbb,
3818                flags: NotificationSetFlags {
3819                    delay_schedule_receiver: false,
3820                    vcpu_id: None
3821                },
3822                bitmap: 0x1234_abcd_5678_def0
3823            },
3824            [0x84000081, 0xaaaa_bbbb, 0, 0x5678_def0, 0x1234_abcd]
3825        );
3826    }
3827
3828    #[test]
3829    fn ffa_notification_get_serde() {
3830        test_regs_serde!(
3831            Interface::NotificationGet {
3832                vcpu_id: 13,
3833                endpoint_id: 0x1234,
3834                flags: NotificationGetFlags {
3835                    sp_bitmap_id: false,
3836                    vm_bitmap_id: true,
3837                    spm_bitmap_id: true,
3838                    hyp_bitmap_id: false
3839                }
3840            },
3841            [0x84000082, 0x000d_1234, 0b0110]
3842        );
3843        test_regs_serde!(
3844            Interface::NotificationGet {
3845                vcpu_id: 13,
3846                endpoint_id: 0x1234,
3847                flags: NotificationGetFlags {
3848                    sp_bitmap_id: false,
3849                    vm_bitmap_id: false,
3850                    spm_bitmap_id: false,
3851                    hyp_bitmap_id: false
3852                }
3853            },
3854            [0x84000082, 0x000d_1234, 0b0000]
3855        );
3856        test_regs_serde!(
3857            Interface::NotificationGet {
3858                vcpu_id: 13,
3859                endpoint_id: 0x1234,
3860                flags: NotificationGetFlags {
3861                    sp_bitmap_id: true,
3862                    vm_bitmap_id: true,
3863                    spm_bitmap_id: true,
3864                    hyp_bitmap_id: true
3865                }
3866            },
3867            [0x84000082, 0x000d_1234, 0b1111]
3868        );
3869
3870        test_args_serde!(
3871            SuccessArgsNotificationGet {
3872                sp_notifications: None,
3873                vm_notifications: None,
3874                spm_notifications: None,
3875                hypervisor_notifications: None
3876            },
3877            SuccessArgs::Args32([0, 0, 0, 0, 0, 0]),
3878            NotificationGetFlags {
3879                sp_bitmap_id: false,
3880                vm_bitmap_id: false,
3881                spm_bitmap_id: false,
3882                hyp_bitmap_id: false
3883            }
3884        );
3885        test_args_serde!(
3886            SuccessArgsNotificationGet {
3887                sp_notifications: None,
3888                vm_notifications: Some(0xdead_beef_1234_1234),
3889                spm_notifications: None,
3890                hypervisor_notifications: Some(0x1234_5678)
3891            },
3892            SuccessArgs::Args32([0, 0, 0x1234_1234, 0xdead_beef, 0, 0x1234_5678]),
3893            NotificationGetFlags {
3894                sp_bitmap_id: false,
3895                vm_bitmap_id: true,
3896                spm_bitmap_id: false,
3897                hyp_bitmap_id: true
3898            }
3899        );
3900
3901        test_args_serde!(
3902            SuccessArgsNotificationGet {
3903                sp_notifications: Some(0x1000),
3904                vm_notifications: Some(0xdead_beef_1234_1234),
3905                spm_notifications: Some(0x2000),
3906                hypervisor_notifications: Some(0x1234_5678)
3907            },
3908            SuccessArgs::Args32([0x1000, 0, 0x1234_1234, 0xdead_beef, 0x2000, 0x1234_5678]),
3909            NotificationGetFlags {
3910                sp_bitmap_id: true,
3911                vm_bitmap_id: true,
3912                spm_bitmap_id: true,
3913                hyp_bitmap_id: true
3914            }
3915        );
3916    }
3917
3918    #[test]
3919    fn ffa_notification_info_get_serde() {
3920        test_regs_serde!(
3921            Interface::NotificationInfoGet { is_32bit: true },
3922            [0x84000083]
3923        );
3924        test_regs_serde!(
3925            Interface::NotificationInfoGet { is_32bit: false },
3926            [0xC4000083]
3927        );
3928        test_args_serde!(
3929            SuccessArgs::Args32([0b1001_0001_0000_0001, 0xbbbb_cccc, 0xaaaa, 0, 0, 0]),
3930            SuccessArgsNotificationInfoGet {
3931                more_pending_notifications: true,
3932                list_count: 2,
3933                id_counts: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0],
3934                ids: [0xcccc, 0xbbbb, 0xaaaa, 0, 0, 0, 0, 0, 0, 0]
3935            }
3936        );
3937    }
3938
3939    #[test]
3940    fn log_chars_empty() {
3941        assert!(ConsoleLogChars64 {
3942            char_cnt: 0,
3943            char_lists: [0; 16]
3944        }
3945        .empty())
3946    }
3947
3948    #[test]
3949    fn log_chars_push() {
3950        let mut console = ConsoleLogChars64 {
3951            char_cnt: 0,
3952            char_lists: [0; 16],
3953        };
3954
3955        assert_eq!(console.push("hello world!".as_bytes()), 12);
3956
3957        assert_eq!(console.char_cnt, 12);
3958        assert_eq!(&console.bytes()[0..12], "hello world!".as_bytes());
3959        assert!(!console.empty());
3960    }
3961
3962    #[test]
3963    fn log_chars_full() {
3964        let mut console = ConsoleLogChars64 {
3965            char_cnt: 0,
3966            char_lists: [0; 16],
3967        };
3968
3969        assert_eq!(console.push(&[97; 128]), 128);
3970
3971        assert!(console.full());
3972    }
3973
3974    #[test]
3975    fn success_args_invalid_variants() {
3976        assert!(SuccessArgs::Args32([0; 6]).try_get_args64_2().is_err());
3977        assert!(SuccessArgs::Args64([0; 6]).try_get_args64_2().is_err());
3978
3979        assert!(SuccessArgs::Args64([0; 6]).try_get_args32().is_err());
3980        assert!(SuccessArgs::Args64_2([0; 16]).try_get_args32().is_err());
3981
3982        assert!(SuccessArgs::Args32([0; 6]).try_get_args64().is_err());
3983        assert!(SuccessArgs::Args64_2([0; 16]).try_get_args64().is_err());
3984    }
3985
3986    #[test]
3987    fn ffa_el3_intr_handle_serde() {
3988        test_regs_serde!(Interface::El3IntrHandle, [0x8400008C]);
3989    }
3990
3991    #[test]
3992    fn ffa_secondary_ep_regs32() {
3993        test_regs_serde!(
3994            Interface::SecondaryEpRegister {
3995                entrypoint: SecondaryEpRegisterAddr::Addr32(0xdead_beef)
3996            },
3997            [0x84000087, 0xdead_beef]
3998        );
3999    }
4000
4001    #[test]
4002    fn ffa_secondary_ep_regs64() {
4003        test_regs_serde!(
4004            Interface::SecondaryEpRegister {
4005                entrypoint: SecondaryEpRegisterAddr::Addr64(0x1234_5678_90ab_cdef)
4006            },
4007            [0xC4000087, 0x1234_5678_90ab_cdef]
4008        );
4009    }
4010}