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