blob: 6f353f30dc6a8fa0a301e259ff508c08d41c3a75 [file] [log] [blame]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![cfg_attr(not(test), no_std)]
5
Andrew Walbran19970ba2024-11-25 15:35:00 +00006use core::fmt::{self, Debug, Display, Formatter};
Andrew Walbran44029a02024-11-25 15:34:31 +00007use num_enum::{IntoPrimitive, TryFromPrimitive};
8use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +02009use uuid::Uuid;
10
11pub mod boot_info;
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010012mod ffa_v1_1;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020013pub mod memory_management;
14pub mod partition_info;
15
Balint Dobszay3aad9572025-01-17 16:54:11 +010016// On many occasions the FF-A spec defines memory size as count of 4K pages,
17// regardless of the current translation granule
18pub const FFA_PAGE_SIZE_4K: usize = 4096;
19
20#[derive(Debug, Error)]
21pub enum Error {
22 #[error("Unrecognised FF-A function ID {0}")]
23 UnrecognisedFunctionId(u32),
24 #[error("Unrecognised FF-A feature ID {0}")]
25 UnrecognisedFeatureId(u8),
26 #[error("Unrecognised FF-A error code {0}")]
27 UnrecognisedErrorCode(i32),
28}
29
30impl From<Error> for FfaError {
31 fn from(value: Error) -> Self {
32 match value {
33 Error::UnrecognisedFunctionId(_) | Error::UnrecognisedFeatureId(_) => {
34 Self::NotSupported
35 }
36 Error::UnrecognisedErrorCode(_) => Self::InvalidParameters,
37 }
38 }
39}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020040
41#[derive(PartialEq, Clone, Copy)]
42pub enum Instance {
43 SecurePhysical,
44 SecureVirtual(u16),
45}
46
Balint Dobszay5bf492f2024-07-29 17:21:32 +020047/// FF-A v1.1: Function IDs
Andrew Walbran969b9252024-11-25 15:35:42 +000048#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay3aad9572025-01-17 16:54:11 +010049#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFunctionId))]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020050#[repr(u32)]
51pub enum FuncId {
52 Error = 0x84000060,
53 Success32 = 0x84000061,
54 Success64 = 0xc4000061,
55 Interrupt = 0x84000062,
56 Version = 0x84000063,
57 Features = 0x84000064,
58 RxAcquire = 0x84000084,
59 RxRelease = 0x84000065,
60 RxTxMap32 = 0x84000066,
61 RxTxMap64 = 0xc4000066,
62 RxTxUnmap = 0x84000067,
63 PartitionInfoGet = 0x84000068,
64 IdGet = 0x84000069,
65 SpmIdGet = 0x84000085,
66 MsgWait = 0x8400006b,
67 Yield = 0x8400006c,
68 Run = 0x8400006d,
69 NormalWorldResume = 0x8400007c,
70 MsgSend2 = 0x84000086,
71 MsgSendDirectReq32 = 0x8400006f,
72 MsgSendDirectReq64 = 0xc400006f,
73 MsgSendDirectResp32 = 0x84000070,
74 MsgSendDirectResp64 = 0xc4000070,
75 MemDonate32 = 0x84000071,
76 MemDonate64 = 0xc4000071,
77 MemLend32 = 0x84000072,
78 MemLend64 = 0xc4000072,
79 MemShare32 = 0x84000073,
80 MemShare64 = 0xc4000073,
81 MemRetrieveReq32 = 0x84000074,
82 MemRetrieveReq64 = 0xc4000074,
83 MemRetrieveResp = 0x84000075,
84 MemRelinquish = 0x84000076,
85 MemReclaim = 0x84000077,
86 MemPermGet32 = 0x84000088,
87 MemPermGet64 = 0xc4000088,
88 MemPermSet32 = 0x84000089,
89 MemPermSet64 = 0xc4000089,
90 ConsoleLog32 = 0x8400008a,
91 ConsoleLog64 = 0xc400008a,
92}
93
Balint Dobszay3aad9572025-01-17 16:54:11 +010094/// FF-A v1.1, Table 12.2: Error status codes
95#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
96#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
97#[repr(i32)]
98pub enum FfaError {
99 #[error("Not supported")]
100 NotSupported = -1,
101 #[error("Invalid parameters")]
102 InvalidParameters = -2,
103 #[error("No memory")]
104 NoMemory = -3,
105 #[error("Busy")]
106 Busy = -4,
107 #[error("Interrupted")]
108 Interrupted = -5,
109 #[error("Denied")]
110 Denied = -6,
111 #[error("Retry")]
112 Retry = -7,
113 #[error("Aborted")]
114 Aborted = -8,
115 #[error("No data")]
116 NoData = -9,
117}
118
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200119#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Balint Dobszay3aad9572025-01-17 16:54:11 +0100120pub struct TargetInfo {
121 pub endpoint_id: u16,
122 pub vcpu_id: u16,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200123}
124
Balint Dobszay3aad9572025-01-17 16:54:11 +0100125impl From<u32> for TargetInfo {
126 fn from(value: u32) -> Self {
127 Self {
128 endpoint_id: (value >> 16) as u16,
129 vcpu_id: value as u16,
130 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200131 }
132}
133
Balint Dobszay3aad9572025-01-17 16:54:11 +0100134impl From<TargetInfo> for u32 {
135 fn from(value: TargetInfo) -> Self {
136 (value.endpoint_id as u32) << 16 | value.vcpu_id as u32
Andrew Walbran0d315812024-11-25 15:36:36 +0000137 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100138}
Andrew Walbran0d315812024-11-25 15:36:36 +0000139
Balint Dobszay3aad9572025-01-17 16:54:11 +0100140#[derive(Debug, Eq, PartialEq, Clone, Copy)]
141pub enum SuccessArgs {
142 Result32([u32; 6]),
143 Result64([u64; 6]),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200144}
145
Andrew Walbran19970ba2024-11-25 15:35:00 +0000146#[derive(Clone, Copy, Eq, PartialEq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200147pub struct Version(pub u16, pub u16);
148
149impl From<u32> for Version {
150 fn from(val: u32) -> Self {
151 Self((val >> 16) as u16, val as u16)
152 }
153}
154
155impl From<Version> for u32 {
156 fn from(v: Version) -> Self {
157 (v.0 as u32) << 16 | v.1 as u32
158 }
159}
160
Andrew Walbran19970ba2024-11-25 15:35:00 +0000161impl Display for Version {
162 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
163 write!(f, "{}.{}", self.0, self.1)
164 }
165}
166
167impl Debug for Version {
168 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
169 Display::fmt(self, f)
170 }
171}
172
Balint Dobszay3aad9572025-01-17 16:54:11 +0100173#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
174#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
175#[repr(u8)]
176pub enum FeatureId {
177 NotificationPendingInterrupt = 0x1,
178 ScheduleReceiverInterrupt = 0x2,
179 ManagedExitInterrupt = 0x3,
180}
Balint Dobszayc8802492025-01-15 18:11:39 +0100181
Balint Dobszay3aad9572025-01-17 16:54:11 +0100182#[derive(Debug, Eq, PartialEq, Clone, Copy)]
183pub enum Feature {
184 FuncId(FuncId),
185 FeatureId(FeatureId),
186}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200187
Balint Dobszay3aad9572025-01-17 16:54:11 +0100188impl TryFrom<u32> for Feature {
189 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200190
Balint Dobszay3aad9572025-01-17 16:54:11 +0100191 fn try_from(value: u32) -> Result<Self, Self::Error> {
192 let res = if (value >> 31) & 1 == 1 {
193 Self::FuncId(value.try_into()?)
194 } else {
195 Self::FeatureId((value as u8).try_into()?)
196 };
197
198 Ok(res)
199 }
200}
201
202impl From<Feature> for u32 {
203 fn from(value: Feature) -> Self {
204 match value {
205 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
206 Feature::FeatureId(feature_id) => feature_id as u32,
207 }
208 }
209}
210
211#[derive(Debug, Eq, PartialEq, Clone, Copy)]
212pub enum RxTxAddr {
213 Addr32 { rx: u32, tx: u32 },
214 Addr64 { rx: u64, tx: u64 },
215}
216
217#[derive(Debug, Eq, PartialEq, Clone, Copy)]
218pub enum DirectMsgArgs {
219 Args32([u32; 5]),
220 Args64([u64; 5]),
221}
222
223#[derive(Debug, Eq, PartialEq, Clone, Copy)]
224pub enum MemOpBuf {
225 Buf32 { addr: u32, page_cnt: u32 },
226 Buf64 { addr: u64, page_cnt: u32 },
227}
228
229#[derive(Debug, Eq, PartialEq, Clone, Copy)]
230pub enum MemAddr {
231 Addr32(u32),
232 Addr64(u64),
233}
234
235#[derive(Debug, Eq, PartialEq, Clone, Copy)]
236pub enum ConsoleLogChars {
237 Reg32([u32; 6]),
238 Reg64([u64; 6]),
239}
240
241#[derive(Debug, Eq, PartialEq, Clone, Copy)]
242pub enum Interface {
243 Error {
244 target_info: TargetInfo,
245 error_code: FfaError,
246 },
247 Success {
248 target_info: u32,
249 args: SuccessArgs,
250 },
251 Interrupt {
252 target_info: TargetInfo,
253 interrupt_id: u32,
254 },
255 Version {
256 input_version: Version,
257 },
258 VersionOut {
259 output_version: Version,
260 },
261 Features {
262 feat_id: Feature,
263 input_properties: u32,
264 },
265 RxAcquire {
266 vm_id: u16,
267 },
268 RxRelease {
269 vm_id: u16,
270 },
271 RxTxMap {
272 addr: RxTxAddr,
273 page_cnt: u32,
274 },
275 RxTxUnmap {
276 id: u16,
277 },
278 PartitionInfoGet {
279 uuid: Uuid,
280 flags: u32,
281 },
282 IdGet,
283 SpmIdGet,
284 MsgWait,
285 Yield,
286 Run {
287 target_info: TargetInfo,
288 },
289 NormalWorldResume,
290 MsgSend2 {
291 sender_vm_id: u16,
292 flags: u32,
293 },
294 MsgSendDirectReq {
295 src_id: u16,
296 dst_id: u16,
297 flags: u32,
298 args: DirectMsgArgs,
299 },
300 MsgSendDirectResp {
301 src_id: u16,
302 dst_id: u16,
303 flags: u32,
304 args: DirectMsgArgs,
305 },
306 MemDonate {
307 total_len: u32,
308 frag_len: u32,
309 buf: Option<MemOpBuf>,
310 },
311 MemLend {
312 total_len: u32,
313 frag_len: u32,
314 buf: Option<MemOpBuf>,
315 },
316 MemShare {
317 total_len: u32,
318 frag_len: u32,
319 buf: Option<MemOpBuf>,
320 },
321 MemRetrieveReq {
322 total_len: u32,
323 frag_len: u32,
324 buf: Option<MemOpBuf>,
325 },
326 MemRetrieveResp {
327 total_len: u32,
328 frag_len: u32,
329 },
330 MemRelinquish,
331 MemReclaim {
332 handle: memory_management::Handle,
333 flags: u32,
334 },
335 MemPermGet {
336 addr: MemAddr,
337 },
338 MemPermSet {
339 addr: MemAddr,
340 page_cnt: u32,
341 mem_perm: u32,
342 },
343 ConsoleLog {
344 char_cnt: u8,
345 char_lists: ConsoleLogChars,
346 },
347}
348
349impl TryFrom<[u64; 8]> for Interface {
350 type Error = Error;
351
352 fn try_from(regs: [u64; 8]) -> Result<Self, Error> {
353 let fid = FuncId::try_from(regs[0] as u32)?;
354
355 let msg = match fid {
356 FuncId::Error => Self::Error {
357 target_info: (regs[1] as u32).into(),
358 error_code: FfaError::try_from(regs[2] as i32)?,
359 },
360 FuncId::Success32 => Self::Success {
361 target_info: regs[1] as u32,
362 args: SuccessArgs::Result32([
363 regs[2] as u32,
364 regs[3] as u32,
365 regs[4] as u32,
366 regs[5] as u32,
367 regs[6] as u32,
368 regs[7] as u32,
369 ]),
370 },
371 FuncId::Success64 => Self::Success {
372 target_info: regs[1] as u32,
373 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
374 },
375 FuncId::Interrupt => Self::Interrupt {
376 target_info: (regs[1] as u32).into(),
377 interrupt_id: regs[2] as u32,
378 },
379 FuncId::Version => Self::Version {
380 input_version: (regs[1] as u32).into(),
381 },
382 FuncId::Features => Self::Features {
383 feat_id: (regs[1] as u32).try_into()?,
384 input_properties: regs[2] as u32,
385 },
386 FuncId::RxAcquire => Self::RxAcquire {
387 vm_id: regs[1] as u16,
388 },
389 FuncId::RxRelease => Self::RxRelease {
390 vm_id: regs[1] as u16,
391 },
392 FuncId::RxTxMap32 => {
393 let addr = RxTxAddr::Addr32 {
394 rx: regs[2] as u32,
395 tx: regs[1] as u32,
396 };
397 let page_cnt = regs[3] as u32;
398
399 Self::RxTxMap { addr, page_cnt }
400 }
401 FuncId::RxTxMap64 => {
402 let addr = RxTxAddr::Addr64 {
403 rx: regs[2],
404 tx: regs[1],
405 };
406 let page_cnt = regs[3] as u32;
407
408 Self::RxTxMap { addr, page_cnt }
409 }
410 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
411 FuncId::PartitionInfoGet => {
412 let uuid_words = [
413 regs[1] as u32,
414 regs[2] as u32,
415 regs[3] as u32,
416 regs[4] as u32,
417 ];
418 let mut bytes: [u8; 16] = [0; 16];
419 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
420 bytes[i] = b;
421 }
422 Self::PartitionInfoGet {
423 uuid: Uuid::from_bytes(bytes),
424 flags: regs[5] as u32,
425 }
426 }
427 FuncId::IdGet => Self::IdGet,
428 FuncId::SpmIdGet => Self::SpmIdGet,
429 FuncId::MsgWait => Self::MsgWait,
430 FuncId::Yield => Self::Yield,
431 FuncId::Run => Self::Run {
432 target_info: (regs[1] as u32).into(),
433 },
434 FuncId::NormalWorldResume => Self::NormalWorldResume,
435 FuncId::MsgSend2 => Self::MsgSend2 {
436 sender_vm_id: regs[1] as u16,
437 flags: regs[2] as u32,
438 },
439 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
440 src_id: (regs[1] >> 16) as u16,
441 dst_id: regs[1] as u16,
442 flags: regs[2] as u32,
443 args: DirectMsgArgs::Args32([
444 regs[3] as u32,
445 regs[4] as u32,
446 regs[5] as u32,
447 regs[6] as u32,
448 regs[7] as u32,
449 ]),
450 },
451 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
452 src_id: (regs[1] >> 16) as u16,
453 dst_id: regs[1] as u16,
454 flags: regs[2] as u32,
455 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
456 },
457 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
458 src_id: (regs[1] >> 16) as u16,
459 dst_id: regs[1] as u16,
460 flags: regs[2] as u32,
461 args: DirectMsgArgs::Args32([
462 regs[3] as u32,
463 regs[4] as u32,
464 regs[5] as u32,
465 regs[6] as u32,
466 regs[7] as u32,
467 ]),
468 },
469 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
470 src_id: (regs[1] >> 16) as u16,
471 dst_id: regs[1] as u16,
472 flags: regs[2] as u32,
473 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
474 },
475 FuncId::MemDonate32 => Self::MemDonate {
476 total_len: regs[1] as u32,
477 frag_len: regs[2] as u32,
478 buf: if regs[3] != 0 && regs[4] != 0 {
479 Some(MemOpBuf::Buf32 {
480 addr: regs[3] as u32,
481 page_cnt: regs[4] as u32,
482 })
483 } else {
484 None
485 },
486 },
487 FuncId::MemDonate64 => Self::MemDonate {
488 total_len: regs[1] as u32,
489 frag_len: regs[2] as u32,
490 buf: if regs[3] != 0 && regs[4] != 0 {
491 Some(MemOpBuf::Buf64 {
492 addr: regs[3],
493 page_cnt: regs[4] as u32,
494 })
495 } else {
496 None
497 },
498 },
499 FuncId::MemLend32 => Self::MemLend {
500 total_len: regs[1] as u32,
501 frag_len: regs[2] as u32,
502 buf: if regs[3] != 0 && regs[4] != 0 {
503 Some(MemOpBuf::Buf32 {
504 addr: regs[3] as u32,
505 page_cnt: regs[4] as u32,
506 })
507 } else {
508 None
509 },
510 },
511 FuncId::MemLend64 => Self::MemLend {
512 total_len: regs[1] as u32,
513 frag_len: regs[2] as u32,
514 buf: if regs[3] != 0 && regs[4] != 0 {
515 Some(MemOpBuf::Buf64 {
516 addr: regs[3],
517 page_cnt: regs[4] as u32,
518 })
519 } else {
520 None
521 },
522 },
523 FuncId::MemShare32 => Self::MemShare {
524 total_len: regs[1] as u32,
525 frag_len: regs[2] as u32,
526 buf: if regs[3] != 0 && regs[4] != 0 {
527 Some(MemOpBuf::Buf32 {
528 addr: regs[3] as u32,
529 page_cnt: regs[4] as u32,
530 })
531 } else {
532 None
533 },
534 },
535 FuncId::MemShare64 => Self::MemShare {
536 total_len: regs[1] as u32,
537 frag_len: regs[2] as u32,
538 buf: if regs[3] != 0 && regs[4] != 0 {
539 Some(MemOpBuf::Buf64 {
540 addr: regs[3],
541 page_cnt: regs[4] as u32,
542 })
543 } else {
544 None
545 },
546 },
547 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
548 total_len: regs[1] as u32,
549 frag_len: regs[2] as u32,
550 buf: if regs[3] != 0 && regs[4] != 0 {
551 Some(MemOpBuf::Buf32 {
552 addr: regs[3] as u32,
553 page_cnt: regs[4] as u32,
554 })
555 } else {
556 None
557 },
558 },
559 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
560 total_len: regs[1] as u32,
561 frag_len: regs[2] as u32,
562 buf: if regs[3] != 0 && regs[4] != 0 {
563 Some(MemOpBuf::Buf64 {
564 addr: regs[3],
565 page_cnt: regs[4] as u32,
566 })
567 } else {
568 None
569 },
570 },
571 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
572 total_len: regs[1] as u32,
573 frag_len: regs[2] as u32,
574 },
575 FuncId::MemRelinquish => Self::MemRelinquish,
576 FuncId::MemReclaim => Self::MemReclaim {
577 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
578 flags: regs[3] as u32,
579 },
580 FuncId::MemPermGet32 => Self::MemPermGet {
581 addr: MemAddr::Addr32(regs[1] as u32),
582 },
583 FuncId::MemPermGet64 => Self::MemPermGet {
584 addr: MemAddr::Addr64(regs[1]),
585 },
586 FuncId::MemPermSet32 => Self::MemPermSet {
587 addr: MemAddr::Addr32(regs[1] as u32),
588 page_cnt: regs[2] as u32,
589 mem_perm: regs[3] as u32,
590 },
591 FuncId::MemPermSet64 => Self::MemPermSet {
592 addr: MemAddr::Addr64(regs[1]),
593 page_cnt: regs[2] as u32,
594 mem_perm: regs[3] as u32,
595 },
596 FuncId::ConsoleLog32 => Self::ConsoleLog {
597 char_cnt: regs[1] as u8,
598 char_lists: ConsoleLogChars::Reg32([
599 regs[2] as u32,
600 regs[3] as u32,
601 regs[4] as u32,
602 regs[5] as u32,
603 regs[6] as u32,
604 regs[7] as u32,
605 ]),
606 },
607 FuncId::ConsoleLog64 => Self::ConsoleLog {
608 char_cnt: regs[1] as u8,
609 char_lists: ConsoleLogChars::Reg64([
610 regs[2], regs[3], regs[4], regs[5], regs[6], regs[7],
611 ]),
612 },
613 };
614
615 Ok(msg)
616 }
617}
618
619impl Interface {
620 /// Returns the function ID for the call, if it has one.
621 pub fn function_id(&self) -> Option<FuncId> {
622 match self {
623 Interface::Error { .. } => Some(FuncId::Error),
624 Interface::Success { args, .. } => match args {
625 SuccessArgs::Result32(..) => Some(FuncId::Success32),
626 SuccessArgs::Result64(..) => Some(FuncId::Success64),
627 },
628 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
629 Interface::Version { .. } => Some(FuncId::Version),
630 Interface::VersionOut { .. } => None,
631 Interface::Features { .. } => Some(FuncId::Features),
632 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
633 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
634 Interface::RxTxMap { addr, .. } => match addr {
635 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
636 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
637 },
638 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
639 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
640 Interface::IdGet => Some(FuncId::IdGet),
641 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
642 Interface::MsgWait => Some(FuncId::MsgWait),
643 Interface::Yield => Some(FuncId::Yield),
644 Interface::Run { .. } => Some(FuncId::Run),
645 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
646 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
647 Interface::MsgSendDirectReq { args, .. } => match args {
648 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
649 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
650 },
651 Interface::MsgSendDirectResp { args, .. } => match args {
652 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
653 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
654 },
655 Interface::MemDonate { buf, .. } => match buf {
656 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
657 _ => Some(FuncId::MemDonate32),
658 },
659 Interface::MemLend { buf, .. } => match buf {
660 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
661 _ => Some(FuncId::MemLend32),
662 },
663 Interface::MemShare { buf, .. } => match buf {
664 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
665 _ => Some(FuncId::MemShare32),
666 },
667 Interface::MemRetrieveReq { buf, .. } => match buf {
668 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
669 _ => Some(FuncId::MemRetrieveReq32),
670 },
671 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
672 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
673 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
674 Interface::MemPermGet { addr, .. } => match addr {
675 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
676 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
677 },
678 Interface::MemPermSet { addr, .. } => match addr {
679 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
680 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
681 },
682 Interface::ConsoleLog { char_lists, .. } => match char_lists {
683 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
684 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
685 },
686 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200687 }
688
Balint Dobszay3aad9572025-01-17 16:54:11 +0100689 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
690 pub fn is_32bit(&self) -> bool {
691 match self {
692 Interface::Error { .. }
693 | Interface::Interrupt { .. }
694 | Interface::Version { .. }
695 | Interface::VersionOut { .. }
696 | Interface::Features { .. }
697 | Interface::RxAcquire { .. }
698 | Interface::RxRelease { .. }
699 | Interface::RxTxUnmap { .. }
700 | Interface::PartitionInfoGet { .. }
701 | Interface::IdGet
702 | Interface::SpmIdGet
703 | Interface::MsgWait
704 | Interface::Yield
705 | Interface::Run { .. }
706 | Interface::NormalWorldResume
707 | Interface::MsgSend2 { .. }
708 | Interface::MemRetrieveResp { .. }
709 | Interface::MemRelinquish
710 | Interface::MemReclaim { .. } => true,
711 Interface::Success {
712 args: SuccessArgs::Result32(..),
713 ..
714 } => true,
715 Interface::RxTxMap {
716 addr: RxTxAddr::Addr32 { .. },
717 ..
718 } => true,
719 Interface::MsgSendDirectReq { args, .. }
720 | Interface::MsgSendDirectResp { args, .. }
721 if matches!(args, DirectMsgArgs::Args32(_)) =>
722 {
723 true
724 }
725 Interface::MemDonate { buf, .. }
726 | Interface::MemLend { buf, .. }
727 | Interface::MemShare { buf, .. }
728 | Interface::MemRetrieveReq { buf, .. }
729 if buf.is_none() || matches!(buf, Some(MemOpBuf::Buf32 { .. })) =>
730 {
731 true
732 }
733 Interface::MemPermGet { addr, .. } | Interface::MemPermSet { addr, .. }
734 if matches!(addr, MemAddr::Addr32(_)) =>
735 {
736 true
737 }
738 Interface::ConsoleLog {
739 char_lists: ConsoleLogChars::Reg32(_),
740 ..
741 } => true,
742 _ => false,
743 }
744 }
745
746 pub fn copy_to_array(&self, a: &mut [u64; 8]) {
747 a.fill(0);
748 if let Some(function_id) = self.function_id() {
749 a[0] = function_id as u64;
750 }
751
752 match *self {
753 Interface::Error {
754 target_info,
755 error_code,
756 } => {
757 a[1] = u32::from(target_info).into();
758 a[2] = (error_code as u32).into();
759 }
760 Interface::Success { target_info, args } => {
761 a[1] = target_info.into();
762 match args {
763 SuccessArgs::Result32(regs) => {
764 a[2] = regs[0].into();
765 a[3] = regs[1].into();
766 a[4] = regs[2].into();
767 a[5] = regs[3].into();
768 a[6] = regs[4].into();
769 a[7] = regs[5].into();
770 }
771 SuccessArgs::Result64(regs) => {
772 a[2] = regs[0];
773 a[3] = regs[1];
774 a[4] = regs[2];
775 a[5] = regs[3];
776 a[6] = regs[4];
777 a[7] = regs[5];
778 }
779 }
780 }
781 Interface::Interrupt {
782 target_info,
783 interrupt_id,
784 } => {
785 a[1] = u32::from(target_info).into();
786 a[2] = interrupt_id.into();
787 }
788 Interface::Version { input_version } => {
789 a[1] = u32::from(input_version).into();
790 }
791 Interface::VersionOut { output_version } => {
792 a[0] = u32::from(output_version).into();
793 }
794 Interface::Features {
795 feat_id,
796 input_properties,
797 } => {
798 a[1] = u32::from(feat_id).into();
799 a[2] = input_properties.into();
800 }
801 Interface::RxAcquire { vm_id } => {
802 a[1] = vm_id.into();
803 }
804 Interface::RxRelease { vm_id } => {
805 a[1] = vm_id.into();
806 }
807 Interface::RxTxMap { addr, page_cnt } => {
808 match addr {
809 RxTxAddr::Addr32 { rx, tx } => {
810 a[1] = tx.into();
811 a[2] = rx.into();
812 }
813 RxTxAddr::Addr64 { rx, tx } => {
814 a[1] = tx;
815 a[2] = rx;
816 }
817 }
818 a[3] = page_cnt.into();
819 }
820 Interface::RxTxUnmap { id } => {
821 a[1] = id.into();
822 }
823 Interface::PartitionInfoGet { uuid, flags } => {
824 let bytes = uuid.into_bytes();
825 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
826 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
827 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
828 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
829 a[5] = flags.into();
830 }
831 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
832 Interface::Run { target_info } => {
833 a[1] = u32::from(target_info).into();
834 }
835 Interface::NormalWorldResume => {}
836 Interface::MsgSend2 {
837 sender_vm_id,
838 flags,
839 } => {
840 a[1] = sender_vm_id.into();
841 a[2] = flags.into();
842 }
843 Interface::MsgSendDirectReq {
844 src_id,
845 dst_id,
846 flags,
847 args,
848 } => {
849 a[1] = (src_id as u64) << 16 | dst_id as u64;
850 a[2] = flags.into();
851 match args {
852 DirectMsgArgs::Args32(args) => {
853 a[3] = args[0].into();
854 a[4] = args[1].into();
855 a[5] = args[2].into();
856 a[6] = args[3].into();
857 a[7] = args[4].into();
858 }
859 DirectMsgArgs::Args64(args) => {
860 a[3] = args[0];
861 a[4] = args[1];
862 a[5] = args[2];
863 a[6] = args[3];
864 a[7] = args[4];
865 }
866 }
867 }
868 Interface::MsgSendDirectResp {
869 src_id,
870 dst_id,
871 flags,
872 args,
873 } => {
874 a[1] = (src_id as u64) << 16 | dst_id as u64;
875 a[2] = flags.into();
876 match args {
877 DirectMsgArgs::Args32(args) => {
878 a[3] = args[0].into();
879 a[4] = args[1].into();
880 a[5] = args[2].into();
881 a[6] = args[3].into();
882 a[7] = args[4].into();
883 }
884 DirectMsgArgs::Args64(args) => {
885 a[3] = args[0];
886 a[4] = args[1];
887 a[5] = args[2];
888 a[6] = args[3];
889 a[7] = args[4];
890 }
891 }
892 }
893 Interface::MemDonate {
894 total_len,
895 frag_len,
896 buf,
897 } => {
898 a[1] = total_len.into();
899 a[2] = frag_len.into();
900 (a[3], a[4]) = match buf {
901 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
902 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
903 None => (0, 0),
904 };
905 }
906 Interface::MemLend {
907 total_len,
908 frag_len,
909 buf,
910 } => {
911 a[1] = total_len.into();
912 a[2] = frag_len.into();
913 (a[3], a[4]) = match buf {
914 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
915 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
916 None => (0, 0),
917 };
918 }
919 Interface::MemShare {
920 total_len,
921 frag_len,
922 buf,
923 } => {
924 a[1] = total_len.into();
925 a[2] = frag_len.into();
926 (a[3], a[4]) = match buf {
927 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
928 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
929 None => (0, 0),
930 };
931 }
932 Interface::MemRetrieveReq {
933 total_len,
934 frag_len,
935 buf,
936 } => {
937 a[1] = total_len.into();
938 a[2] = frag_len.into();
939 (a[3], a[4]) = match buf {
940 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
941 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
942 None => (0, 0),
943 };
944 }
945 Interface::MemRetrieveResp {
946 total_len,
947 frag_len,
948 } => {
949 a[1] = total_len.into();
950 a[2] = frag_len.into();
951 }
952 Interface::MemRelinquish => {}
953 Interface::MemReclaim { handle, flags } => {
954 let handle_regs: [u32; 2] = handle.into();
955 a[1] = handle_regs[0].into();
956 a[2] = handle_regs[1].into();
957 a[3] = flags.into();
958 }
959 Interface::MemPermGet { addr } => {
960 a[1] = match addr {
961 MemAddr::Addr32(addr) => addr.into(),
962 MemAddr::Addr64(addr) => addr,
963 };
964 }
965 Interface::MemPermSet {
966 addr,
967 page_cnt,
968 mem_perm,
969 } => {
970 a[1] = match addr {
971 MemAddr::Addr32(addr) => addr.into(),
972 MemAddr::Addr64(addr) => addr,
973 };
974 a[2] = page_cnt.into();
975 a[3] = mem_perm.into();
976 }
977 Interface::ConsoleLog {
978 char_cnt,
979 char_lists,
980 } => {
981 a[1] = char_cnt.into();
982 match char_lists {
983 ConsoleLogChars::Reg32(regs) => {
984 a[2] = regs[0].into();
985 a[3] = regs[1].into();
986 a[4] = regs[2].into();
987 a[5] = regs[3].into();
988 a[6] = regs[4].into();
989 a[7] = regs[5].into();
990 }
991 ConsoleLogChars::Reg64(regs) => {
992 a[2] = regs[0];
993 a[3] = regs[1];
994 a[4] = regs[2];
995 a[5] = regs[3];
996 a[6] = regs[4];
997 a[7] = regs[5];
998 }
999 }
1000 }
1001 }
1002 }
1003
1004 /// Helper function to create an FFA_SUCCESS interface without any arguments
1005 pub fn success32_noargs() -> Self {
1006 Self::Success {
1007 target_info: 0,
1008 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1009 }
1010 }
1011
1012 /// Helper function to create an FFA_ERROR interface without any arguments
1013 pub fn error(error_code: FfaError) -> Self {
1014 Self::Error {
1015 target_info: TargetInfo {
1016 endpoint_id: 0,
1017 vcpu_id: 0,
1018 },
1019 error_code,
1020 }
1021 }
1022}
1023
1024pub const CONSOLE_LOG_32_MAX_MSG_LEN: u8 = 24;
1025pub const CONSOLE_LOG_64_MAX_MSG_LEN: u8 = 48;
1026
1027pub fn parse_console_log(
1028 char_cnt: u8,
1029 char_lists: &ConsoleLogChars,
1030 log_bytes: &mut [u8],
1031) -> Result<(), FfaError> {
1032 match char_lists {
1033 ConsoleLogChars::Reg32(regs) => {
1034 if !(1..=CONSOLE_LOG_32_MAX_MSG_LEN).contains(&char_cnt) {
1035 return Err(FfaError::InvalidParameters);
1036 }
1037 for (i, reg) in regs.iter().enumerate() {
1038 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1039 }
1040 }
1041 ConsoleLogChars::Reg64(regs) => {
1042 if !(1..=CONSOLE_LOG_64_MAX_MSG_LEN).contains(&char_cnt) {
1043 return Err(FfaError::InvalidParameters);
1044 }
1045 for (i, reg) in regs.iter().enumerate() {
1046 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1047 }
1048 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001049 }
1050
Balint Dobszayc8802492025-01-15 18:11:39 +01001051 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001052}