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