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, IntoBytes};
14
15pub mod boot_info;
16mod ffa_v1_1;
17mod ffa_v1_2;
18pub mod memory_management;
19pub mod partition_info;
20
21/// Constant for 4K page size. On many occasions the FF-A spec defines memory size as count of 4K
22/// pages, regardless of the current translation granule.
23pub const FFA_PAGE_SIZE_4K: usize = 4096;
24
25/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
26/// with the `FFA_ERROR` interface.
27#[derive(Debug, Error, PartialEq)]
28pub enum Error {
29    #[error("Unrecognised FF-A function ID {0}")]
30    UnrecognisedFunctionId(u32),
31    #[error("Unrecognised FF-A feature ID {0}")]
32    UnrecognisedFeatureId(u8),
33    #[error("Unrecognised FF-A error code {0}")]
34    UnrecognisedErrorCode(i32),
35    #[error("Unrecognised FF-A Framework Message {0}")]
36    UnrecognisedFwkMsg(u32),
37    #[error("Invalid FF-A Msg Wait Flag {0}")]
38    InvalidMsgWaitFlag(u32),
39    #[error("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                _ => panic!("Invalid direct request arguments: {:#?}", args),
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                _ => panic!("Invalid direct response arguments: {:#?}", args),
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        if matches!(self, Self::VersionOut { .. }) {
1373            return true;
1374        }
1375
1376        self.function_id().unwrap().is_32bit()
1377    }
1378
1379    /// Returns the FF-A version that has introduced the function ID.
1380    pub fn minimum_ffa_version(&self) -> Version {
1381        if matches!(self, Self::VersionOut { .. }) {
1382            return Version(1, 0);
1383        }
1384
1385        self.function_id().unwrap().minimum_ffa_version()
1386    }
1387
1388    /// Parse interface from register contents. The caller must ensure that the `regs` argument has
1389    /// the correct length: 8 registers for FF-A v1.1 and lower, 18 registers for v1.2 and higher.
1390    pub fn from_regs(version: Version, regs: &[u64]) -> Result<Self, Error> {
1391        let func_id = FuncId::try_from(regs[0] as u32)?;
1392        if version < func_id.minimum_ffa_version() {
1393            return Err(Error::InvalidVersionForFunctionId(version, func_id));
1394        }
1395
1396        let reg_cnt = regs.len();
1397
1398        let msg = match reg_cnt {
1399            8 => {
1400                assert!(version <= Version(1, 1));
1401                Interface::unpack_regs8(version, regs.try_into().unwrap())?
1402            }
1403            18 => {
1404                assert!(version >= Version(1, 2));
1405                match func_id {
1406                    FuncId::ConsoleLog64
1407                    | FuncId::Success64
1408                    | FuncId::MsgSendDirectReq64_2
1409                    | FuncId::MsgSendDirectResp64_2
1410                    | FuncId::PartitionInfoGetRegs => {
1411                        Interface::unpack_regs18(version, regs.try_into().unwrap())?
1412                    }
1413                    _ => Interface::unpack_regs8(version, regs[..8].try_into().unwrap())?,
1414                }
1415            }
1416            _ => panic!(
1417                "Invalid number of registers ({}) for FF-A version {}",
1418                reg_cnt, version
1419            ),
1420        };
1421
1422        Ok(msg)
1423    }
1424
1425    fn unpack_regs8(version: Version, regs: &[u64; 8]) -> Result<Self, Error> {
1426        let fid = FuncId::try_from(regs[0] as u32)?;
1427
1428        let msg = match fid {
1429            FuncId::Error => Self::Error {
1430                target_info: (regs[1] as u32).into(),
1431                error_code: FfaError::try_from(regs[2] as i32)?,
1432                error_arg: regs[3] as u32,
1433            },
1434            FuncId::Success32 => Self::Success {
1435                target_info: regs[1] as u32,
1436                args: SuccessArgs::Args32([
1437                    regs[2] as u32,
1438                    regs[3] as u32,
1439                    regs[4] as u32,
1440                    regs[5] as u32,
1441                    regs[6] as u32,
1442                    regs[7] as u32,
1443                ]),
1444            },
1445            FuncId::Success64 => Self::Success {
1446                target_info: regs[1] as u32,
1447                args: SuccessArgs::Args64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
1448            },
1449            FuncId::Interrupt => Self::Interrupt {
1450                target_info: (regs[1] as u32).into(),
1451                interrupt_id: regs[2] as u32,
1452            },
1453            FuncId::Version => Self::Version {
1454                input_version: (regs[1] as u32).try_into()?,
1455            },
1456            FuncId::Features => Self::Features {
1457                feat_id: (regs[1] as u32).into(),
1458                input_properties: regs[2] as u32,
1459            },
1460            FuncId::RxAcquire => Self::RxAcquire {
1461                vm_id: regs[1] as u16,
1462            },
1463            FuncId::RxRelease => Self::RxRelease {
1464                vm_id: regs[1] as u16,
1465            },
1466            FuncId::RxTxMap32 => {
1467                let addr = RxTxAddr::Addr32 {
1468                    rx: regs[2] as u32,
1469                    tx: regs[1] as u32,
1470                };
1471                let page_cnt = regs[3] as u32;
1472
1473                Self::RxTxMap { addr, page_cnt }
1474            }
1475            FuncId::RxTxMap64 => {
1476                let addr = RxTxAddr::Addr64 {
1477                    rx: regs[2],
1478                    tx: regs[1],
1479                };
1480                let page_cnt = regs[3] as u32;
1481
1482                Self::RxTxMap { addr, page_cnt }
1483            }
1484            FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
1485            FuncId::PartitionInfoGet => {
1486                let uuid_words = [
1487                    regs[1] as u32,
1488                    regs[2] as u32,
1489                    regs[3] as u32,
1490                    regs[4] as u32,
1491                ];
1492                let mut bytes: [u8; 16] = [0; 16];
1493                for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
1494                    bytes[i] = b;
1495                }
1496                Self::PartitionInfoGet {
1497                    uuid: Uuid::from_bytes(bytes),
1498                    flags: PartitionInfoGetFlags::try_from(regs[5] as u32)?,
1499                }
1500            }
1501            FuncId::IdGet => Self::IdGet,
1502            FuncId::SpmIdGet => Self::SpmIdGet,
1503            FuncId::MsgWait => Self::MsgWait {
1504                flags: if version >= Version(1, 2) {
1505                    Some(MsgWaitFlags::try_from(regs[2] as u32)?)
1506                } else {
1507                    None
1508                },
1509            },
1510            FuncId::Yield => Self::Yield,
1511            FuncId::Run => Self::Run {
1512                target_info: (regs[1] as u32).into(),
1513            },
1514            FuncId::NormalWorldResume => Self::NormalWorldResume,
1515            FuncId::SecondaryEpRegister32 => Self::SecondaryEpRegister {
1516                entrypoint: SecondaryEpRegisterAddr::Addr32(regs[1] as u32),
1517            },
1518            FuncId::SecondaryEpRegister64 => Self::SecondaryEpRegister {
1519                entrypoint: SecondaryEpRegisterAddr::Addr64(regs[1]),
1520            },
1521            FuncId::MsgSend2 => Self::MsgSend2 {
1522                sender_vm_id: regs[1] as u16,
1523                flags: regs[2] as u32,
1524            },
1525            FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
1526                src_id: (regs[1] >> 16) as u16,
1527                dst_id: regs[1] as u16,
1528                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1529                    match regs[2] as u32 {
1530                        DirectMsgArgs::VERSION_REQ => DirectMsgArgs::VersionReq {
1531                            version: Version::try_from(regs[3] as u32)?,
1532                        },
1533                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq32 {
1534                            params: [
1535                                regs[3] as u32,
1536                                regs[4] as u32,
1537                                regs[5] as u32,
1538                                regs[6] as u32,
1539                            ],
1540                        },
1541                        DirectMsgArgs::POWER_WARM_BOOT_REQ => DirectMsgArgs::PowerWarmBootReq {
1542                            boot_type: WarmBootType::try_from(regs[3] as u32)?,
1543                        },
1544                        DirectMsgArgs::VM_CREATED => DirectMsgArgs::VmCreated {
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                        DirectMsgArgs::VM_DESTRUCTED => DirectMsgArgs::VmDestructed {
1552                            handle: memory_management::Handle::from([
1553                                regs[3] as u32,
1554                                regs[4] as u32,
1555                            ]),
1556                            vm_id: regs[5] as u16,
1557                        },
1558                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1559                    }
1560                } else {
1561                    DirectMsgArgs::Args32([
1562                        regs[3] as u32,
1563                        regs[4] as u32,
1564                        regs[5] as u32,
1565                        regs[6] as u32,
1566                        regs[7] as u32,
1567                    ])
1568                },
1569            },
1570            FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
1571                src_id: (regs[1] >> 16) as u16,
1572                dst_id: regs[1] as u16,
1573                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1574                    match regs[2] as u32 {
1575                        DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq64 {
1576                            params: [regs[3], regs[4], regs[5], regs[6]],
1577                        },
1578                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1579                    }
1580                } else {
1581                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1582                },
1583            },
1584            FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
1585                src_id: (regs[1] >> 16) as u16,
1586                dst_id: regs[1] as u16,
1587                args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
1588                    match regs[2] as u32 {
1589                        DirectMsgArgs::VERSION_RESP => {
1590                            if regs[3] as i32 == FfaError::NotSupported.into() {
1591                                DirectMsgArgs::VersionResp { version: None }
1592                            } else {
1593                                DirectMsgArgs::VersionResp {
1594                                    version: Some(Version::try_from(regs[3] as u32)?),
1595                                }
1596                            }
1597                        }
1598                        DirectMsgArgs::POWER_PSCI_RESP => DirectMsgArgs::PowerPsciResp {
1599                            psci_status: regs[3] as i32,
1600                        },
1601                        DirectMsgArgs::VM_CREATED_ACK => DirectMsgArgs::VmCreatedAck {
1602                            sp_status: (regs[3] as i32).try_into()?,
1603                        },
1604                        DirectMsgArgs::VM_DESTRUCTED_ACK => DirectMsgArgs::VmDestructedAck {
1605                            sp_status: (regs[3] as i32).try_into()?,
1606                        },
1607                        _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
1608                    }
1609                } else {
1610                    DirectMsgArgs::Args32([
1611                        regs[3] as u32,
1612                        regs[4] as u32,
1613                        regs[5] as u32,
1614                        regs[6] as u32,
1615                        regs[7] as u32,
1616                    ])
1617                },
1618            },
1619            FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
1620                src_id: (regs[1] >> 16) as u16,
1621                dst_id: regs[1] as u16,
1622                args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
1623                    return Err(Error::UnrecognisedFwkMsg(regs[2] as u32));
1624                } else {
1625                    DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
1626                },
1627            },
1628            FuncId::MemDonate32 => Self::MemDonate {
1629                total_len: regs[1] as u32,
1630                frag_len: regs[2] as u32,
1631                buf: if regs[3] != 0 && regs[4] != 0 {
1632                    Some(MemOpBuf::Buf32 {
1633                        addr: regs[3] as u32,
1634                        page_cnt: regs[4] as u32,
1635                    })
1636                } else {
1637                    None
1638                },
1639            },
1640            FuncId::MemDonate64 => Self::MemDonate {
1641                total_len: regs[1] as u32,
1642                frag_len: regs[2] as u32,
1643                buf: if regs[3] != 0 && regs[4] != 0 {
1644                    Some(MemOpBuf::Buf64 {
1645                        addr: regs[3],
1646                        page_cnt: regs[4] as u32,
1647                    })
1648                } else {
1649                    None
1650                },
1651            },
1652            FuncId::MemLend32 => Self::MemLend {
1653                total_len: regs[1] as u32,
1654                frag_len: regs[2] as u32,
1655                buf: if regs[3] != 0 && regs[4] != 0 {
1656                    Some(MemOpBuf::Buf32 {
1657                        addr: regs[3] as u32,
1658                        page_cnt: regs[4] as u32,
1659                    })
1660                } else {
1661                    None
1662                },
1663            },
1664            FuncId::MemLend64 => Self::MemLend {
1665                total_len: regs[1] as u32,
1666                frag_len: regs[2] as u32,
1667                buf: if regs[3] != 0 && regs[4] != 0 {
1668                    Some(MemOpBuf::Buf64 {
1669                        addr: regs[3],
1670                        page_cnt: regs[4] as u32,
1671                    })
1672                } else {
1673                    None
1674                },
1675            },
1676            FuncId::MemShare32 => Self::MemShare {
1677                total_len: regs[1] as u32,
1678                frag_len: regs[2] as u32,
1679                buf: if regs[3] != 0 && regs[4] != 0 {
1680                    Some(MemOpBuf::Buf32 {
1681                        addr: regs[3] as u32,
1682                        page_cnt: regs[4] as u32,
1683                    })
1684                } else {
1685                    None
1686                },
1687            },
1688            FuncId::MemShare64 => Self::MemShare {
1689                total_len: regs[1] as u32,
1690                frag_len: regs[2] as u32,
1691                buf: if regs[3] != 0 && regs[4] != 0 {
1692                    Some(MemOpBuf::Buf64 {
1693                        addr: regs[3],
1694                        page_cnt: regs[4] as u32,
1695                    })
1696                } else {
1697                    None
1698                },
1699            },
1700            FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
1701                total_len: regs[1] as u32,
1702                frag_len: regs[2] as u32,
1703                buf: if regs[3] != 0 && regs[4] != 0 {
1704                    Some(MemOpBuf::Buf32 {
1705                        addr: regs[3] as u32,
1706                        page_cnt: regs[4] as u32,
1707                    })
1708                } else {
1709                    None
1710                },
1711            },
1712            FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
1713                total_len: regs[1] as u32,
1714                frag_len: regs[2] as u32,
1715                buf: if regs[3] != 0 && regs[4] != 0 {
1716                    Some(MemOpBuf::Buf64 {
1717                        addr: regs[3],
1718                        page_cnt: regs[4] as u32,
1719                    })
1720                } else {
1721                    None
1722                },
1723            },
1724            FuncId::MemRetrieveResp => Self::MemRetrieveResp {
1725                total_len: regs[1] as u32,
1726                frag_len: regs[2] as u32,
1727            },
1728            FuncId::MemRelinquish => Self::MemRelinquish,
1729            FuncId::MemReclaim => Self::MemReclaim {
1730                handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
1731                flags: regs[3] as u32,
1732            },
1733            FuncId::MemPermGet32 => Self::MemPermGet {
1734                addr: MemAddr::Addr32(regs[1] as u32),
1735                page_cnt: if version >= Version(1, 3) {
1736                    Some(regs[2] as u32)
1737                } else {
1738                    None
1739                },
1740            },
1741            FuncId::MemPermGet64 => Self::MemPermGet {
1742                addr: MemAddr::Addr64(regs[1]),
1743                page_cnt: if version >= Version(1, 3) {
1744                    Some(regs[2] as u32)
1745                } else {
1746                    None
1747                },
1748            },
1749            FuncId::MemPermSet32 => Self::MemPermSet {
1750                addr: MemAddr::Addr32(regs[1] as u32),
1751                page_cnt: regs[2] as u32,
1752                mem_perm: regs[3] as u32,
1753            },
1754            FuncId::MemPermSet64 => Self::MemPermSet {
1755                addr: MemAddr::Addr64(regs[1]),
1756                page_cnt: regs[2] as u32,
1757                mem_perm: regs[3] as u32,
1758            },
1759            FuncId::ConsoleLog32 => Self::ConsoleLog {
1760                char_cnt: regs[1] as u8,
1761                char_lists: ConsoleLogChars::Reg32([
1762                    regs[2] as u32,
1763                    regs[3] as u32,
1764                    regs[4] as u32,
1765                    regs[5] as u32,
1766                    regs[6] as u32,
1767                    regs[7] as u32,
1768                ]),
1769            },
1770            FuncId::NotificationBitmapCreate => {
1771                let tentative_vm_id = regs[1] as u32;
1772                if (tentative_vm_id >> 16) != 0 {
1773                    return Err(Error::InvalidVmId(tentative_vm_id));
1774                }
1775                Self::NotificationBitmapCreate {
1776                    vm_id: tentative_vm_id as u16,
1777                    vcpu_cnt: regs[2] as u32,
1778                }
1779            }
1780            FuncId::NotificationBitmapDestroy => {
1781                let tentative_vm_id = regs[1] as u32;
1782                if (tentative_vm_id >> 16) != 0 {
1783                    return Err(Error::InvalidVmId(tentative_vm_id));
1784                }
1785                Self::NotificationBitmapDestroy {
1786                    vm_id: tentative_vm_id as u16,
1787                }
1788            }
1789            FuncId::NotificationBind => Self::NotificationBind {
1790                sender_id: (regs[1] >> 16) as u16,
1791                receiver_id: regs[1] as u16,
1792                flags: (regs[2] as u32).into(),
1793                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
1794            },
1795            FuncId::NotificationUnbind => Self::NotificationUnBind {
1796                sender_id: (regs[1] >> 16) as u16,
1797                receiver_id: regs[1] as u16,
1798                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
1799            },
1800            FuncId::NotificationSet => Self::NotificationSet {
1801                sender_id: (regs[1] >> 16) as u16,
1802                receiver_id: regs[1] as u16,
1803                flags: (regs[2] as u32).try_into()?,
1804                bitmap: (regs[4] << 32) | (regs[3] & 0xffff_ffff),
1805            },
1806            FuncId::NotificationGet => Self::NotificationGet {
1807                vcpu_id: (regs[1] >> 16) as u16,
1808                endpoint_id: regs[1] as u16,
1809                flags: (regs[2] as u32).into(),
1810            },
1811            FuncId::NotificationInfoGet32 => Self::NotificationInfoGet { is_32bit: true },
1812            FuncId::NotificationInfoGet64 => Self::NotificationInfoGet { is_32bit: false },
1813            FuncId::El3IntrHandle => Self::El3IntrHandle,
1814            _ => panic!("Invalid number of registers (8) for function {:#x?}", fid),
1815        };
1816
1817        Ok(msg)
1818    }
1819
1820    fn unpack_regs18(version: Version, regs: &[u64; 18]) -> Result<Self, Error> {
1821        assert!(version >= Version(1, 2));
1822
1823        let fid = FuncId::try_from(regs[0] as u32)?;
1824
1825        let msg = match fid {
1826            FuncId::Success64 => Self::Success {
1827                target_info: regs[1] as u32,
1828                args: SuccessArgs::Args64_2(regs[2..18].try_into().unwrap()),
1829            },
1830            FuncId::MsgSendDirectReq64_2 => Self::MsgSendDirectReq2 {
1831                src_id: (regs[1] >> 16) as u16,
1832                dst_id: regs[1] as u16,
1833                uuid: Uuid::from_u64_pair(regs[2].swap_bytes(), regs[3].swap_bytes()),
1834                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
1835            },
1836            FuncId::MsgSendDirectResp64_2 => Self::MsgSendDirectResp2 {
1837                src_id: (regs[1] >> 16) as u16,
1838                dst_id: regs[1] as u16,
1839                args: DirectMsg2Args(regs[4..18].try_into().unwrap()),
1840            },
1841            FuncId::ConsoleLog64 => Self::ConsoleLog {
1842                char_cnt: regs[1] as u8,
1843                char_lists: ConsoleLogChars::Reg64(regs[2..18].try_into().unwrap()),
1844            },
1845            FuncId::PartitionInfoGetRegs => {
1846                // Bits[15:0]: Start index
1847                let start_index = (regs[3] & 0xffff) as u16;
1848                let info_tag = ((regs[3] >> 16) & 0xffff) as u16;
1849                Self::PartitionInfoGetRegs {
1850                    uuid: Uuid::from_u64_pair(regs[1].swap_bytes(), regs[2].swap_bytes()),
1851                    start_index,
1852                    info_tag: if start_index == 0 && info_tag != 0 {
1853                        return Err(Error::InvalidInformationTag(info_tag));
1854                    } else {
1855                        info_tag
1856                    },
1857                }
1858            }
1859            _ => panic!("Invalid number of registers (18) for function {:#x?}", fid),
1860        };
1861
1862        Ok(msg)
1863    }
1864
1865    /// Create register contents for an interface.
1866    pub fn to_regs(&self, version: Version, regs: &mut [u64]) {
1867        assert!(self.minimum_ffa_version() <= version);
1868
1869        let reg_cnt = regs.len();
1870
1871        match reg_cnt {
1872            8 => {
1873                assert!(version <= Version(1, 1));
1874                regs.fill(0);
1875
1876                self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
1877            }
1878            18 => {
1879                assert!(version >= Version(1, 2));
1880                regs.fill(0);
1881
1882                match self {
1883                    Interface::ConsoleLog {
1884                        char_lists: ConsoleLogChars::Reg64(_),
1885                        ..
1886                    }
1887                    | Interface::Success {
1888                        args: SuccessArgs::Args64_2(_),
1889                        ..
1890                    }
1891                    | Interface::MsgSendDirectReq2 { .. }
1892                    | Interface::MsgSendDirectResp2 { .. }
1893                    | Interface::PartitionInfoGetRegs { .. } => {
1894                        self.pack_regs18(version, regs.try_into().unwrap());
1895                    }
1896                    _ => {
1897                        self.pack_regs8(version, (&mut regs[..8]).try_into().unwrap());
1898                    }
1899                }
1900            }
1901            _ => panic!("Invalid number of registers {}", reg_cnt),
1902        }
1903    }
1904
1905    fn pack_regs8(&self, version: Version, a: &mut [u64; 8]) {
1906        if let Some(function_id) = self.function_id() {
1907            a[0] = function_id as u64;
1908        }
1909
1910        match *self {
1911            Interface::Error {
1912                target_info,
1913                error_code,
1914                error_arg,
1915            } => {
1916                a[1] = u32::from(target_info).into();
1917                a[2] = (error_code as u32).into();
1918                a[3] = error_arg.into();
1919            }
1920            Interface::Success { target_info, args } => {
1921                a[1] = target_info.into();
1922                match args {
1923                    SuccessArgs::Args32(regs) => {
1924                        a[2] = regs[0].into();
1925                        a[3] = regs[1].into();
1926                        a[4] = regs[2].into();
1927                        a[5] = regs[3].into();
1928                        a[6] = regs[4].into();
1929                        a[7] = regs[5].into();
1930                    }
1931                    SuccessArgs::Args64(regs) => {
1932                        a[2] = regs[0];
1933                        a[3] = regs[1];
1934                        a[4] = regs[2];
1935                        a[5] = regs[3];
1936                        a[6] = regs[4];
1937                        a[7] = regs[5];
1938                    }
1939                    _ => panic!("{:#x?} requires 18 registers", args),
1940                }
1941            }
1942            Interface::Interrupt {
1943                target_info,
1944                interrupt_id,
1945            } => {
1946                a[1] = u32::from(target_info).into();
1947                a[2] = interrupt_id.into();
1948            }
1949            Interface::Version { input_version } => {
1950                a[1] = u32::from(input_version).into();
1951            }
1952            Interface::VersionOut { output_version } => {
1953                a[0] = u32::from(output_version).into();
1954            }
1955            Interface::Features {
1956                feat_id,
1957                input_properties,
1958            } => {
1959                a[1] = u32::from(feat_id).into();
1960                a[2] = input_properties.into();
1961            }
1962            Interface::RxAcquire { vm_id } => {
1963                a[1] = vm_id.into();
1964            }
1965            Interface::RxRelease { vm_id } => {
1966                a[1] = vm_id.into();
1967            }
1968            Interface::RxTxMap { addr, page_cnt } => {
1969                match addr {
1970                    RxTxAddr::Addr32 { rx, tx } => {
1971                        a[1] = tx.into();
1972                        a[2] = rx.into();
1973                    }
1974                    RxTxAddr::Addr64 { rx, tx } => {
1975                        a[1] = tx;
1976                        a[2] = rx;
1977                    }
1978                }
1979                a[3] = page_cnt.into();
1980            }
1981            Interface::RxTxUnmap { id } => {
1982                a[1] = id.into();
1983            }
1984            Interface::PartitionInfoGet { uuid, flags } => {
1985                let bytes = uuid.into_bytes();
1986                a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
1987                a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
1988                a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
1989                a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
1990                a[5] = u32::from(flags).into();
1991            }
1992            Interface::MsgWait { flags } => {
1993                if version >= Version(1, 2) {
1994                    if let Some(flags) = flags {
1995                        a[2] = u32::from(flags).into();
1996                    }
1997                }
1998            }
1999            Interface::IdGet | Interface::SpmIdGet | Interface::Yield => {}
2000            Interface::Run { target_info } => {
2001                a[1] = u32::from(target_info).into();
2002            }
2003            Interface::NormalWorldResume => {}
2004            Interface::SecondaryEpRegister { entrypoint } => match entrypoint {
2005                SecondaryEpRegisterAddr::Addr32(addr) => a[1] = addr as u64,
2006                SecondaryEpRegisterAddr::Addr64(addr) => a[1] = addr,
2007            },
2008            Interface::MsgSend2 {
2009                sender_vm_id,
2010                flags,
2011            } => {
2012                a[1] = sender_vm_id.into();
2013                a[2] = flags.into();
2014            }
2015            Interface::MsgSendDirectReq {
2016                src_id,
2017                dst_id,
2018                args,
2019            } => {
2020                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2021                match args {
2022                    DirectMsgArgs::Args32(args) => {
2023                        a[3] = args[0].into();
2024                        a[4] = args[1].into();
2025                        a[5] = args[2].into();
2026                        a[6] = args[3].into();
2027                        a[7] = args[4].into();
2028                    }
2029                    DirectMsgArgs::Args64(args) => {
2030                        a[3] = args[0];
2031                        a[4] = args[1];
2032                        a[5] = args[2];
2033                        a[6] = args[3];
2034                        a[7] = args[4];
2035                    }
2036                    DirectMsgArgs::VersionReq { version } => {
2037                        a[2] = DirectMsgArgs::VERSION_REQ.into();
2038                        a[3] = u32::from(version).into();
2039                    }
2040                    DirectMsgArgs::PowerPsciReq32 { params } => {
2041                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2042                        a[3] = params[0].into();
2043                        a[4] = params[1].into();
2044                        a[5] = params[2].into();
2045                        a[6] = params[3].into();
2046                    }
2047                    DirectMsgArgs::PowerPsciReq64 { params } => {
2048                        a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
2049                        a[3] = params[0];
2050                        a[4] = params[1];
2051                        a[5] = params[2];
2052                        a[6] = params[3];
2053                    }
2054                    DirectMsgArgs::PowerWarmBootReq { boot_type } => {
2055                        a[2] = DirectMsgArgs::POWER_WARM_BOOT_REQ.into();
2056                        a[3] = u32::from(boot_type).into();
2057                    }
2058                    DirectMsgArgs::VmCreated { handle, vm_id } => {
2059                        a[2] = DirectMsgArgs::VM_CREATED.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                    DirectMsgArgs::VmDestructed { handle, vm_id } => {
2066                        a[2] = DirectMsgArgs::VM_DESTRUCTED.into();
2067                        let handle_regs: [u32; 2] = handle.into();
2068                        a[3] = handle_regs[0].into();
2069                        a[4] = handle_regs[1].into();
2070                        a[5] = vm_id.into();
2071                    }
2072                    _ => panic!("Malformed MsgSendDirectReq interface"),
2073                }
2074            }
2075            Interface::MsgSendDirectResp {
2076                src_id,
2077                dst_id,
2078                args,
2079            } => {
2080                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2081                match args {
2082                    DirectMsgArgs::Args32(args) => {
2083                        a[3] = args[0].into();
2084                        a[4] = args[1].into();
2085                        a[5] = args[2].into();
2086                        a[6] = args[3].into();
2087                        a[7] = args[4].into();
2088                    }
2089                    DirectMsgArgs::Args64(args) => {
2090                        a[3] = args[0];
2091                        a[4] = args[1];
2092                        a[5] = args[2];
2093                        a[6] = args[3];
2094                        a[7] = args[4];
2095                    }
2096                    DirectMsgArgs::VersionResp { version } => {
2097                        a[2] = DirectMsgArgs::VERSION_RESP.into();
2098                        match version {
2099                            None => a[3] = (i32::from(FfaError::NotSupported) as u32).into(),
2100                            Some(ver) => a[3] = u32::from(ver).into(),
2101                        }
2102                    }
2103                    DirectMsgArgs::PowerPsciResp { psci_status } => {
2104                        a[2] = DirectMsgArgs::POWER_PSCI_RESP.into();
2105                        a[3] = (psci_status as u32).into();
2106                    }
2107                    DirectMsgArgs::VmCreatedAck { sp_status } => {
2108                        a[2] = DirectMsgArgs::VM_CREATED_ACK.into();
2109                        a[3] = (i32::from(sp_status) as u32).into();
2110                    }
2111                    DirectMsgArgs::VmDestructedAck { sp_status } => {
2112                        a[2] = DirectMsgArgs::VM_DESTRUCTED_ACK.into();
2113                        a[3] = (i32::from(sp_status) as u32).into();
2114                    }
2115                    _ => panic!("Malformed MsgSendDirectResp interface"),
2116                }
2117            }
2118            Interface::MemDonate {
2119                total_len,
2120                frag_len,
2121                buf,
2122            } => {
2123                a[1] = total_len.into();
2124                a[2] = frag_len.into();
2125                (a[3], a[4]) = match buf {
2126                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2127                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2128                    None => (0, 0),
2129                };
2130            }
2131            Interface::MemLend {
2132                total_len,
2133                frag_len,
2134                buf,
2135            } => {
2136                a[1] = total_len.into();
2137                a[2] = frag_len.into();
2138                (a[3], a[4]) = match buf {
2139                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2140                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2141                    None => (0, 0),
2142                };
2143            }
2144            Interface::MemShare {
2145                total_len,
2146                frag_len,
2147                buf,
2148            } => {
2149                a[1] = total_len.into();
2150                a[2] = frag_len.into();
2151                (a[3], a[4]) = match buf {
2152                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2153                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2154                    None => (0, 0),
2155                };
2156            }
2157            Interface::MemRetrieveReq {
2158                total_len,
2159                frag_len,
2160                buf,
2161            } => {
2162                a[1] = total_len.into();
2163                a[2] = frag_len.into();
2164                (a[3], a[4]) = match buf {
2165                    Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
2166                    Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
2167                    None => (0, 0),
2168                };
2169            }
2170            Interface::MemRetrieveResp {
2171                total_len,
2172                frag_len,
2173            } => {
2174                a[1] = total_len.into();
2175                a[2] = frag_len.into();
2176            }
2177            Interface::MemRelinquish => {}
2178            Interface::MemReclaim { handle, flags } => {
2179                let handle_regs: [u32; 2] = handle.into();
2180                a[1] = handle_regs[0].into();
2181                a[2] = handle_regs[1].into();
2182                a[3] = flags.into();
2183            }
2184            Interface::MemPermGet { addr, page_cnt } => {
2185                a[1] = match addr {
2186                    MemAddr::Addr32(addr) => addr.into(),
2187                    MemAddr::Addr64(addr) => addr,
2188                };
2189                a[2] = if version >= Version(1, 3) {
2190                    page_cnt.unwrap().into()
2191                } else {
2192                    assert!(page_cnt.is_none());
2193                    0
2194                }
2195            }
2196            Interface::MemPermSet {
2197                addr,
2198                page_cnt,
2199                mem_perm,
2200            } => {
2201                a[1] = match addr {
2202                    MemAddr::Addr32(addr) => addr.into(),
2203                    MemAddr::Addr64(addr) => addr,
2204                };
2205                a[2] = page_cnt.into();
2206                a[3] = mem_perm.into();
2207            }
2208            Interface::ConsoleLog {
2209                char_cnt,
2210                char_lists,
2211            } => {
2212                a[1] = char_cnt.into();
2213                match char_lists {
2214                    ConsoleLogChars::Reg32(regs) => {
2215                        a[2] = regs[0].into();
2216                        a[3] = regs[1].into();
2217                        a[4] = regs[2].into();
2218                        a[5] = regs[3].into();
2219                        a[6] = regs[4].into();
2220                        a[7] = regs[5].into();
2221                    }
2222                    _ => panic!("{:#x?} requires 18 registers", char_lists),
2223                }
2224            }
2225            Interface::NotificationBitmapCreate { vm_id, vcpu_cnt } => {
2226                a[1] = vm_id.into();
2227                a[2] = vcpu_cnt.into();
2228            }
2229            Interface::NotificationBitmapDestroy { vm_id } => {
2230                a[1] = vm_id.into();
2231            }
2232            Interface::NotificationBind {
2233                sender_id,
2234                receiver_id,
2235                flags,
2236                bitmap,
2237            } => {
2238                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2239                a[2] = u32::from(flags).into();
2240                a[3] = bitmap & 0xffff_ffff;
2241                a[4] = bitmap >> 32;
2242            }
2243            Interface::NotificationUnBind {
2244                sender_id,
2245                receiver_id,
2246                bitmap,
2247            } => {
2248                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2249                a[3] = bitmap & 0xffff_ffff;
2250                a[4] = bitmap >> 32;
2251            }
2252            Interface::NotificationSet {
2253                sender_id,
2254                receiver_id,
2255                flags,
2256                bitmap,
2257            } => {
2258                a[1] = (u64::from(sender_id) << 16) | u64::from(receiver_id);
2259                a[2] = u32::from(flags).into();
2260                a[3] = bitmap & 0xffff_ffff;
2261                a[4] = bitmap >> 32;
2262            }
2263            Interface::NotificationGet {
2264                vcpu_id,
2265                endpoint_id,
2266                flags,
2267            } => {
2268                a[1] = (u64::from(vcpu_id) << 16) | u64::from(endpoint_id);
2269                a[2] = u32::from(flags).into();
2270            }
2271            Interface::NotificationInfoGet { .. } => {}
2272            Interface::El3IntrHandle => {}
2273            _ => panic!("{:#x?} requires 18 registers", self),
2274        }
2275    }
2276
2277    fn pack_regs18(&self, version: Version, a: &mut [u64; 18]) {
2278        assert!(version >= Version(1, 2));
2279
2280        if let Some(function_id) = self.function_id() {
2281            a[0] = function_id as u64;
2282        }
2283
2284        match *self {
2285            Interface::Success { target_info, args } => {
2286                a[1] = target_info.into();
2287                match args {
2288                    SuccessArgs::Args64_2(regs) => a[2..18].copy_from_slice(&regs[..16]),
2289                    _ => panic!("{:#x?} requires 8 registers", args),
2290                }
2291            }
2292            Interface::MsgSendDirectReq2 {
2293                src_id,
2294                dst_id,
2295                uuid,
2296                args,
2297            } => {
2298                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2299                let (uuid_msb, uuid_lsb) = uuid.as_u64_pair();
2300                (a[2], a[3]) = (uuid_msb.swap_bytes(), uuid_lsb.swap_bytes());
2301                a[4..18].copy_from_slice(&args.0[..14]);
2302            }
2303            Interface::MsgSendDirectResp2 {
2304                src_id,
2305                dst_id,
2306                args,
2307            } => {
2308                a[1] = ((src_id as u64) << 16) | dst_id as u64;
2309                a[2] = 0;
2310                a[3] = 0;
2311                a[4..18].copy_from_slice(&args.0[..14]);
2312            }
2313            Interface::ConsoleLog {
2314                char_cnt,
2315                char_lists,
2316            } => {
2317                a[1] = char_cnt.into();
2318                match char_lists {
2319                    ConsoleLogChars::Reg64(regs) => a[2..18].copy_from_slice(&regs[..16]),
2320                    _ => panic!("{:#x?} requires 8 registers", char_lists),
2321                }
2322            }
2323            Interface::PartitionInfoGetRegs {
2324                uuid,
2325                start_index,
2326                info_tag,
2327            } => {
2328                if start_index == 0 && info_tag != 0 {
2329                    panic!("Information Tag MBZ if start index is 0: {:#x?}", self);
2330                }
2331                let (uuid_msb, uuid_lsb) = uuid.as_u64_pair();
2332                (a[1], a[2]) = (uuid_msb.swap_bytes(), uuid_lsb.swap_bytes());
2333                a[3] = (u64::from(info_tag) << 16) | u64::from(start_index);
2334            }
2335            _ => panic!("{:#x?} requires 8 registers", self),
2336        }
2337    }
2338
2339    /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
2340    pub fn success32_noargs() -> Self {
2341        Self::Success {
2342            target_info: 0,
2343            args: SuccessArgs::Args32([0; 6]),
2344        }
2345    }
2346
2347    /// Helper function to create an `FFA_ERROR` interface with an error code.
2348    pub fn error(error_code: FfaError) -> Self {
2349        Self::Error {
2350            target_info: TargetInfo {
2351                endpoint_id: 0,
2352                vcpu_id: 0,
2353            },
2354            error_code,
2355            error_arg: 0,
2356        }
2357    }
2358}
2359
2360/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
2361pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
2362/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message.
2363pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 128;
2364
2365/// Helper function to convert the "Tightly packed list of characters" format used by the
2366/// `FFA_CONSOLE_LOG` interface into a byte slice.
2367pub fn parse_console_log(
2368    char_cnt: u8,
2369    char_lists: &ConsoleLogChars,
2370    log_bytes: &mut [u8],
2371) -> Result<(), FfaError> {
2372    match char_lists {
2373        ConsoleLogChars::Reg32(regs) => {
2374            if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
2375                return Err(FfaError::InvalidParameters);
2376            }
2377            log_bytes[..char_cnt.into()].copy_from_slice(&regs.as_bytes()[0..char_cnt.into()]);
2378        }
2379        ConsoleLogChars::Reg64(regs) => {
2380            if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
2381                return Err(FfaError::InvalidParameters);
2382            }
2383            log_bytes[..char_cnt.into()].copy_from_slice(&regs.as_bytes()[0..char_cnt.into()]);
2384        }
2385    }
2386
2387    Ok(())
2388}
2389
2390#[cfg(test)]
2391mod tests {
2392    use super::*;
2393
2394    #[test]
2395    fn part_info_get_regs() {
2396        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2397        let uuid_bytes = uuid.as_bytes();
2398        let test_info_tag = 0b1101_1101;
2399        let test_start_index = 0b1101;
2400        let start_index_and_tag = (test_info_tag << 16) | test_start_index;
2401        let version = Version(1, 2);
2402
2403        // From spec:
2404        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2405        let reg_x1 = ((uuid_bytes[7] as u64) << 56)
2406            | ((uuid_bytes[6] as u64) << 48)
2407            | ((uuid_bytes[5] as u64) << 40)
2408            | ((uuid_bytes[4] as u64) << 32)
2409            | ((uuid_bytes[3] as u64) << 24)
2410            | ((uuid_bytes[2] as u64) << 16)
2411            | ((uuid_bytes[1] as u64) << 8)
2412            | (uuid_bytes[0] as u64);
2413
2414        // From spec:
2415        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2416        let reg_x2 = ((uuid_bytes[15] as u64) << 56)
2417            | ((uuid_bytes[14] as u64) << 48)
2418            | ((uuid_bytes[13] as u64) << 40)
2419            | ((uuid_bytes[12] as u64) << 32)
2420            | ((uuid_bytes[11] as u64) << 24)
2421            | ((uuid_bytes[10] as u64) << 16)
2422            | ((uuid_bytes[9] as u64) << 8)
2423            | (uuid_bytes[8] as u64);
2424
2425        // First, test for wrong tag:
2426        {
2427            let mut regs = [0u64; 18];
2428            regs[0] = FuncId::PartitionInfoGetRegs as u64;
2429            regs[1] = reg_x1;
2430            regs[2] = reg_x2;
2431            regs[3] = test_info_tag << 16;
2432
2433            assert!(Interface::from_regs(version, &regs).is_err_and(
2434                |e| e == Error::InvalidInformationTag(test_info_tag.try_into().unwrap())
2435            ));
2436        }
2437
2438        // Test for regs -> Interface -> regs
2439        {
2440            let mut orig_regs = [0u64; 18];
2441            orig_regs[0] = FuncId::PartitionInfoGetRegs as u64;
2442            orig_regs[1] = reg_x1;
2443            orig_regs[2] = reg_x2;
2444            orig_regs[3] = start_index_and_tag;
2445
2446            let mut test_regs = orig_regs;
2447            let interface = Interface::from_regs(version, &test_regs).unwrap();
2448            match &interface {
2449                Interface::PartitionInfoGetRegs {
2450                    info_tag,
2451                    start_index,
2452                    uuid: int_uuid,
2453                } => {
2454                    assert_eq!(u64::from(*info_tag), test_info_tag);
2455                    assert_eq!(u64::from(*start_index), test_start_index);
2456                    assert_eq!(*int_uuid, uuid);
2457                }
2458                _ => panic!("Expecting Interface::PartitionInfoGetRegs!"),
2459            }
2460            test_regs.fill(0);
2461            interface.to_regs(version, &mut test_regs);
2462            assert_eq!(orig_regs, test_regs);
2463        }
2464
2465        // Test for Interface -> regs -> Interface
2466        {
2467            let interface = Interface::PartitionInfoGetRegs {
2468                info_tag: test_info_tag.try_into().unwrap(),
2469                start_index: test_start_index.try_into().unwrap(),
2470                uuid,
2471            };
2472
2473            let mut regs: [u64; 18] = [0; 18];
2474            interface.to_regs(version, &mut regs);
2475
2476            assert_eq!(Some(FuncId::PartitionInfoGetRegs), interface.function_id());
2477            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2478            assert_eq!(regs[1], reg_x1);
2479            assert_eq!(regs[2], reg_x2);
2480            assert_eq!(regs[3], (test_info_tag << 16) | test_start_index);
2481
2482            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2483        }
2484    }
2485
2486    #[test]
2487    fn msg_send_direct_req2() {
2488        let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
2489        let uuid_bytes = uuid.as_bytes();
2490
2491        // From spec:
2492        // Bytes[0...7] of UUID with byte 0 in the low-order bits.
2493        let reg_x2 = ((uuid_bytes[7] as u64) << 56)
2494            | ((uuid_bytes[6] as u64) << 48)
2495            | ((uuid_bytes[5] as u64) << 40)
2496            | ((uuid_bytes[4] as u64) << 32)
2497            | ((uuid_bytes[3] as u64) << 24)
2498            | ((uuid_bytes[2] as u64) << 16)
2499            | ((uuid_bytes[1] as u64) << 8)
2500            | (uuid_bytes[0] as u64);
2501
2502        // From spec:
2503        // Bytes[8...15] of UUID with byte 8 in the low-order bits.
2504        let reg_x3 = ((uuid_bytes[15] as u64) << 56)
2505            | ((uuid_bytes[14] as u64) << 48)
2506            | ((uuid_bytes[13] as u64) << 40)
2507            | ((uuid_bytes[12] as u64) << 32)
2508            | ((uuid_bytes[11] as u64) << 24)
2509            | ((uuid_bytes[10] as u64) << 16)
2510            | ((uuid_bytes[9] as u64) << 8)
2511            | (uuid_bytes[8] as u64);
2512
2513        let test_sender = 0b1101_1101;
2514        let test_receiver = 0b1101;
2515        let test_sender_receiver = (test_sender << 16) | test_receiver;
2516        let version = Version(1, 2);
2517
2518        // Test for regs -> Interface -> regs
2519        {
2520            let mut orig_regs = [0u64; 18];
2521            orig_regs[0] = FuncId::MsgSendDirectReq64_2 as u64;
2522            orig_regs[1] = test_sender_receiver;
2523            orig_regs[2] = reg_x2;
2524            orig_regs[3] = reg_x3;
2525
2526            let mut test_regs = orig_regs;
2527            let interface = Interface::from_regs(version, &test_regs).unwrap();
2528            match &interface {
2529                Interface::MsgSendDirectReq2 {
2530                    dst_id,
2531                    src_id,
2532                    args: _,
2533                    uuid: int_uuid,
2534                } => {
2535                    assert_eq!(u64::from(*src_id), test_sender);
2536                    assert_eq!(u64::from(*dst_id), test_receiver);
2537                    assert_eq!(*int_uuid, uuid);
2538                }
2539                _ => panic!("Expecting Interface::MsgSendDirectReq2!"),
2540            }
2541            test_regs.fill(0);
2542            interface.to_regs(version, &mut test_regs);
2543            assert_eq!(orig_regs, test_regs);
2544        }
2545
2546        // Test for Interface -> regs -> Interface
2547        {
2548            let rest_of_regs: [u64; 14] = [0; 14];
2549
2550            let interface = Interface::MsgSendDirectReq2 {
2551                src_id: test_sender.try_into().unwrap(),
2552                dst_id: test_receiver.try_into().unwrap(),
2553                uuid,
2554                args: DirectMsg2Args(rest_of_regs),
2555            };
2556
2557            let mut regs: [u64; 18] = [0; 18];
2558            interface.to_regs(version, &mut regs);
2559
2560            assert_eq!(Some(FuncId::MsgSendDirectReq64_2), interface.function_id());
2561            assert_eq!(regs[0], interface.function_id().unwrap() as u64);
2562            assert_eq!(regs[1], test_sender_receiver);
2563            assert_eq!(regs[2], reg_x2);
2564            assert_eq!(regs[3], reg_x3);
2565            assert_eq!(regs[4], 0);
2566
2567            assert_eq!(Interface::from_regs(version, &regs).unwrap(), interface);
2568        }
2569    }
2570
2571    #[test]
2572    fn is_32bit() {
2573        let interface_64 = Interface::MsgSendDirectReq {
2574            src_id: 0,
2575            dst_id: 1,
2576            args: DirectMsgArgs::Args64([0, 0, 0, 0, 0]),
2577        };
2578        assert!(!interface_64.is_32bit());
2579
2580        let interface_32 = Interface::MsgSendDirectReq {
2581            src_id: 0,
2582            dst_id: 1,
2583            args: DirectMsgArgs::Args32([0, 0, 0, 0, 0]),
2584        };
2585        assert!(interface_32.is_32bit());
2586    }
2587
2588    #[test]
2589    fn success_args_notification_info_get32() {
2590        let mut notifications = SuccessArgsNotificationInfoGet32::default();
2591
2592        // 16.7.1.1 Example usage
2593        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2594        notifications.add_list(0x0000, &[4, 6]).unwrap();
2595        notifications.add_list(0x0002, &[]).unwrap();
2596        notifications.add_list(0x0003, &[1]).unwrap();
2597
2598        let args: SuccessArgs = notifications.into();
2599        assert_eq!(
2600            SuccessArgs::Args32([
2601                0x0004_b200,
2602                0x0000_0000,
2603                0x0003_0002,
2604                0x0004_0000,
2605                0x0002_0006,
2606                0x0001_0003
2607            ]),
2608            args
2609        );
2610
2611        let notifications = SuccessArgsNotificationInfoGet32::try_from(args).unwrap();
2612        let mut iter = notifications.iter();
2613        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2614        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2615        assert_eq!(Some((0x0002, &[][..])), iter.next());
2616        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2617    }
2618
2619    #[test]
2620    fn success_args_notification_info_get64() {
2621        let mut notifications = SuccessArgsNotificationInfoGet64::default();
2622
2623        // 16.7.1.1 Example usage
2624        notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
2625        notifications.add_list(0x0000, &[4, 6]).unwrap();
2626        notifications.add_list(0x0002, &[]).unwrap();
2627        notifications.add_list(0x0003, &[1]).unwrap();
2628
2629        let args: SuccessArgs = notifications.into();
2630        assert_eq!(
2631            SuccessArgs::Args64([
2632                0x0004_b200,
2633                0x0003_0002_0000_0000,
2634                0x0002_0006_0004_0000,
2635                0x0000_0000_0001_0003,
2636                0x0000_0000_0000_0000,
2637                0x0000_0000_0000_0000,
2638            ]),
2639            args
2640        );
2641
2642        let notifications = SuccessArgsNotificationInfoGet64::try_from(args).unwrap();
2643        let mut iter = notifications.iter();
2644        assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
2645        assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
2646        assert_eq!(Some((0x0002, &[][..])), iter.next());
2647        assert_eq!(Some((0x0003, &[1][..])), iter.next());
2648    }
2649}