1use crate::{Error, FfaError, FuncId, Version, memory_management};
7use num_enum::{IntoPrimitive, TryFromPrimitive};
8use zerocopy::{FromBytes, Immutable, IntoBytes};
9
10#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
12pub struct TargetInfo {
13 pub endpoint_id: u16,
14 pub vcpu_id: u16,
15}
16
17impl From<u32> for TargetInfo {
18 fn from(value: u32) -> Self {
19 Self {
20 endpoint_id: (value >> 16) as u16,
21 vcpu_id: value as u16,
22 }
23 }
24}
25
26impl From<TargetInfo> for u32 {
27 fn from(value: TargetInfo) -> Self {
28 ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
29 }
30}
31
32#[derive(Debug, Eq, PartialEq, Clone, Copy)]
47pub enum SuccessArgs {
48 Args32([u32; 6]),
49 Args64([u64; 16]),
50}
51
52impl SuccessArgs {
53 pub(crate) fn try_get_args32(self) -> Result<[u32; 6], Error> {
54 match self {
55 SuccessArgs::Args32(args) => Ok(args),
56 SuccessArgs::Args64(_) => Err(Error::InvalidSuccessArgsVariant),
57 }
58 }
59
60 pub(crate) fn try_get_args64(self) -> Result<[u64; 16], Error> {
61 match self {
62 SuccessArgs::Args64(args) => Ok(args),
63 SuccessArgs::Args32(_) => Err(Error::InvalidSuccessArgsVariant),
64 }
65 }
66}
67
68#[derive(Debug, Eq, PartialEq, Clone, Copy)]
70pub enum SecondaryEpRegisterAddr {
71 Addr32(u32),
72 Addr64(u64),
73}
74
75#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
77#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
78#[repr(u8)]
79pub enum FeatureId {
80 NotificationPendingInterrupt = 0x1,
81 ScheduleReceiverInterrupt = 0x2,
82 ManagedExitInterrupt = 0x3,
83}
84
85#[derive(Debug, Eq, PartialEq, Clone, Copy)]
87pub enum Feature {
88 FuncId(FuncId),
89 FeatureId(FeatureId),
90 Unknown(u32),
91}
92
93impl From<u32> for Feature {
94 fn from(value: u32) -> Self {
95 if let Ok(func_id) = value.try_into() {
97 Self::FuncId(func_id)
98 } else if let Ok(feat_id) = (value as u8).try_into() {
99 Self::FeatureId(feat_id)
100 } else {
101 Self::Unknown(value)
102 }
103 }
104}
105
106impl From<Feature> for u32 {
107 fn from(value: Feature) -> Self {
108 match value {
109 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
110 Feature::FeatureId(feature_id) => feature_id as u32,
111 Feature::Unknown(id) => id,
112 }
113 }
114}
115
116#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
119pub struct SuccessArgsFeatures {
120 pub properties: [u32; 2],
121}
122
123impl From<SuccessArgsFeatures> for SuccessArgs {
124 fn from(value: SuccessArgsFeatures) -> Self {
125 Self::Args32([value.properties[0], value.properties[1], 0, 0, 0, 0])
126 }
127}
128
129impl TryFrom<SuccessArgs> for SuccessArgsFeatures {
130 type Error = Error;
131
132 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
133 let args = value.try_get_args32()?;
134
135 Ok(Self {
136 properties: [args[0], args[1]],
137 })
138 }
139}
140
141#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
143#[num_enum(error_type(name = Error, constructor = Error::InvalidVersionQueryType))]
144#[repr(u8)]
145pub enum VersionQueryType {
146 Negotiate = 0b00,
148 QueryCompatibility = 0b01,
151 QueryNegotiated = 0b10,
153}
154
155#[derive(Clone, Copy, Debug, Eq, PartialEq)]
157pub struct VersionFlags {
158 pub query_type: VersionQueryType,
159}
160
161impl VersionFlags {
162 const QUERY_TYPE_MASK: u32 = 0b11;
163 const MBZ_BITS: u32 = 0xffff_fffc;
164}
165
166impl TryFrom<u32> for VersionFlags {
167 type Error = Error;
168
169 fn try_from(val: u32) -> Result<Self, Self::Error> {
170 if (val & Self::MBZ_BITS) != 0 {
171 Err(Error::InvalidVersionFlags(val))
172 } else {
173 Ok(Self {
174 query_type: VersionQueryType::try_from((val & Self::QUERY_TYPE_MASK) as u8)?,
175 })
176 }
177 }
178}
179
180impl From<VersionFlags> for u32 {
181 fn from(flags: VersionFlags) -> Self {
182 flags.query_type as u32
183 }
184}
185
186#[derive(Debug, Eq, PartialEq, Clone, Copy)]
188pub enum RxTxAddr {
189 Addr32 { rx: u32, tx: u32 },
190 Addr64 { rx: u64, tx: u64 },
191}
192
193#[derive(Debug, Eq, PartialEq, Clone, Copy)]
195pub struct SuccessArgsIdGet {
196 pub id: u16,
197}
198
199impl From<SuccessArgsIdGet> for SuccessArgs {
200 fn from(value: SuccessArgsIdGet) -> Self {
201 SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
202 }
203}
204
205impl TryFrom<SuccessArgs> for SuccessArgsIdGet {
206 type Error = Error;
207
208 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
209 let args = value.try_get_args32()?;
210 Ok(Self { id: args[0] as u16 })
211 }
212}
213
214#[derive(Debug, Eq, PartialEq, Clone, Copy)]
216pub struct SuccessArgsSpmIdGet {
217 pub id: u16,
218}
219
220impl From<SuccessArgsSpmIdGet> for SuccessArgs {
221 fn from(value: SuccessArgsSpmIdGet) -> Self {
222 SuccessArgs::Args32([value.id as u32, 0, 0, 0, 0, 0])
223 }
224}
225
226impl TryFrom<SuccessArgs> for SuccessArgsSpmIdGet {
227 type Error = Error;
228
229 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
230 let args = value.try_get_args32()?;
231 Ok(Self { id: args[0] as u16 })
232 }
233}
234
235#[derive(Debug, Eq, Default, PartialEq, Clone, Copy)]
237pub struct MsgSend2Flags {
238 pub delay_schedule_receiver: bool,
239}
240
241impl MsgSend2Flags {
242 const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
243 const MBZ_BITS: u32 = 0xffff_fffd;
244}
245
246impl TryFrom<u32> for MsgSend2Flags {
247 type Error = Error;
248
249 fn try_from(val: u32) -> Result<Self, Self::Error> {
250 if (val & Self::MBZ_BITS) != 0 {
251 Err(Error::InvalidMsgSend2Flag(val))
252 } else {
253 Ok(MsgSend2Flags {
254 delay_schedule_receiver: val & Self::DELAY_SCHEDULE_RECEIVER != 0,
255 })
256 }
257 }
258}
259
260impl From<MsgSend2Flags> for u32 {
261 fn from(flags: MsgSend2Flags) -> Self {
262 let mut bits: u32 = 0;
263 if flags.delay_schedule_receiver {
264 bits |= MsgSend2Flags::DELAY_SCHEDULE_RECEIVER;
265 }
266 bits
267 }
268}
269
270#[derive(Debug, Eq, PartialEq, Clone, Copy)]
276pub enum VmAvailabilityStatus {
277 Success,
278 Error(FfaError),
279}
280
281impl TryFrom<i32> for VmAvailabilityStatus {
282 type Error = Error;
283 fn try_from(value: i32) -> Result<Self, <Self as TryFrom<i32>>::Error> {
284 Ok(match value {
285 0 => Self::Success,
286 error_code => Self::Error(FfaError::try_from(error_code)?),
287 })
288 }
289}
290
291impl From<VmAvailabilityStatus> for i32 {
292 fn from(value: VmAvailabilityStatus) -> Self {
293 match value {
294 VmAvailabilityStatus::Success => 0,
295 VmAvailabilityStatus::Error(error_code) => error_code.into(),
296 }
297 }
298}
299
300#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
302#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedWarmBootType))]
303#[repr(u32)]
304pub enum WarmBootType {
305 ExitFromSuspendToRam = 0,
306 ExitFromLowPower = 1,
308}
309
310impl WarmBootType {
311 #[allow(non_upper_case_globals)]
312 #[deprecated = "Ambiguous name. Please use ExitFromSuspendToRam."]
313 pub const ExitFromSuspend: WarmBootType = WarmBootType::ExitFromSuspendToRam;
314}
315
316#[derive(Debug, Eq, PartialEq, Clone, Copy)]
318pub enum DirectMsgArgs {
319 Args32([u32; 5]),
320 Args64([u64; 15]),
321 VersionReq {
323 version: Version,
324 flags: VersionFlags,
325 },
326 VersionResp {
329 version: Option<Version>,
330 },
331 PowerPsciReq32 {
333 params: [u32; 4],
336 },
337 PowerPsciReq64 {
339 params: [u64; 4],
342 },
343 PowerWarmBootReq {
345 boot_type: WarmBootType,
346 },
347 PowerPsciResp {
351 psci_status: i32,
352 },
353 VmCreated {
355 handle: memory_management::Handle,
360 vm_id: u16,
361 },
362 VmCreatedAck {
364 sp_status: VmAvailabilityStatus,
365 },
366 VmDestructed {
368 handle: memory_management::Handle,
373 vm_id: u16,
374 },
375 VmDestructedAck {
377 sp_status: VmAvailabilityStatus,
378 },
379}
380
381impl DirectMsgArgs {
382 pub(crate) const FWK_MSG_BITS: u32 = 1 << 31;
385 pub(crate) const VERSION_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1000;
386 pub(crate) const VERSION_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1001;
387 pub(crate) const POWER_PSCI_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS;
388 pub(crate) const POWER_WARM_BOOT_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0001;
389 pub(crate) const POWER_PSCI_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0010;
390 pub(crate) const VM_CREATED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0100;
391 pub(crate) const VM_CREATED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0101;
392 pub(crate) const VM_DESTRUCTED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0110;
393 pub(crate) const VM_DESTRUCTED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0111;
394}
395
396#[derive(Debug, Eq, PartialEq, Clone, Copy)]
398pub struct DirectMsg2Args(pub [u64; 14]);
399
400#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
402pub struct MsgWaitFlags {
403 pub retain_rx_buffer: bool,
404}
405
406impl MsgWaitFlags {
407 const RETAIN_RX_BUFFER: u32 = 0x01;
408 const MBZ_BITS: u32 = 0xfffe;
409}
410
411impl TryFrom<u32> for MsgWaitFlags {
412 type Error = Error;
413
414 fn try_from(val: u32) -> Result<Self, Self::Error> {
415 if (val & Self::MBZ_BITS) != 0 {
416 Err(Error::InvalidMsgWaitFlag(val))
417 } else {
418 Ok(MsgWaitFlags {
419 retain_rx_buffer: val & Self::RETAIN_RX_BUFFER != 0,
420 })
421 }
422 }
423}
424
425impl From<MsgWaitFlags> for u32 {
426 fn from(flags: MsgWaitFlags) -> Self {
427 let mut bits: u32 = 0;
428 if flags.retain_rx_buffer {
429 bits |= MsgWaitFlags::RETAIN_RX_BUFFER;
430 }
431 bits
432 }
433}
434
435#[derive(Debug, Eq, PartialEq, Clone, Copy)]
441pub enum MemOpBuf {
442 Buf32 { addr: u32, page_cnt: u32 },
443 Buf64 { addr: u64, page_cnt: u32 },
444}
445
446#[derive(Debug, Eq, PartialEq, Clone, Copy)]
448pub enum MemAddr {
449 Addr32(u32),
450 Addr64(u64),
451}
452
453impl MemAddr {
454 pub fn address(&self) -> u64 {
456 match self {
457 MemAddr::Addr32(a) => (*a).into(),
458 MemAddr::Addr64(a) => *a,
459 }
460 }
461}
462
463#[derive(Debug, Eq, PartialEq, Clone, Copy)]
465pub enum ConsoleLogChars {
466 Chars32(ConsoleLogChars32),
467 Chars64(ConsoleLogChars64),
468}
469
470#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
472pub struct LogChars<T>
473where
474 T: IntoBytes + FromBytes + Immutable,
475{
476 pub(crate) char_cnt: u8,
477 pub(crate) char_lists: T,
478}
479
480impl<T> LogChars<T>
481where
482 T: IntoBytes + FromBytes + Immutable,
483{
484 pub(crate) const MAX_LENGTH: u8 = core::mem::size_of::<T>() as u8;
485
486 pub fn empty(&self) -> bool {
488 self.char_cnt == 0
489 }
490
491 pub fn full(&self) -> bool {
493 self.char_cnt as usize >= core::mem::size_of::<T>()
494 }
495
496 pub fn bytes(&self) -> &[u8] {
498 &self.char_lists.as_bytes()[..self.char_cnt as usize]
499 }
500
501 pub fn push(&mut self, source: &[u8]) -> usize {
503 let empty_area = &mut self.char_lists.as_mut_bytes()[self.char_cnt.into()..];
504 let len = empty_area.len().min(source.len());
505
506 empty_area[..len].copy_from_slice(&source[..len]);
507 self.char_cnt += len as u8;
508
509 len
510 }
511}
512
513pub type ConsoleLogChars32 = LogChars<[u32; 6]>;
515
516pub type ConsoleLogChars64 = LogChars<[u64; 16]>;
518
519#[cfg(test)]
520mod tests {
521 use super::*;
522
523 #[test]
524 fn log_chars_empty() {
525 assert!(
526 ConsoleLogChars64 {
527 char_cnt: 0,
528 char_lists: [0; 16]
529 }
530 .empty()
531 )
532 }
533
534 #[test]
535 fn log_chars_push() {
536 let mut console = ConsoleLogChars64 {
537 char_cnt: 0,
538 char_lists: [0; 16],
539 };
540
541 assert_eq!(console.push("hello world!".as_bytes()), 12);
542
543 assert_eq!(console.char_cnt, 12);
544 assert_eq!(&console.bytes()[0..12], "hello world!".as_bytes());
545 assert!(!console.empty());
546 }
547
548 #[test]
549 fn log_chars_full() {
550 let mut console = ConsoleLogChars64 {
551 char_cnt: 0,
552 char_lists: [0; 16],
553 };
554
555 assert_eq!(console.push(&[97; 128]), 128);
556
557 assert!(console.full());
558 }
559
560 #[test]
561 fn success_args_invalid_variants() {
562 assert!(SuccessArgs::Args32([0; 6]).try_get_args64().is_err());
563 assert!(SuccessArgs::Args64([0; 16]).try_get_args32().is_err());
564 }
565}