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)]
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        let msg = match reg_cnt {
1643            8 => {
1644                assert!(version <= Version(1, 1));
1645                Interface::unpack_regs8(version, 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, regs.try_into().unwrap())?
1656                    }
1657                    _ => Interface::unpack_regs8(version, 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        Ok(msg)
1667    }
1668
1669    fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
1670        let fid = FuncId::try_from(regs[0] as u32)?;
1671
1672        let msg = match fid {
1673            FuncId::Error => Self::Error {
1674                target_info: (regs[1] as u32).into(),
1675                error_code: FfaError::try_from(regs[2] as i32)?,
1676                error_arg: regs[3] as u32,
1677            },
1678            FuncId::Success32 => Self::Success {
1679                target_info: (regs[1] as u32).into(),
1680                args: SuccessArgs::Args32([
1681                    regs[2] as u32,
1682                    regs[3] as u32,
1683                    regs[4] as u32,
1684                    regs[5] as u32,
1685                    regs[6] as u32,
1686                    regs[7] as u32,
1687                ]),
1688            },
1689            FuncId::Success64 => Self::Success {
1690                target_info: (regs[1] as u32).into(),
1691                args: SuccessArgs::Args64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
1692            },
1693            FuncId::Interrupt => Self::Interrupt {
1694                target_info: (regs[1] as u32).into(),
1695                interrupt_id: regs[2] as u32,
1696            },
1697            FuncId::Version => Self::Version {
1698                input_version: (regs[1] as u32).try_into()?,
1699            },
1700            FuncId::Features => Self::Features {
1701                feat_id: (regs[1] as u32).into(),
1702                input_properties: regs[2] as u32,
1703            },
1704            FuncId::RxAcquire => Self::RxAcquire {
1705                vm_id: regs[1] as u16,
1706            },
1707            FuncId::RxRelease => Self::RxRelease {
1708                vm_id: regs[1] as u16,
1709            },
1710            FuncId::RxTxMap32 => {
1711                let addr = RxTxAddr::Addr32 {
1712                    rx: regs[2] as u32,
1713                    tx: regs[1] as u32,
1714                };
1715                let page_cnt = regs[3] as u32;
1716
1717                Self::RxTxMap { addr, page_cnt }
1718            }
1719            FuncId::RxTxMap64 => {
1720                let addr = RxTxAddr::Addr64 {
1721                    rx: regs[2],
1722                    tx: regs[1],
1723                };
1724                let page_cnt = regs[3] as u32;
1725
1726                Self::RxTxMap { addr, page_cnt }
1727            }
1728            FuncId::RxTxUnmap => Self::RxTxUnmap {
1729                id: (regs[1] >> 16) as u16,
1730            },
1731            FuncId::PartitionInfoGet => {
1732                let uuid_words = [
1733                    regs[1] as u32,
1734                    regs[2] as u32,
1735                    regs[3] as u32,
1736                    regs[4] as u32,
1737                ];
1738
1739                Self::PartitionInfoGet {
1740                    uuid: UuidHelper::from_u32_regs(uuid_words),
1741                    flags: PartitionInfoGetFlags::try_from(regs[5] as u32)?,
1742                }
1743            }
1744            FuncId::IdGet => Self::IdGet,
1745            FuncId::SpmIdGet => Self::SpmIdGet,
1746            FuncId::MsgWait => Self::MsgWait {
1747                flags: if version >= Version(1, 2) {
1748                    Some(MsgWaitFlags::try_from(regs[2] as u32)?)
1749                } else {
1750                    None
1751                },
1752            },
1753            FuncId::Yield => Self::Yield,
1754            FuncId::Run => Self::Run {
1755                target_info: (regs[1] as u32).into(),
1756            },
1757            FuncId::NormalWorldResume => Self::NormalWorldResume,
1758            FuncId::SecondaryEpRegister32 => Self::SecondaryEpRegister {
1759                entrypoint: SecondaryEpRegisterAddr::Addr32(regs[1] as u32),
1760            },
1761            FuncId::SecondaryEpRegister64 => Self::SecondaryEpRegister {
1762                entrypoint: SecondaryEpRegisterAddr::Addr64(regs[1]),
1763            },
1764            FuncId::MsgSend2 => Self::MsgSend2 {
1765                sender_vm_id: (regs[1] >> 16) as u16,
1766                flags: (regs[2] as u32).try_into()?,
1767            },
1768            FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
1769                src_id: (regs[1] >> 16) as u16,
1770                dst_id: regs[1] as u16,
1771                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1772                    match regs[2] as u32 {
1773                        DirectMsgArgs::VERSION_REQ => DirectMsgArgs::VersionReq {
1774                            version: Version::try_from(regs[3] as u32)?,
1775                        },
1776                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq32 {
1777                            params: [
1778                                regs[3] as u32,
1779                                regs[4] as u32,
1780                                regs[5] as u32,
1781                                regs[6] as u32,
1782                            ],
1783                        },
1784                        DirectMsgArgs::POWER_WARM_BOOT_REQ => DirectMsgArgs::PowerWarmBootReq {
1785                            boot_type: WarmBootType::try_from(regs[3] as u32)?,
1786                        },
1787                        DirectMsgArgs::VM_CREATED => DirectMsgArgs::VmCreated {
1788                            handle: memory_management::Handle::from([
1789                                regs[3] as u32,
1790                                regs[4] as u32,
1791                            ]),
1792                            vm_id: regs[5] as u16,
1793                        },
1794                        DirectMsgArgs::VM_DESTRUCTED => DirectMsgArgs::VmDestructed {
1795                            handle: memory_management::Handle::from([
1796                                regs[3] as u32,
1797                                regs[4] as u32,
1798                            ]),
1799                            vm_id: regs[5] as u16,
1800                        },
1801                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1802                    }
1803                } else {
1804                    DirectMsgArgs::Args32([
1805                        regs[3] as u32,
1806                        regs[4] as u32,
1807                        regs[5] as u32,
1808                        regs[6] as u32,
1809                        regs[7] as u32,
1810                    ])
1811                },
1812            },
1813            FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
1814                src_id: (regs[1] >> 16) as u16,
1815                dst_id: regs[1] as u16,
1816                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1817                    match regs[2] as u32 {
1818                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq64 {
1819                            params: [regs[3], regs[4], regs[5], regs[6]],
1820                        },
1821                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1822                    }
1823                } else {
1824                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1825                },
1826            },
1827            FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
1828                src_id: (regs[1] >> 16) as u16,
1829                dst_id: regs[1] as u16,
1830                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1831                    match regs[2] as u32 {
1832                        DirectMsgArgs::VERSION_RESP => {
1833                            if regs[3] as i32 == FfaError::NotSupported.into() {
1834                                DirectMsgArgs::VersionResp { version: None }
1835                            } else {
1836                                DirectMsgArgs::VersionResp {
1837                                    version: Some(Version::try_from(regs[3] as u32)?),
1838                                }
1839                            }
1840                        }
1841                        DirectMsgArgs::POWER_PSCI_RESP => DirectMsgArgs::PowerPsciResp {
1842                            psci_status: regs[3] as i32,
1843                        },
1844                        DirectMsgArgs::VM_CREATED_ACK => DirectMsgArgs::VmCreatedAck {
1845                            sp_status: (regs[3] as i32).try_into()?,
1846                        },
1847                        DirectMsgArgs::VM_DESTRUCTED_ACK => DirectMsgArgs::VmDestructedAck {
1848                            sp_status: (regs[3] as i32).try_into()?,
1849                        },
1850                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1851                    }
1852                } else {
1853                    DirectMsgArgs::Args32([
1854                        regs[3] as u32,
1855                        regs[4] as u32,
1856                        regs[5] as u32,
1857                        regs[6] as u32,
1858                        regs[7] as u32,
1859                    ])
1860                },
1861            },
1862            FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
1863                src_id: (regs[1] >> 16) as u16,
1864                dst_id: regs[1] as u16,
1865                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1866                    return Err(Error::UnrecognisedFwkMsg(regs[2] as u32));
1867                } else {
1868                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1869                },
1870            },
1871            FuncId::MemDonate32 => Self::MemDonate {
1872                total_len: regs[1] as u32,
1873                frag_len: regs[2] as u32,
1874                buf: if regs[3] != 0 && regs[4] != 0 {
1875                    Some(MemOpBuf::Buf32 {
1876                        addr: regs[3] as u32,
1877                        page_cnt: regs[4] as u32,
1878                    })
1879                } else {
1880                    None
1881                },
1882            },
1883            FuncId::MemDonate64 => Self::MemDonate {
1884                total_len: regs[1] as u32,
1885                frag_len: regs[2] as u32,
1886                buf: if regs[3] != 0 && regs[4] != 0 {
1887                    Some(MemOpBuf::Buf64 {
1888                        addr: regs[3],
1889                        page_cnt: regs[4] as u32,
1890                    })
1891                } else {
1892                    None
1893                },
1894            },
1895            FuncId::MemLend32 => Self::MemLend {
1896                total_len: regs[1] as u32,
1897                frag_len: regs[2] as u32,
1898                buf: if regs[3] != 0 && regs[4] != 0 {
1899                    Some(MemOpBuf::Buf32 {
1900                        addr: regs[3] as u32,
1901                        page_cnt: regs[4] as u32,
1902                    })
1903                } else {
1904                    None
1905                },
1906            },
1907            FuncId::MemLend64 => Self::MemLend {
1908                total_len: regs[1] as u32,
1909                frag_len: regs[2] as u32,
1910                buf: if regs[3] != 0 && regs[4] != 0 {
1911                    Some(MemOpBuf::Buf64 {
1912                        addr: regs[3],
1913                        page_cnt: regs[4] as u32,
1914                    })
1915                } else {
1916                    None
1917                },
1918            },
1919            FuncId::MemShare32 => Self::MemShare {
1920                total_len: regs[1] as u32,
1921                frag_len: regs[2] as u32,
1922                buf: if regs[3] != 0 && regs[4] != 0 {
1923                    Some(MemOpBuf::Buf32 {
1924                        addr: regs[3] as u32,
1925                        page_cnt: regs[4] as u32,
1926                    })
1927                } else {
1928                    None
1929                },
1930            },
1931            FuncId::MemShare64 => Self::MemShare {
1932                total_len: regs[1] as u32,
1933                frag_len: regs[2] as u32,
1934                buf: if regs[3] != 0 && regs[4] != 0 {
1935                    Some(MemOpBuf::Buf64 {
1936                        addr: regs[3],
1937                        page_cnt: regs[4] as u32,
1938                    })
1939                } else {
1940                    None
1941                },
1942            },
1943            FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
1944                total_len: regs[1] as u32,
1945                frag_len: regs[2] as u32,
1946                buf: if regs[3] != 0 && regs[4] != 0 {
1947                    Some(MemOpBuf::Buf32 {
1948                        addr: regs[3] as u32,
1949                        page_cnt: regs[4] as u32,
1950                    })
1951                } else {
1952                    None
1953                },
1954            },
1955            FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
1956                total_len: regs[1] as u32,
1957                frag_len: regs[2] as u32,
1958                buf: if regs[3] != 0 && regs[4] != 0 {
1959                    Some(MemOpBuf::Buf64 {
1960                        addr: regs[3],
1961                        page_cnt: regs[4] as u32,
1962                    })
1963                } else {
1964                    None
1965                },
1966            },
1967            FuncId::MemRetrieveResp => Self::MemRetrieveResp {
1968                total_len: regs[1] as u32,
1969                frag_len: regs[2] as u32,
1970            },
1971            FuncId::MemRelinquish => Self::MemRelinquish,
1972            FuncId::MemReclaim => Self::MemReclaim {
1973                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
1974                flags: (regs[3] as u32).try_into()?,
1975            },
1976            FuncId::MemPermGet32 => {
1977                if (version <= Version(1, 2) && regs[2] != 0)
1978                    || (regs[2] as u32).checked_add(1).is_none()
1979                {
1980                    return Err(Error::MemoryManagementError(
1981                        memory_management::Error::InvalidPageCount,
1982                    ));
1983                }
1984
1985                Self::MemPermGet {
1986                    addr: MemAddr::Addr32(regs[1] as u32),
1987                    page_cnt: regs[2] as u32 + 1,
1988                }
1989            }
1990            FuncId::MemPermGet64 => {
1991                if (version <= Version(1, 2) && regs[2] != 0)
1992                    || (regs[2] as u32).checked_add(1).is_none()
1993                {
1994                    return Err(Error::MemoryManagementError(
1995                        memory_management::Error::InvalidPageCount,
1996                    ));
1997                }
1998
1999                Self::MemPermGet {
2000                    addr: MemAddr::Addr64(regs[1]),
2001                    page_cnt: regs[2] as u32 + 1,
2002                }
2003            }
2004            FuncId::MemPermSet32 => Self::MemPermSet {
2005                addr: MemAddr::Addr32(regs[1] as u32),
2006                page_cnt: regs[2] as u32,
2007                mem_perm: (regs[3] as u32).try_into()?,
2008            },
2009            FuncId::MemPermSet64 => Self::MemPermSet {
2010                addr: MemAddr::Addr64(regs[1]),
2011                page_cnt: regs[2] as u32,
2012                mem_perm: (regs[3] as u32).try_into()?,
2013            },
2014            FuncId::MemOpPause => Self::MemOpPause {
2015                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2016            },
2017            FuncId::MemOpResume => Self::MemOpResume {
2018                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2019            },
2020            FuncId::MemFragRx => Self::MemFragRx {
2021                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2022                frag_offset: regs[3] as u32,
2023                endpoint_id: (regs[4] >> 16) as u16,
2024            },
2025            FuncId::MemFragTx => Self::MemFragTx {
2026                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
2027                frag_len: regs[3] as u32,
2028                endpoint_id: (regs[4] >> 16) as u16,
2029            },
2030            FuncId::ConsoleLog32 => {
2031                let char_cnt = regs[1] as u8;
2032                if char_cnt > ConsoleLogChars32::MAX_LENGTH {
2033                    return Err(Error::InvalidCharacterCount(char_cnt));
2034                }
2035
2036                Self::ConsoleLog {
2037                    chars: ConsoleLogChars::Chars32(ConsoleLogChars32 {
2038                        char_cnt,
2039                        char_lists: [
2040                            regs[2] as u32,
2041                            regs[3] as u32,
2042                            regs[4] as u32,
2043                            regs[5] as u32,
2044                            regs[6] as u32,
2045                            regs[7] as u32,
2046                        ],
2047                    }),
2048                }
2049            }
2050            FuncId::NotificationBitmapCreate => {
2051                let tentative_vm_id = regs[1] as u32;
2052                if (tentative_vm_id >> 16) != 0 {
2053                    return Err(Error::InvalidVmId(tentative_vm_id));
2054                }
2055                Self::NotificationBitmapCreate {
2056                    vm_id: tentative_vm_id as u16,
2057                    vcpu_cnt: regs[2] as u32,
2058                }
2059            }
2060            FuncId::NotificationBitmapDestroy => {
2061                let tentative_vm_id = regs[1] as u32;
2062                if (tentative_vm_id >> 16) != 0 {
2063                    return Err(Error::InvalidVmId(tentative_vm_id));
2064                }
2065                Self::NotificationBitmapDestroy {
2066                    vm_id: tentative_vm_id as u16,
2067                }
2068            }
2069            FuncId::NotificationBind => Self::NotificationBind {
2070                sender_id: (regs[1] >> 16) as u16,
2071                receiver_id: regs[1] as u16,
2072                flags: (regs[2] as u32).into(),
2073                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
2074            },
2075            FuncId::NotificationUnbind => Self::NotificationUnbind {
2076                sender_id: (regs[1] >> 16) as u16,
2077                receiver_id: regs[1] as u16,
2078                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
2079            },
2080            FuncId::NotificationSet => Self::NotificationSet {
2081                sender_id: (regs[1] >> 16) as u16,
2082                receiver_id: regs[1] as u16,
2083                flags: (regs[2] as u32).try_into()?,
2084                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
2085            },
2086            FuncId::NotificationGet => Self::NotificationGet {
2087                vcpu_id: (regs[1] >> 16) as u16,
2088                endpoint_id: regs[1] as u16,
2089                flags: (regs[2] as u32).into(),
2090            },
2091            FuncId::NotificationInfoGet32 => Self::NotificationInfoGet { is_32bit: true },
2092            FuncId::NotificationInfoGet64 => Self::NotificationInfoGet { is_32bit: false },
2093            FuncId::El3IntrHandle => Self::El3IntrHandle,
2094            _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
2095        };
2096
2097        Ok(msg)
2098    }
2099
2100    fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
2101        assert!(version >= Version(1, 2));
2102
2103        let fid = FuncId::try_from(regs[0] as u32)?;
2104
2105        let msg = match fid {
2106            FuncId::Success64 => Self::Success {
2107                target_info: (regs[1] as u32).into(),
2108                args: SuccessArgs::Args64_2(regs[2..18].try_into().unwrap()),
2109            },
2110            FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
2111                src_id: (regs[1] >> 16) as u16,
2112                dst_id: regs[1] as u16,
2113                uuid: UuidHelper::from_u64_regs([regs[2], regs[3]]),
2114                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
2115            },
2116            FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
2117                src_id: (regs[1] >> 16) as u16,
2118                dst_id: regs[1] as u16,
2119                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
2120            },
2121            FuncId::ConsoleLog64 => {
2122                let char_cnt = regs[1] as u8;
2123                if char_cnt > ConsoleLogChars64::MAX_LENGTH {
2124                    return Err(Error::InvalidCharacterCount(char_cnt));
2125                }
2126
2127                Self::ConsoleLog {
2128                    chars: ConsoleLogChars::Chars64(ConsoleLogChars64 {
2129                        char_cnt,
2130                        char_lists: regs[2..18].try_into().unwrap(),
2131                    }),
2132                }
2133            }
2134            FuncId::PartitionInfoGetRegs => {
2135                // Bits[15:0]: Start index
2136                let start_index = (regs[3] & 0xffff) as u16;
2137                let info_tag = ((regs[3] >> 16) & 0xffff) as u16;
2138                Self::PartitionInfoGetRegs {
2139                    uuid: UuidHelper::from_u64_regs([regs[1], regs[2]]),
2140                    start_index,
2141                    info_tag: if start_index == 0 && info_tag != 0 {
2142                        return Err(Error::InvalidInformationTag(info_tag));
2143                    } else {
2144                        info_tag
2145                    },
2146                }
2147            }
2148            _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
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                regs.fill(0);
2164
2165                self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
2166            }
2167            18 => {
2168                assert!(version >= Version(1, 2));
2169                regs.fill(0);
2170
2171                match self {
2172                    Interface::ConsoleLog {
2173                        chars: ConsoleLogChars::Chars64(_),
2174                        ..
2175                    }
2176                    | Interface::Success {
2177                        args: SuccessArgs::Args64_2(_),
2178                        ..
2179                    }
2180                    | Interface::MsgSendDirectReq2 { .. }
2181                    | Interface::MsgSendDirectResp2 { .. }
2182                    | Interface::PartitionInfoGetRegs { .. } => {
2183                        self.pack_regs18(version, regs.try_into().unwrap());
2184                    }
2185                    _ => {
2186                        self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
2187                    }
2188                }
2189            }
2190            _ => panic!("Invalid number of registers {}", reg_cnt),
2191        }
2192    }
2193
2194    fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
2195        if let Some(function_id) = self.function_id() {
2196            a[0] = function_id as u64;
2197        }
2198
2199        match *self {
2200            Interface::Error {
2201                target_info,
2202                error_code,
2203                error_arg,
2204            } => {
2205                a[1] = u32::from(target_info).into();
2206                a[2] = (error_code as u32).into();
2207                a[3] = error_arg.into();
2208            }
2209            Interface::Success { target_info, args } => {
2210                a[1] = u32::from(target_info).into();
2211                match args {
2212                    SuccessArgs::Args32(regs) => {
2213                        a[2] = regs[0].into();
2214                        a[3] = regs[1].into();
2215                        a[4] = regs[2].into();
2216                        a[5] = regs[3].into();
2217                        a[6] = regs[4].into();
2218                        a[7] = regs[5].into();
2219                    }
2220                    SuccessArgs::Args64(regs) => {
2221                        a[2] = regs[0];
2222                        a[3] = regs[1];
2223                        a[4] = regs[2];
2224                        a[5] = regs[3];
2225                        a[6] = regs[4];
2226                        a[7] = regs[5];
2227                    }
2228                    _ => panic!("{:#x?} requires 18 registers", args),
2229                }
2230            }
2231            Interface::Interrupt {
2232                target_info,
2233                interrupt_id,
2234            } => {
2235                a[1] = u32::from(target_info).into();
2236                a[2] = interrupt_id.into();
2237            }
2238            Interface::Version { input_version } => {
2239                a[1] = u32::from(input_version).into();
2240            }
2241            Interface::VersionOut { output_version } => {
2242                a[0] = u32::from(output_version).into();
2243            }
2244            Interface::Features {
2245                feat_id,
2246                input_properties,
2247            } => {
2248                a[1] = u32::from(feat_id).into();
2249                a[2] = input_properties.into();
2250            }
2251            Interface::RxAcquire { vm_id } => {
2252                a[1] = vm_id.into();
2253            }
2254            Interface::RxRelease { vm_id } => {
2255                a[1] = vm_id.into();
2256            }
2257            Interface::RxTxMap { addr, page_cnt } => {
2258                match addr {
2259                    RxTxAddr::Addr32 { rx, tx } => {
2260                        a[1] = tx.into();
2261                        a[2] = rx.into();
2262                    }
2263                    RxTxAddr::Addr64 { rx, tx } => {
2264                        a[1] = tx;
2265                        a[2] = rx;
2266                    }
2267                }
2268                a[3] = page_cnt.into();
2269            }
2270            Interface::RxTxUnmap { id } => {
2271                a[1] = (u32::from(id) << 16).into();
2272            }
2273            Interface::PartitionInfoGet { uuid, flags } => {
2274                let uuid_words: [u32; 4] = UuidHelper::to_u32_regs(uuid);
2275
2276                a[1] = uuid_words[0].into();
2277                a[2] = uuid_words[1].into();
2278                a[3] = uuid_words[2].into();
2279                a[4] = uuid_words[3].into();
2280                a[5] = u32::from(flags).into();
2281            }
2282            Interface::MsgWait { flags } => {
2283                if version >= Version(1, 2) {
2284                    if let Some(flags) = flags {
2285                        a[2] = u32::from(flags).into();
2286                    }
2287                }
2288            }
2289            Interface::IdGet | Interface::SpmIdGet | Interface::Yield => {}
2290            Interface::Run { target_info } => {
2291                a[1] = u32::from(target_info).into();
2292            }
2293            Interface::NormalWorldResume => {}
2294            Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
2295                SecondaryEpRegisterAddr::Addr32(addr) => a[1] = addr as u64,
2296                SecondaryEpRegisterAddr::Addr64(addr) => a[1] = addr,
2297            },
2298            Interface::MsgSend2 {
2299                sender_vm_id,
2300                flags,
2301            } => {
2302                a[1] = (sender_vm_id as u64) << 16;
2303                a[2] = u32::from(flags).into();
2304            }
2305            Interface::MsgSendDirectReq {
2306                src_id,
2307                dst_id,
2308                args,
2309            } => {
2310                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2311                match args {
2312                    DirectMsgArgs::Args32(args) => {
2313                        a[3] = args[0].into();
2314                        a[4] = args[1].into();
2315                        a[5] = args[2].into();
2316                        a[6] = args[3].into();
2317                        a[7] = args[4].into();
2318                    }
2319                    DirectMsgArgs::Args64(args) => {
2320                        a[3] = args[0];
2321                        a[4] = args[1];
2322                        a[5] = args[2];
2323                        a[6] = args[3];
2324                        a[7] = args[4];
2325                    }
2326                    DirectMsgArgs::VersionReq { version } => {
2327                        a[2] = DirectMsgArgs::VERSION_REQ.into();
2328                        a[3] = u32::from(version).into();
2329                    }
2330                    DirectMsgArgs::PowerPsciReq32 { params } => {
2331                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2332                        a[3] = params[0].into();
2333                        a[4] = params[1].into();
2334                        a[5] = params[2].into();
2335                        a[6] = params[3].into();
2336                    }
2337                    DirectMsgArgs::PowerPsciReq64 { params } => {
2338                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2339                        a[3] = params[0];
2340                        a[4] = params[1];
2341                        a[5] = params[2];
2342                        a[6] = params[3];
2343                    }
2344                    DirectMsgArgs::PowerWarmBootReq { boot_type } => {
2345                        a[2] = DirectMsgArgs::POWER_WARM_BOOT_REQ.into();
2346                        a[3] = u32::from(boot_type).into();
2347                    }
2348                    DirectMsgArgs::VmCreated { handle, vm_id } => {
2349                        a[2] = DirectMsgArgs::VM_CREATED.into();
2350                        let handle_regs: [u32; 2] = handle.into();
2351                        a[3] = handle_regs[0].into();
2352                        a[4] = handle_regs[1].into();
2353                        a[5] = vm_id.into();
2354                    }
2355                    DirectMsgArgs::VmDestructed { handle, vm_id } => {
2356                        a[2] = DirectMsgArgs::VM_DESTRUCTED.into();
2357                        let handle_regs: [u32; 2] = handle.into();
2358                        a[3] = handle_regs[0].into();
2359                        a[4] = handle_regs[1].into();
2360                        a[5] = vm_id.into();
2361                    }
2362                    _ => panic!("Malformed MsgSendDirectReq interface"),
2363                }
2364            }
2365            Interface::MsgSendDirectResp {
2366                src_id,
2367                dst_id,
2368                args,
2369            } => {
2370                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2371                match args {
2372                    DirectMsgArgs::Args32(args) => {
2373                        a[3] = args[0].into();
2374                        a[4] = args[1].into();
2375                        a[5] = args[2].into();
2376                        a[6] = args[3].into();
2377                        a[7] = args[4].into();
2378                    }
2379                    DirectMsgArgs::Args64(args) => {
2380                        a[3] = args[0];
2381                        a[4] = args[1];
2382                        a[5] = args[2];
2383                        a[6] = args[3];
2384                        a[7] = args[4];
2385                    }
2386                    DirectMsgArgs::VersionResp { version } => {
2387                        a[2] = DirectMsgArgs::VERSION_RESP.into();
2388                        match version {
2389                            None => a[3] = (i32::from(FfaError::NotSupported) as u32).into(),
2390                            Some(ver) => a[3] = u32::from(ver).into(),
2391                        }
2392                    }
2393                    DirectMsgArgs::PowerPsciResp { psci_status } => {
2394                        a[2] = DirectMsgArgs::POWER_PSCI_RESP.into();
2395                        a[3] = (psci_status as u32).into();
2396                    }
2397                    DirectMsgArgs::VmCreatedAck { sp_status } => {
2398                        a[2] = DirectMsgArgs::VM_CREATED_ACK.into();
2399                        a[3] = (i32::from(sp_status) as u32).into();
2400                    }
2401                    DirectMsgArgs::VmDestructedAck { sp_status } => {
2402                        a[2] = DirectMsgArgs::VM_DESTRUCTED_ACK.into();
2403                        a[3] = (i32::from(sp_status) as u32).into();
2404                    }
2405                    _ => panic!("Malformed MsgSendDirectResp interface"),
2406                }
2407            }
2408            Interface::MemDonate {
2409                total_len,
2410                frag_len,
2411                buf,
2412            } => {
2413                a[1] = total_len.into();
2414                a[2] = frag_len.into();
2415                (a[3], a[4]) = match buf {
2416                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2417                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2418                    None => (0, 0),
2419                };
2420            }
2421            Interface::MemLend {
2422                total_len,
2423                frag_len,
2424                buf,
2425            } => {
2426                a[1] = total_len.into();
2427                a[2] = frag_len.into();
2428                (a[3], a[4]) = match buf {
2429                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2430                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2431                    None => (0, 0),
2432                };
2433            }
2434            Interface::MemShare {
2435                total_len,
2436                frag_len,
2437                buf,
2438            } => {
2439                a[1] = total_len.into();
2440                a[2] = frag_len.into();
2441                (a[3], a[4]) = match buf {
2442                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2443                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2444                    None => (0, 0),
2445                };
2446            }
2447            Interface::MemRetrieveReq {
2448                total_len,
2449                frag_len,
2450                buf,
2451            } => {
2452                a[1] = total_len.into();
2453                a[2] = frag_len.into();
2454                (a[3], a[4]) = match buf {
2455                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2456                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2457                    None => (0, 0),
2458                };
2459            }
2460            Interface::MemRetrieveResp {
2461                total_len,
2462                frag_len,
2463            } => {
2464                a[1] = total_len.into();
2465                a[2] = frag_len.into();
2466            }
2467            Interface::MemRelinquish => {}
2468            Interface::MemReclaim { handle, flags } => {
2469                let handle_regs: [u32; 2] = handle.into();
2470                a[1] = handle_regs[0].into();
2471                a[2] = handle_regs[1].into();
2472                a[3] = u32::from(flags).into();
2473            }
2474            Interface::MemPermGet { addr, page_cnt } => {
2475                a[1] = match addr {
2476                    MemAddr::Addr32(addr) => addr.into(),
2477                    MemAddr::Addr64(addr) => addr,
2478                };
2479                a[2] = if version <= Version(1, 2) {
2480                    assert_eq!(page_cnt, 1);
2481                    0
2482                } else {
2483                    assert_ne!(page_cnt, 0);
2484                    (page_cnt - 1).into()
2485                }
2486            }
2487            Interface::MemPermSet {
2488                addr,
2489                page_cnt,
2490                mem_perm,
2491            } => {
2492                a[1] = match addr {
2493                    MemAddr::Addr32(addr) => addr.into(),
2494                    MemAddr::Addr64(addr) => addr,
2495                };
2496                a[2] = page_cnt.into();
2497                a[3] = u32::from(mem_perm).into();
2498            }
2499            Interface::MemOpPause { handle } => {
2500                let handle_regs: [u32; 2] = handle.into();
2501                a[1] = handle_regs[0].into();
2502                a[2] = handle_regs[1].into();
2503            }
2504            Interface::MemOpResume { handle } => {
2505                let handle_regs: [u32; 2] = handle.into();
2506                a[1] = handle_regs[0].into();
2507                a[2] = handle_regs[1].into();
2508            }
2509            Interface::MemFragRx {
2510                handle,
2511                frag_offset,
2512                endpoint_id,
2513            } => {
2514                let handle_regs: [u32; 2] = handle.into();
2515                a[1] = handle_regs[0].into();
2516                a[2] = handle_regs[1].into();
2517                a[3] = frag_offset.into();
2518                a[4] = (u32::from(endpoint_id) << 16).into();
2519            }
2520            Interface::MemFragTx {
2521                handle,
2522                frag_len,
2523                endpoint_id,
2524            } => {
2525                let handle_regs: [u32; 2] = handle.into();
2526                a[1] = handle_regs[0].into();
2527                a[2] = handle_regs[1].into();
2528                a[3] = frag_len.into();
2529                a[4] = (u32::from(endpoint_id) << 16).into();
2530            }
2531            Interface::ConsoleLog { chars } => match chars {
2532                ConsoleLogChars::Chars32(ConsoleLogChars32 {
2533                    char_cnt,
2534                    char_lists,
2535                }) => {
2536                    a[1] = char_cnt.into();
2537                    a[2] = char_lists[0].into();
2538                    a[3] = char_lists[1].into();
2539                    a[4] = char_lists[2].into();
2540                    a[5] = char_lists[3].into();
2541                    a[6] = char_lists[4].into();
2542                    a[7] = char_lists[5].into();
2543                }
2544                _ => panic!("{:#x?} requires 18 registers", chars),
2545            },
2546            Interface::NotificationBitmapCreate { vm_id, vcpu_cnt } => {
2547                a[1] = vm_id.into();
2548                a[2] = vcpu_cnt.into();
2549            }
2550            Interface::NotificationBitmapDestroy { vm_id } => {
2551                a[1] = vm_id.into();
2552            }
2553            Interface::NotificationBind {
2554                sender_id,
2555                receiver_id,
2556                flags,
2557                bitmap,
2558            } => {
2559                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2560                a[2] = u32::from(flags).into();
2561                a[3] = bitmap & 0xffff_ffff;
2562                a[4] = bitmap >> 32;
2563            }
2564            Interface::NotificationUnbind {
2565                sender_id,
2566                receiver_id,
2567                bitmap,
2568            } => {
2569                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2570                a[3] = bitmap & 0xffff_ffff;
2571                a[4] = bitmap >> 32;
2572            }
2573            Interface::NotificationSet {
2574                sender_id,
2575                receiver_id,
2576                flags,
2577                bitmap,
2578            } => {
2579                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2580                a[2] = u32::from(flags).into();
2581                a[3] = bitmap & 0xffff_ffff;
2582                a[4] = bitmap >> 32;
2583            }
2584            Interface::NotificationGet {
2585                vcpu_id,
2586                endpoint_id,
2587                flags,
2588            } => {
2589                a[1] = (u64::from(vcpu_id) << 16) | u64::from(endpoint_id);
2590                a[2] = u32::from(flags).into();
2591            }
2592            Interface::NotificationInfoGet { .. } => {}
2593            Interface::El3IntrHandle => {}
2594            _ => panic!("{:#x?} requires 18 registers", self),
2595        }
2596    }
2597
2598    fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
2599        assert!(version >= Version(1, 2));
2600
2601        if let Some(function_id) = self.function_id() {
2602            a[0] = function_id as u64;
2603        }
2604
2605        match *self {
2606            Interface::Success { target_info, args } => {
2607                a[1] = u32::from(target_info).into();
2608                match args {
2609                    SuccessArgs::Args64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
2610                    _ => panic!("{:#x?} requires 8 registers", args),
2611                }
2612            }
2613            Interface::MsgSendDirectReq2 {
2614                src_id,
2615                dst_id,
2616                uuid,
2617                args,
2618            } => {
2619                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2620                [a[2], a[3]] = UuidHelper::to_u64_regs(uuid);
2621                a[4..18].copy_from_slice(&args.0[..14]);
2622            }
2623            Interface::MsgSendDirectResp2 {
2624                src_id,
2625                dst_id,
2626                args,
2627            } => {
2628                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2629                a[2] = 0;
2630                a[3] = 0;
2631                a[4..18].copy_from_slice(&args.0[..14]);
2632            }
2633            Interface::ConsoleLog { chars: char_lists } => match char_lists {
2634                ConsoleLogChars::Chars64(ConsoleLogChars64 {
2635                    char_cnt,
2636                    char_lists,
2637                }) => {
2638                    a[1] = char_cnt.into();
2639                    a[2..18].copy_from_slice(&char_lists[..16])
2640                }
2641                _ => panic!("{:#x?} requires 8 registers", char_lists),
2642            },
2643            Interface::PartitionInfoGetRegs {
2644                uuid,
2645                start_index,
2646                info_tag,
2647            } => {
2648                if start_index == 0 && info_tag != 0 {
2649                    panic!("Information Tag MBZ if start index is 0: {:#x?}", self);
2650                }
2651                [a[1], a[2]] = UuidHelper::to_u64_regs(uuid);
2652                a[3] = (u64::from(info_tag) << 16) | u64::from(start_index);
2653            }
2654            _ => panic!("{:#x?} requires 8 registers", self),
2655        }
2656    }
2657
2658    /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
2659    pub fn success32_noargs() -> Self {
2660        Self::Success {
2661            target_info: TargetInfo::default(),
2662            args: SuccessArgs::Args32([0; 6]),
2663        }
2664    }
2665
2666    /// Helper function to create an `FFA_ERROR` interface with an error code.
2667    pub fn error(error_code: FfaError) -> Self {
2668        Self::Error {
2669            target_info: TargetInfo::default(),
2670            error_code,
2671            error_arg: 0,
2672        }
2673    }
2674}
2675
2676#[cfg(test)]
2677mod tests {
2678    use uuid::uuid;
2679
2680    use crate::{
2681        memory_management::Handle,
2682        partition_info::{SuccessArgsPartitionInfoGet, SuccessArgsPartitionInfoGetRegs},
2683    };
2684
2685    use super::*;
2686
2687    const fn error_code(code: i32) -> u64 {
2688        (code as u32) as u64
2689    }
2690
2691    #[test]
2692    fn version_reg_count() {
2693        assert!(!Version(1, 1).needs_18_regs());
2694        assert!(Version(1, 2).needs_18_regs())
2695    }
2696
2697    #[test]
2698    fn ffa_uuid_helpers() {
2699        const UUID: Uuid = uuid!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
2700
2701        let bytes = [
2702            0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
2703            0xd7, 0xd8,
2704        ];
2705
2706        assert_eq!(UUID, UuidHelper::from_bytes(bytes));
2707        assert_eq!(bytes, UuidHelper::to_bytes(UUID));
2708
2709        let words = [0xa4a3a2a1, 0xc2c1b2b1, 0xd4d3d2d1, 0xd8d7d6d5];
2710        assert_eq!(UUID, UuidHelper::from_u32_regs(words));
2711        assert_eq!(words, UuidHelper::to_u32_regs(UUID));
2712
2713        let pair = [0xc2c1b2b1a4a3a2a1, 0xd8d7d6d5d4d3d2d1];
2714        assert_eq!(UUID, UuidHelper::from_u64_regs(pair));
2715        assert_eq!(pair, UuidHelper::to_u64_regs(UUID));
2716    }
2717
2718    #[test]
2719    fn part_info_get_regs() {
2720        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2721        let uuid_bytes = uuid.as_bytes();
2722        let test_info_tag = 0b1101_1101;
2723        let test_start_index = 0b1101;
2724        let start_index_and_tag = (test_info_tag << 16) | test_start_index;
2725        let version = Version(1, 2);
2726
2727        // From spec:
2728        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2729        let reg_x1 = ((uuid_bytes[7] as u64) << 56)
2730            | ((uuid_bytes[6] as u64) << 48)
2731            | ((uuid_bytes[5] as u64) << 40)
2732            | ((uuid_bytes[4] as u64) << 32)
2733            | ((uuid_bytes[3] as u64) << 24)
2734            | ((uuid_bytes[2] as u64) << 16)
2735            | ((uuid_bytes[1] as u64) << 8)
2736            | (uuid_bytes[0] as u64);
2737
2738        // From spec:
2739        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2740        let reg_x2 = ((uuid_bytes[15] as u64) << 56)
2741            | ((uuid_bytes[14] as u64) << 48)
2742            | ((uuid_bytes[13] as u64) << 40)
2743            | ((uuid_bytes[12] as u64) << 32)
2744            | ((uuid_bytes[11] as u64) << 24)
2745            | ((uuid_bytes[10] as u64) << 16)
2746            | ((uuid_bytes[9] as u64) << 8)
2747            | (uuid_bytes[8] as u64);
2748
2749        // First, test for wrong tag:
2750        {
2751            let mut regs = [0u64; 18];
2752            regs[0] = FuncId::PartitionInfoGetRegs as u64;
2753            regs[1] = reg_x1;
2754            regs[2] = reg_x2;
2755            regs[3] = test_info_tag << 16;
2756
2757            assert!(Interface::from_regs(version, &regs).is_err_and(
2758                |e| e == Error::InvalidInformationTag(test_info_tag.try_into().unwrap())
2759            ));
2760        }
2761
2762        // Test for regs -> Interface -> regs
2763        {
2764            let mut orig_regs = [0u64; 18];
2765            orig_regs[0] = FuncId::PartitionInfoGetRegs as u64;
2766            orig_regs[1] = reg_x1;
2767            orig_regs[2] = reg_x2;
2768            orig_regs[3] = start_index_and_tag;
2769
2770            let mut test_regs = orig_regs;
2771            let interface = Interface::from_regs(version, &test_regs).unwrap();
2772            match &interface {
2773                Interface::PartitionInfoGetRegs {
2774                    info_tag,
2775                    start_index,
2776                    uuid: int_uuid,
2777                } => {
2778                    assert_eq!(u64::from(*info_tag), test_info_tag);
2779                    assert_eq!(u64::from(*start_index), test_start_index);
2780                    assert_eq!(*int_uuid, uuid);
2781                }
2782                _ => panic!("Expecting Interface::PartitionInfoGetRegs!"),
2783            }
2784            test_regs.fill(0);
2785            interface.to_regs(version, &mut test_regs);
2786            assert_eq!(orig_regs, test_regs);
2787        }
2788
2789        // Test for Interface -> regs -> Interface
2790        {
2791            let interface = Interface::PartitionInfoGetRegs {
2792                info_tag: test_info_tag.try_into().unwrap(),
2793                start_index: test_start_index.try_into().unwrap(),
2794                uuid,
2795            };
2796
2797            let mut regs: [u64; 18] = [0; 18];
2798            interface.to_regs(version, &mut regs);
2799
2800            assert_eq!(Some(FuncId::PartitionInfoGetRegs), interface.function_id());
2801            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2802            assert_eq!(regs[1], reg_x1);
2803            assert_eq!(regs[2], reg_x2);
2804            assert_eq!(regs[3], (test_info_tag << 16) | test_start_index);
2805
2806            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2807        }
2808    }
2809
2810    #[test]
2811    fn msg_send_direct_req2() {
2812        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2813        let uuid_bytes = uuid.as_bytes();
2814
2815        // From spec:
2816        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2817        let reg_x2 = ((uuid_bytes[7] as u64) << 56)
2818            | ((uuid_bytes[6] as u64) << 48)
2819            | ((uuid_bytes[5] as u64) << 40)
2820            | ((uuid_bytes[4] as u64) << 32)
2821            | ((uuid_bytes[3] as u64) << 24)
2822            | ((uuid_bytes[2] as u64) << 16)
2823            | ((uuid_bytes[1] as u64) << 8)
2824            | (uuid_bytes[0] as u64);
2825
2826        // From spec:
2827        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2828        let reg_x3 = ((uuid_bytes[15] as u64) << 56)
2829            | ((uuid_bytes[14] as u64) << 48)
2830            | ((uuid_bytes[13] as u64) << 40)
2831            | ((uuid_bytes[12] as u64) << 32)
2832            | ((uuid_bytes[11] as u64) << 24)
2833            | ((uuid_bytes[10] as u64) << 16)
2834            | ((uuid_bytes[9] as u64) << 8)
2835            | (uuid_bytes[8] as u64);
2836
2837        let test_sender = 0b1101_1101;
2838        let test_receiver = 0b1101;
2839        let test_sender_receiver = (test_sender << 16) | test_receiver;
2840        let version = Version(1, 2);
2841
2842        // Test for regs -> Interface -> regs
2843        {
2844            let mut orig_regs = [0u64; 18];
2845            orig_regs[0] = FuncId::MsgSendDirectReq64_2 as u64;
2846            orig_regs[1] = test_sender_receiver;
2847            orig_regs[2] = reg_x2;
2848            orig_regs[3] = reg_x3;
2849
2850            let mut test_regs = orig_regs;
2851            let interface = Interface::from_regs(version, &test_regs).unwrap();
2852            match &interface {
2853                Interface::MsgSendDirectReq2 {
2854                    dst_id,
2855                    src_id,
2856                    args: _,
2857                    uuid: int_uuid,
2858                } => {
2859                    assert_eq!(u64::from(*src_id), test_sender);
2860                    assert_eq!(u64::from(*dst_id), test_receiver);
2861                    assert_eq!(*int_uuid, uuid);
2862                }
2863                _ => panic!("Expecting Interface::MsgSendDirectReq2!"),
2864            }
2865            test_regs.fill(0);
2866            interface.to_regs(version, &mut test_regs);
2867            assert_eq!(orig_regs, test_regs);
2868        }
2869
2870        // Test for Interface -> regs -> Interface
2871        {
2872            let rest_of_regs: [u64; 14] = [0; 14];
2873
2874            let interface = Interface::MsgSendDirectReq2 {
2875                src_id: test_sender.try_into().unwrap(),
2876                dst_id: test_receiver.try_into().unwrap(),
2877                uuid,
2878                args: DirectMsg2Args(rest_of_regs),
2879            };
2880
2881            let mut regs: [u64; 18] = [0; 18];
2882            interface.to_regs(version, &mut regs);
2883
2884            assert_eq!(Some(FuncId::MsgSendDirectReq64_2), interface.function_id());
2885            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2886            assert_eq!(regs[1], test_sender_receiver);
2887            assert_eq!(regs[2], reg_x2);
2888            assert_eq!(regs[3], reg_x3);
2889            assert_eq!(regs[4], 0);
2890
2891            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2892        }
2893    }
2894
2895    #[test]
2896    fn is_32bit() {
2897        let interface_64 = Interface::MsgSendDirectReq {
2898            src_id: 0,
2899            dst_id: 1,
2900            args: DirectMsgArgs::Args64([0, 0, 0, 0, 0]),
2901        };
2902        assert!(!interface_64.is_32bit());
2903
2904        let interface_32 = Interface::MsgSendDirectReq {
2905            src_id: 0,
2906            dst_id: 1,
2907            args: DirectMsgArgs::Args32([0, 0, 0, 0, 0]),
2908        };
2909        assert!(interface_32.is_32bit());
2910    }
2911
2912    #[test]
2913    fn success_args_notification_info_get32() {
2914        let mut notifications = SuccessArgsNotificationInfoGet32::default();
2915
2916        // 16.7.1.1 Example usage
2917        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2918        notifications.add_list(0x0000, &[4, 6]).unwrap();
2919        notifications.add_list(0x0002, &[]).unwrap();
2920        notifications.add_list(0x0003, &[1]).unwrap();
2921
2922        let args: SuccessArgs = notifications.into();
2923        assert_eq!(
2924            SuccessArgs::Args32([
2925                0x0004_b200,
2926                0x0000_0000,
2927                0x0003_0002,
2928                0x0004_0000,
2929                0x0002_0006,
2930                0x0001_0003
2931            ]),
2932            args
2933        );
2934
2935        let notifications = SuccessArgsNotificationInfoGet32::try_from(args).unwrap();
2936        let mut iter = notifications.iter();
2937        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2938        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2939        assert_eq!(Some((0x0002, &[][..])), iter.next());
2940        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2941    }
2942
2943    #[test]
2944    fn success_args_notification_info_get64() {
2945        let mut notifications = SuccessArgsNotificationInfoGet64::default();
2946
2947        // 16.7.1.1 Example usage
2948        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2949        notifications.add_list(0x0000, &[4, 6]).unwrap();
2950        notifications.add_list(0x0002, &[]).unwrap();
2951        notifications.add_list(0x0003, &[1]).unwrap();
2952
2953        let args: SuccessArgs = notifications.into();
2954        assert_eq!(
2955            SuccessArgs::Args64([
2956                0x0004_b200,
2957                0x0003_0002_0000_0000,
2958                0x0002_0006_0004_0000,
2959                0x0000_0000_0001_0003,
2960                0x0000_0000_0000_0000,
2961                0x0000_0000_0000_0000,
2962            ]),
2963            args
2964        );
2965
2966        let notifications = SuccessArgsNotificationInfoGet64::try_from(args).unwrap();
2967        let mut iter = notifications.iter();
2968        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2969        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2970        assert_eq!(Some((0x0002, &[][..])), iter.next());
2971        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2972    }
2973
2974    #[test]
2975    fn mem_perm_get_pack() {
2976        let mut expected_regs = [0u64; 18];
2977        let mut out_regs = [0u64; 18];
2978
2979        expected_regs[0] = u32::from(FuncId::MemPermGet32).into();
2980        expected_regs[1] = 0xabcd;
2981        expected_regs[2] = 5;
2982
2983        Interface::MemPermGet {
2984            addr: MemAddr::Addr32(0xabcd),
2985            page_cnt: 6,
2986        }
2987        .to_regs(Version(1, 3), &mut out_regs);
2988
2989        assert_eq!(expected_regs, out_regs);
2990
2991        expected_regs[2] = 0;
2992
2993        Interface::MemPermGet {
2994            addr: MemAddr::Addr32(0xabcd),
2995            page_cnt: 1,
2996        }
2997        .to_regs(Version(1, 2), &mut out_regs);
2998
2999        assert_eq!(expected_regs, out_regs);
3000    }
3001
3002    #[test]
3003    #[should_panic]
3004    fn mem_perm_get_pack_fail1() {
3005        let mut out_regs = [0u64; 18];
3006        Interface::MemPermGet {
3007            addr: MemAddr::Addr32(0xabcd),
3008            page_cnt: 2,
3009        }
3010        .to_regs(Version(1, 2), &mut out_regs);
3011    }
3012
3013    #[test]
3014    #[should_panic]
3015    fn mem_perm_get_pack_fail2() {
3016        let mut out_regs = [0u64; 18];
3017        Interface::MemPermGet {
3018            addr: MemAddr::Addr32(0xabcd),
3019            page_cnt: 0,
3020        }
3021        .to_regs(Version(1, 3), &mut out_regs);
3022    }
3023
3024    #[test]
3025    fn mem_perm_get_unpack() {
3026        let mut in_regs = [0u64; 18];
3027
3028        in_regs[0] = u32::from(FuncId::MemPermGet32).into();
3029        in_regs[1] = 0xabcd;
3030        in_regs[2] = 5;
3031
3032        assert_eq!(
3033            Interface::from_regs(Version(1, 3), &in_regs),
3034            Ok(Interface::MemPermGet {
3035                addr: MemAddr::Addr32(0xabcd),
3036                page_cnt: 6,
3037            }),
3038        );
3039
3040        assert_eq!(
3041            Interface::from_regs(Version(1, 2), &in_regs),
3042            Err(Error::MemoryManagementError(
3043                memory_management::Error::InvalidPageCount
3044            )),
3045        );
3046
3047        in_regs[2] = 0;
3048
3049        assert_eq!(
3050            Interface::from_regs(Version(1, 2), &in_regs),
3051            Ok(Interface::MemPermGet {
3052                addr: MemAddr::Addr32(0xabcd),
3053                page_cnt: 1,
3054            }),
3055        );
3056
3057        in_regs[2] = u32::MAX.into();
3058
3059        assert_eq!(
3060            Interface::from_regs(Version(1, 3), &in_regs),
3061            Err(Error::MemoryManagementError(
3062                memory_management::Error::InvalidPageCount
3063            )),
3064        );
3065    }
3066
3067    macro_rules! test_regs_serde {
3068        ($value:expr, $bytes:expr) => {
3069            let mut regs = [0u64; 18];
3070            let mut bytes = [0u64; 18];
3071
3072            let b: &[u64] = &$bytes;
3073            bytes[0..(b.len())].copy_from_slice(&b);
3074
3075            $value.to_regs(Version(1, 2), &mut regs);
3076            assert_eq!(regs, bytes);
3077
3078            assert_eq!(Interface::from_regs(Version(1, 2), &bytes), Ok($value));
3079        };
3080    }
3081    pub(crate) use test_regs_serde;
3082
3083    macro_rules! test_args_serde {
3084        ($args:expr, $sa:expr) => {
3085            assert_eq!($args.try_into(), Ok($sa));
3086            assert_eq!($sa.try_into(), Ok($args));
3087        };
3088        ($args:expr, $sa:expr, $flags:expr) => {
3089            assert_eq!($args.try_into(), Ok($sa));
3090            assert_eq!(($flags, $sa).try_into(), Ok($args));
3091        };
3092    }
3093    pub(crate) use test_args_serde;
3094
3095    #[test]
3096    fn ffa_error_serde() {
3097        test_regs_serde!(
3098            Interface::Error {
3099                target_info: TargetInfo {
3100                    endpoint_id: 0x1234,
3101                    vcpu_id: 0xabcd
3102                },
3103                error_code: FfaError::Aborted,
3104                error_arg: 0xdead_beef
3105            },
3106            [0x84000060, 0x1234_abcd, error_code(-8), 0xdead_beef]
3107        );
3108    }
3109
3110    #[test]
3111    fn ffa_success_serde() {
3112        test_regs_serde!(
3113            Interface::Success {
3114                target_info: TargetInfo {
3115                    endpoint_id: 0x1234,
3116                    vcpu_id: 0xabcd
3117                },
3118                args: SuccessArgs::Args32([1, 2, 3, 4, 5, 6])
3119            },
3120            [0x84000061, 0x1234_abcd, 1, 2, 3, 4, 5, 6]
3121        );
3122        test_regs_serde!(
3123            Interface::Success {
3124                target_info: TargetInfo {
3125                    endpoint_id: 0x1234,
3126                    vcpu_id: 0xabcd
3127                },
3128                args: SuccessArgs::Args64_2([
3129                    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
3130                ])
3131            },
3132            [
3133                0xC4000061,
3134                0x1234_abcd,
3135                1,
3136                2,
3137                3,
3138                4,
3139                5,
3140                6,
3141                7,
3142                8,
3143                9,
3144                10,
3145                11,
3146                12,
3147                13,
3148                14,
3149                15,
3150                16
3151            ]
3152        );
3153    }
3154
3155    #[test]
3156    fn ffa_interrupt_serde() {
3157        test_regs_serde!(
3158            Interface::Interrupt {
3159                target_info: TargetInfo {
3160                    endpoint_id: 0x1234,
3161                    vcpu_id: 0xabcd
3162                },
3163                interrupt_id: 0xdead_beef
3164            },
3165            [0x84000062, 0x1234_abcd, 0xdead_beef]
3166        );
3167    }
3168
3169    #[test]
3170    fn ffa_version_serde() {
3171        test_regs_serde!(
3172            Interface::Version {
3173                input_version: Version(1, 2),
3174            },
3175            [0x84000063, 0x0001_0002]
3176        );
3177    }
3178
3179    #[test]
3180    fn ffa_feature_serde() {
3181        test_regs_serde!(
3182            Interface::Features {
3183                feat_id: Feature::FeatureId(FeatureId::NotificationPendingInterrupt),
3184                input_properties: 0
3185            },
3186            [0x84000064, 0x1]
3187        );
3188        test_regs_serde!(
3189            Interface::Features {
3190                feat_id: Feature::FeatureId(FeatureId::ScheduleReceiverInterrupt),
3191                input_properties: 0
3192            },
3193            [0x84000064, 0x2]
3194        );
3195        test_regs_serde!(
3196            Interface::Features {
3197                feat_id: Feature::FeatureId(FeatureId::ManagedExitInterrupt),
3198                input_properties: 0
3199            },
3200            [0x84000064, 0x3]
3201        );
3202        test_regs_serde!(
3203            Interface::Features {
3204                feat_id: Feature::FuncId(FuncId::Features),
3205                input_properties: 32
3206            },
3207            [0x84000064, 0x84000064, 32]
3208        );
3209        test_args_serde!(
3210            SuccessArgs::Args32([8, 8, 0, 0, 0, 0]),
3211            SuccessArgsFeatures { properties: [8, 8] }
3212        );
3213    }
3214
3215    #[test]
3216    fn ffa_rx_acquire_serde() {
3217        test_regs_serde!(Interface::RxAcquire { vm_id: 0xbeef }, [0x84000084, 0xbeef]);
3218    }
3219
3220    #[test]
3221    fn ffa_rx_release_serde() {
3222        test_regs_serde!(Interface::RxRelease { vm_id: 0xbeef }, [0x84000065, 0xbeef]);
3223    }
3224
3225    #[test]
3226    fn ffa_rxtx_map_serde() {
3227        test_regs_serde!(
3228            Interface::RxTxMap {
3229                addr: RxTxAddr::Addr32 {
3230                    rx: 0xbeef,
3231                    tx: 0xfeed_dead
3232                },
3233                page_cnt: 0x1234_abcd
3234            },
3235            [0x84000066, 0xfeed_dead, 0xbeef, 0x1234_abcd]
3236        );
3237        test_regs_serde!(
3238            Interface::RxTxMap {
3239                addr: RxTxAddr::Addr64 {
3240                    rx: 0xdead_1234_beef,
3241                    tx: 0xaaaa_bbbb_feed_dead
3242                },
3243                page_cnt: 0x1234_abcd
3244            },
3245            [
3246                0xC4000066,
3247                0xaaaa_bbbb_feed_dead,
3248                0xdead_1234_beef,
3249                0x1234_abcd
3250            ]
3251        );
3252    }
3253
3254    #[test]
3255    fn ffa_rxtx_unmap_serde() {
3256        test_regs_serde!(
3257            Interface::RxTxUnmap { id: 0x1234 },
3258            [0x84000067, 0x1234_0000]
3259        );
3260    }
3261
3262    #[test]
3263    fn ffa_partition_info_get_serde() {
3264        test_regs_serde!(
3265            Interface::PartitionInfoGet {
3266                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3267                flags: PartitionInfoGetFlags { count_only: false }
3268            },
3269            [0x84000068, 0x78563412, 0x12efcdab, 0x90785634, 0x00efcdab]
3270        );
3271        test_args_serde!(
3272            SuccessArgsPartitionInfoGet {
3273                count: 0x1234_5678,
3274                size: Some(0xabcd_beef)
3275            },
3276            SuccessArgs::Args32([0x1234_5678, 0xabcd_beef, 0, 0, 0, 0]),
3277            PartitionInfoGetFlags { count_only: false }
3278        );
3279        test_regs_serde!(
3280            Interface::PartitionInfoGet {
3281                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3282                flags: PartitionInfoGetFlags { count_only: true }
3283            },
3284            [0x84000068, 0x78563412, 0x12efcdab, 0x90785634, 0x00efcdab, 0b1]
3285        );
3286        test_args_serde!(
3287            SuccessArgsPartitionInfoGet {
3288                count: 0x1234_5678,
3289                size: None
3290            },
3291            SuccessArgs::Args32([0x1234_5678, 0, 0, 0, 0, 0]),
3292            PartitionInfoGetFlags { count_only: true }
3293        );
3294    }
3295
3296    #[test]
3297    fn ffa_partition_info_get_regs_serde() {
3298        test_regs_serde!(
3299            Interface::PartitionInfoGetRegs {
3300                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3301                start_index: 0xfeed,
3302                info_tag: 0xbeef
3303            },
3304            [
3305                0xC400008B,
3306                0x12ef_cdab_7856_3412,
3307                0x00ef_cdab_9078_5634,
3308                0xbeef_feed
3309            ]
3310        );
3311        test_args_serde!(
3312            SuccessArgs::Args64_2([
3313                0x0018_2222_0002_0004,
3314                0,
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            ]),
3330            SuccessArgsPartitionInfoGetRegs {
3331                last_index: 4,
3332                current_index: 2,
3333                info_tag: 0x2222,
3334                descriptor_data: [0; 120]
3335            }
3336        );
3337    }
3338
3339    #[test]
3340    fn ffa_id_get_serde() {
3341        test_regs_serde!(Interface::IdGet, [0x84000069]);
3342        test_args_serde!(
3343            SuccessArgs::Args32([0x1234, 0, 0, 0, 0, 0]),
3344            SuccessArgsIdGet { id: 0x1234 }
3345        );
3346    }
3347
3348    #[test]
3349    fn ffa_spm_id_get_serde() {
3350        test_regs_serde!(Interface::SpmIdGet, [0x84000085]);
3351        test_args_serde!(
3352            SuccessArgs::Args32([0x1234, 0, 0, 0, 0, 0]),
3353            SuccessArgsSpmIdGet { id: 0x1234 }
3354        );
3355    }
3356
3357    #[test]
3358    fn ffa_console_log_serde() {
3359        test_regs_serde!(
3360            Interface::ConsoleLog {
3361                chars: ConsoleLogChars::Chars32(LogChars {
3362                    char_cnt: 8,
3363                    char_lists: [0x6566_6768, 0x6970_7172, 0, 0, 0, 0,]
3364                })
3365            },
3366            [0x8400008A, 8, 0x6566_6768, 0x6970_7172]
3367        );
3368        test_regs_serde!(
3369            Interface::ConsoleLog {
3370                chars: ConsoleLogChars::Chars64(LogChars {
3371                    char_cnt: 8,
3372                    char_lists: [
3373                        0x6566_6768_6970_7172,
3374                        0,
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                    ]
3390                })
3391            },
3392            [0xC400008A, 8, 0x6566_6768_6970_7172]
3393        );
3394    }
3395
3396    #[test]
3397    fn ffa_msg_send2_serde() {
3398        test_regs_serde!(
3399            Interface::MsgSend2 {
3400                sender_vm_id: 0xfeed,
3401                flags: MsgSend2Flags {
3402                    delay_schedule_receiver: true
3403                }
3404            },
3405            [0x84000086, 0xfeed_0000, 0b10]
3406        );
3407    }
3408
3409    #[test]
3410    fn ffa_msg_send_direct_req_serde() {
3411        test_regs_serde!(
3412            Interface::MsgSendDirectReq {
3413                src_id: 0x8005,
3414                dst_id: 0x8003,
3415                args: DirectMsgArgs::Args32([1, 2, 3, 4, 5])
3416            },
3417            [0x8400006F, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3418        );
3419
3420        test_regs_serde!(
3421            Interface::MsgSendDirectReq {
3422                src_id: 0x8005,
3423                dst_id: 0x8003,
3424                args: DirectMsgArgs::Args64([1, 2, 3, 4, 5])
3425            },
3426            [0xC400006F, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3427        );
3428    }
3429
3430    #[test]
3431    fn ffa_msg_send_direct_resp_serde() {
3432        test_regs_serde!(
3433            Interface::MsgSendDirectResp {
3434                src_id: 0x8005,
3435                dst_id: 0x8003,
3436                args: DirectMsgArgs::Args32([1, 2, 3, 4, 5])
3437            },
3438            [0x84000070, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3439        );
3440
3441        test_regs_serde!(
3442            Interface::MsgSendDirectResp {
3443                src_id: 0x8005,
3444                dst_id: 0x8003,
3445                args: DirectMsgArgs::Args64([1, 2, 3, 4, 5])
3446            },
3447            [0xC4000070, 0x8005_8003, 0x0, 1, 2, 3, 4, 5]
3448        );
3449    }
3450
3451    #[test]
3452    fn ffa_psci_req_serde() {
3453        test_regs_serde!(
3454            Interface::MsgSendDirectReq {
3455                src_id: 0xdead,
3456                dst_id: 0xbeef,
3457                args: DirectMsgArgs::PowerPsciReq32 {
3458                    params: [1, 2, 3, 4]
3459                }
3460            },
3461            [0x8400006F, 0xdead_beef, 0x8000_0000, 1, 2, 3, 4]
3462        );
3463        test_regs_serde!(
3464            Interface::MsgSendDirectReq {
3465                src_id: 0xdead,
3466                dst_id: 0xbeef,
3467                args: DirectMsgArgs::PowerPsciReq64 {
3468                    params: [0x1234_5678_90ab_cdef, 2, 3, 4]
3469                }
3470            },
3471            [
3472                0xC400006F,
3473                0xdead_beef,
3474                0x8000_0000,
3475                0x1234_5678_90ab_cdef,
3476                2,
3477                3,
3478                4
3479            ]
3480        );
3481    }
3482
3483    #[test]
3484    fn ffa_power_warm_boot_req_serde() {
3485        test_regs_serde!(
3486            Interface::MsgSendDirectReq {
3487                src_id: 0xdead,
3488                dst_id: 0xbeef,
3489                args: DirectMsgArgs::PowerWarmBootReq {
3490                    boot_type: WarmBootType::ExitFromLowPower
3491                }
3492            },
3493            [0x8400006F, 0xdead_beef, 0x80000001, 0b1]
3494        );
3495        test_regs_serde!(
3496            Interface::MsgSendDirectReq {
3497                src_id: 0xdead,
3498                dst_id: 0xbeef,
3499                args: DirectMsgArgs::PowerWarmBootReq {
3500                    boot_type: WarmBootType::ExitFromSuspend
3501                }
3502            },
3503            [0x8400006F, 0xdead_beef, 0x80000001, 0b0]
3504        );
3505    }
3506
3507    #[test]
3508    fn ffa_power_resp_serde() {
3509        test_regs_serde!(
3510            Interface::MsgSendDirectResp {
3511                src_id: 0xdead,
3512                dst_id: 0xbeef,
3513                args: DirectMsgArgs::PowerPsciResp {
3514                    psci_status: 0x1234
3515                }
3516            },
3517            [0x84000070, 0xdead_beef, 0x8000_0002, 0x1234]
3518        );
3519    }
3520
3521    #[test]
3522    fn ffa_vm_creation_req() {
3523        test_regs_serde!(
3524            Interface::MsgSendDirectReq {
3525                src_id: 0xdead,
3526                dst_id: 0xbeef,
3527                args: DirectMsgArgs::VmCreated {
3528                    handle: Handle(0x1234_5678_90ab_cdef),
3529                    vm_id: 0x1234
3530                }
3531            },
3532            [
3533                0x8400006F,
3534                0xdead_beef,
3535                0x8000_0004,
3536                0x90ab_cdef,
3537                0x1234_5678,
3538                0x1234
3539            ]
3540        );
3541    }
3542
3543    #[test]
3544    fn ffa_vm_creation_resp() {
3545        test_regs_serde!(
3546            Interface::MsgSendDirectResp {
3547                src_id: 0xdead,
3548                dst_id: 0xbeef,
3549                args: DirectMsgArgs::VmCreatedAck {
3550                    sp_status: VmAvailabilityStatus::Success
3551                }
3552            },
3553            [0x84000070, 0xdead_beef, 0x8000_0005]
3554        );
3555        test_regs_serde!(
3556            Interface::MsgSendDirectResp {
3557                src_id: 0xdead,
3558                dst_id: 0xbeef,
3559                args: DirectMsgArgs::VmCreatedAck {
3560                    sp_status: VmAvailabilityStatus::Error(FfaError::Retry)
3561                }
3562            },
3563            [0x84000070, 0xdead_beef, 0x8000_0005, error_code(-7)]
3564        );
3565    }
3566
3567    #[test]
3568    fn ffa_vm_destruction_req() {
3569        test_regs_serde!(
3570            Interface::MsgSendDirectReq {
3571                src_id: 0xdead,
3572                dst_id: 0xbeef,
3573                args: DirectMsgArgs::VmDestructed {
3574                    handle: Handle(0x1234_5678_90ab_cdef),
3575                    vm_id: 0x1234
3576                }
3577            },
3578            [
3579                0x8400006F,
3580                0xdead_beef,
3581                0x8000_0006,
3582                0x90ab_cdef,
3583                0x1234_5678,
3584                0x1234
3585            ]
3586        );
3587    }
3588
3589    #[test]
3590    fn ffa_vm_destruction_resp() {
3591        test_regs_serde!(
3592            Interface::MsgSendDirectResp {
3593                src_id: 0xdead,
3594                dst_id: 0xbeef,
3595                args: DirectMsgArgs::VmDestructedAck {
3596                    sp_status: VmAvailabilityStatus::Success
3597                }
3598            },
3599            [0x84000070, 0xdead_beef, 0x8000_0007]
3600        );
3601        test_regs_serde!(
3602            Interface::MsgSendDirectResp {
3603                src_id: 0xdead,
3604                dst_id: 0xbeef,
3605                args: DirectMsgArgs::VmDestructedAck {
3606                    sp_status: VmAvailabilityStatus::Error(FfaError::Denied)
3607                }
3608            },
3609            [0x84000070, 0xdead_beef, 0x8000_0007, error_code(-6)]
3610        );
3611    }
3612
3613    #[test]
3614    fn ffa_version_req() {
3615        test_regs_serde!(
3616            Interface::MsgSendDirectReq {
3617                src_id: 0xdead,
3618                dst_id: 0xbeef,
3619                args: DirectMsgArgs::VersionReq {
3620                    version: Version(1, 2)
3621                }
3622            },
3623            [0x8400006F, 0xdead_beef, 0x8000_0008, 0x0001_0002]
3624        );
3625    }
3626
3627    #[test]
3628    fn ffa_version_resp() {
3629        test_regs_serde!(
3630            Interface::MsgSendDirectResp {
3631                src_id: 0xdead,
3632                dst_id: 0xbeef,
3633                args: DirectMsgArgs::VersionResp {
3634                    version: Some(Version(1, 2))
3635                }
3636            },
3637            [0x84000070, 0xdead_beef, 0x8000_0009, 0x0001_0002]
3638        );
3639        test_regs_serde!(
3640            Interface::MsgSendDirectResp {
3641                src_id: 0xdead,
3642                dst_id: 0xbeef,
3643                args: DirectMsgArgs::VersionResp { version: None }
3644            },
3645            [0x84000070, 0xdead_beef, 0x8000_0009, u32::MAX as u64]
3646        );
3647    }
3648
3649    #[test]
3650    fn ffa_msg_send_direct_req2_serde() {
3651        test_regs_serde!(
3652            Interface::MsgSendDirectReq2 {
3653                src_id: 0x1234,
3654                dst_id: 0xdcba,
3655                uuid: uuid!("12345678-abcd-ef12-3456-7890abcdef00"),
3656                args: DirectMsg2Args([4; 14])
3657            },
3658            [
3659                0xC400008D,
3660                0x1234_dcba,
3661                0x12ef_cdab_7856_3412,
3662                0x00ef_cdab_9078_5634,
3663                4,
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            ]
3678        );
3679    }
3680
3681    #[test]
3682    fn ffa_msg_send_direct_resp2_serde() {
3683        test_regs_serde!(
3684            Interface::MsgSendDirectResp2 {
3685                src_id: 0xaaaa,
3686                dst_id: 0xbbbb,
3687                args: DirectMsg2Args([8; 14])
3688            },
3689            [
3690                0xC400008E,
3691                0xaaaa_bbbb,
3692                0,
3693                0,
3694                8,
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            ]
3709        );
3710    }
3711
3712    #[test]
3713    fn ffa_msg_wait_serde() {
3714        test_regs_serde!(
3715            Interface::MsgWait {
3716                flags: Some(MsgWaitFlags {
3717                    retain_rx_buffer: true
3718                })
3719            },
3720            [0x8400006B, 0, 0b1]
3721        );
3722    }
3723
3724    #[test]
3725    fn ffa_yield_serde() {
3726        test_regs_serde!(Interface::Yield, [0x8400006C]);
3727    }
3728
3729    #[test]
3730    fn ffa_run_serde() {
3731        test_regs_serde!(
3732            Interface::Run {
3733                target_info: TargetInfo {
3734                    endpoint_id: 0xaaaa,
3735                    vcpu_id: 0x1234
3736                }
3737            },
3738            [0x8400006D, 0xaaaa_1234]
3739        );
3740    }
3741
3742    #[test]
3743    fn ffa_normal_world_resume_serde() {
3744        test_regs_serde!(Interface::NormalWorldResume, [0x8400007C]);
3745    }
3746
3747    #[test]
3748    fn ffa_notification_bitmap_create_serde() {
3749        test_regs_serde!(
3750            Interface::NotificationBitmapCreate {
3751                vm_id: 0xabcd,
3752                vcpu_cnt: 16
3753            },
3754            [0x8400007D, 0xabcd, 16]
3755        );
3756    }
3757
3758    #[test]
3759    fn ffa_notification_bitmap_destroy_serde() {
3760        test_regs_serde!(
3761            Interface::NotificationBitmapDestroy { vm_id: 0xabcd },
3762            [0x8400007E, 0xabcd]
3763        );
3764    }
3765
3766    #[test]
3767    fn ffa_notification_bind_serde() {
3768        test_regs_serde!(
3769            Interface::NotificationBind {
3770                sender_id: 0xdead,
3771                receiver_id: 0xbeef,
3772                flags: NotificationBindFlags {
3773                    per_vcpu_notification: true
3774                },
3775                bitmap: 0x1234_abcd_5678_def0
3776            },
3777            [0x8400007F, 0xdead_beef, 0b1, 0x5678_def0, 0x1234_abcd]
3778        );
3779    }
3780
3781    #[test]
3782    fn ffa_notification_unbind_serde() {
3783        test_regs_serde!(
3784            Interface::NotificationUnbind {
3785                sender_id: 0xaaaa,
3786                receiver_id: 0xbbbb,
3787                bitmap: 0x1234_abcd_5678_def0
3788            },
3789            [0x84000080, 0xaaaa_bbbb, 0, 0x5678_def0, 0x1234_abcd]
3790        );
3791    }
3792
3793    #[test]
3794    fn ffa_notification_set_serde() {
3795        test_regs_serde!(
3796            Interface::NotificationSet {
3797                sender_id: 0xaaaa,
3798                receiver_id: 0xbbbb,
3799                flags: NotificationSetFlags {
3800                    delay_schedule_receiver: true,
3801                    vcpu_id: Some(7)
3802                },
3803                bitmap: 0x1234_abcd_5678_def0
3804            },
3805            [
3806                0x84000081,
3807                0xaaaa_bbbb,
3808                0x0007_0003,
3809                0x5678_def0,
3810                0x1234_abcd
3811            ]
3812        );
3813        test_regs_serde!(
3814            Interface::NotificationSet {
3815                sender_id: 0xaaaa,
3816                receiver_id: 0xbbbb,
3817                flags: NotificationSetFlags {
3818                    delay_schedule_receiver: false,
3819                    vcpu_id: None
3820                },
3821                bitmap: 0x1234_abcd_5678_def0
3822            },
3823            [0x84000081, 0xaaaa_bbbb, 0, 0x5678_def0, 0x1234_abcd]
3824        );
3825    }
3826
3827    #[test]
3828    fn ffa_notification_get_serde() {
3829        test_regs_serde!(
3830            Interface::NotificationGet {
3831                vcpu_id: 13,
3832                endpoint_id: 0x1234,
3833                flags: NotificationGetFlags {
3834                    sp_bitmap_id: false,
3835                    vm_bitmap_id: true,
3836                    spm_bitmap_id: true,
3837                    hyp_bitmap_id: false
3838                }
3839            },
3840            [0x84000082, 0x000d_1234, 0b0110]
3841        );
3842        test_regs_serde!(
3843            Interface::NotificationGet {
3844                vcpu_id: 13,
3845                endpoint_id: 0x1234,
3846                flags: NotificationGetFlags {
3847                    sp_bitmap_id: false,
3848                    vm_bitmap_id: false,
3849                    spm_bitmap_id: false,
3850                    hyp_bitmap_id: false
3851                }
3852            },
3853            [0x84000082, 0x000d_1234, 0b0000]
3854        );
3855        test_regs_serde!(
3856            Interface::NotificationGet {
3857                vcpu_id: 13,
3858                endpoint_id: 0x1234,
3859                flags: NotificationGetFlags {
3860                    sp_bitmap_id: true,
3861                    vm_bitmap_id: true,
3862                    spm_bitmap_id: true,
3863                    hyp_bitmap_id: true
3864                }
3865            },
3866            [0x84000082, 0x000d_1234, 0b1111]
3867        );
3868
3869        test_args_serde!(
3870            SuccessArgsNotificationGet {
3871                sp_notifications: None,
3872                vm_notifications: None,
3873                spm_notifications: None,
3874                hypervisor_notifications: None
3875            },
3876            SuccessArgs::Args32([0, 0, 0, 0, 0, 0]),
3877            NotificationGetFlags {
3878                sp_bitmap_id: false,
3879                vm_bitmap_id: false,
3880                spm_bitmap_id: false,
3881                hyp_bitmap_id: false
3882            }
3883        );
3884        test_args_serde!(
3885            SuccessArgsNotificationGet {
3886                sp_notifications: None,
3887                vm_notifications: Some(0xdead_beef_1234_1234),
3888                spm_notifications: None,
3889                hypervisor_notifications: Some(0x1234_5678)
3890            },
3891            SuccessArgs::Args32([0, 0, 0x1234_1234, 0xdead_beef, 0, 0x1234_5678]),
3892            NotificationGetFlags {
3893                sp_bitmap_id: false,
3894                vm_bitmap_id: true,
3895                spm_bitmap_id: false,
3896                hyp_bitmap_id: true
3897            }
3898        );
3899
3900        test_args_serde!(
3901            SuccessArgsNotificationGet {
3902                sp_notifications: Some(0x1000),
3903                vm_notifications: Some(0xdead_beef_1234_1234),
3904                spm_notifications: Some(0x2000),
3905                hypervisor_notifications: Some(0x1234_5678)
3906            },
3907            SuccessArgs::Args32([0x1000, 0, 0x1234_1234, 0xdead_beef, 0x2000, 0x1234_5678]),
3908            NotificationGetFlags {
3909                sp_bitmap_id: true,
3910                vm_bitmap_id: true,
3911                spm_bitmap_id: true,
3912                hyp_bitmap_id: true
3913            }
3914        );
3915    }
3916
3917    #[test]
3918    fn ffa_notification_info_get_serde() {
3919        test_regs_serde!(
3920            Interface::NotificationInfoGet { is_32bit: true },
3921            [0x84000083]
3922        );
3923        test_regs_serde!(
3924            Interface::NotificationInfoGet { is_32bit: false },
3925            [0xC4000083]
3926        );
3927        test_args_serde!(
3928            SuccessArgs::Args32([0b1001_0001_0000_0001, 0xbbbb_cccc, 0xaaaa, 0, 0, 0]),
3929            SuccessArgsNotificationInfoGet {
3930                more_pending_notifications: true,
3931                list_count: 2,
3932                id_counts: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0],
3933                ids: [0xcccc, 0xbbbb, 0xaaaa, 0, 0, 0, 0, 0, 0, 0]
3934            }
3935        );
3936    }
3937
3938    #[test]
3939    fn log_chars_empty() {
3940        assert!(ConsoleLogChars64 {
3941            char_cnt: 0,
3942            char_lists: [0; 16]
3943        }
3944        .empty())
3945    }
3946
3947    #[test]
3948    fn log_chars_push() {
3949        let mut console = ConsoleLogChars64 {
3950            char_cnt: 0,
3951            char_lists: [0; 16],
3952        };
3953
3954        assert_eq!(console.push("hello world!".as_bytes()), 12);
3955
3956        assert_eq!(console.char_cnt, 12);
3957        assert_eq!(&console.bytes()[0..12], "hello world!".as_bytes());
3958        assert!(!console.empty());
3959    }
3960
3961    #[test]
3962    fn log_chars_full() {
3963        let mut console = ConsoleLogChars64 {
3964            char_cnt: 0,
3965            char_lists: [0; 16],
3966        };
3967
3968        assert_eq!(console.push(&[97; 128]), 128);
3969
3970        assert!(console.full());
3971    }
3972
3973    #[test]
3974    fn success_args_invalid_variants() {
3975        assert!(SuccessArgs::Args32([0; 6]).try_get_args64_2().is_err());
3976        assert!(SuccessArgs::Args64([0; 6]).try_get_args64_2().is_err());
3977
3978        assert!(SuccessArgs::Args64([0; 6]).try_get_args32().is_err());
3979        assert!(SuccessArgs::Args64_2([0; 16]).try_get_args32().is_err());
3980
3981        assert!(SuccessArgs::Args32([0; 6]).try_get_args64().is_err());
3982        assert!(SuccessArgs::Args64_2([0; 16]).try_get_args64().is_err());
3983    }
3984
3985    #[test]
3986    fn ffa_el3_intr_handle_serde() {
3987        test_regs_serde!(Interface::El3IntrHandle, [0x8400008C]);
3988    }
3989
3990    #[test]
3991    fn ffa_secondary_ep_regs32() {
3992        test_regs_serde!(
3993            Interface::SecondaryEpRegister {
3994                entrypoint: SecondaryEpRegisterAddr::Addr32(0xdead_beef)
3995            },
3996            [0x84000087, 0xdead_beef]
3997        );
3998    }
3999
4000    #[test]
4001    fn ffa_secondary_ep_regs64() {
4002        test_regs_serde!(
4003            Interface::SecondaryEpRegister {
4004                entrypoint: SecondaryEpRegisterAddr::Addr64(0x1234_5678_90ab_cdef)
4005            },
4006            [0xC4000087, 0x1234_5678_90ab_cdef]
4007        );
4008    }
4009}