arm_ffa/
lib.rs

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