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