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