Skip to main content

arm_ffa/
interface.rs

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