blob: 466ec0a43ab2feb04a437be624e6866987507264 [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)]
Balint Dobszaya5846852025-02-26 15:38:53 +01005#![deny(clippy::undocumented_unsafe_blocks)]
6#![deny(unsafe_op_in_unsafe_fn)]
7#![doc = include_str!("../README.md")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02008
Andrew Walbran19970ba2024-11-25 15:35:00 +00009use core::fmt::{self, Debug, Display, Formatter};
Andrew Walbran44029a02024-11-25 15:34:31 +000010use num_enum::{IntoPrimitive, TryFromPrimitive};
11use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020012use uuid::Uuid;
13
14pub mod boot_info;
Balint Dobszayb2ff2bc2024-12-19 18:59:38 +010015mod ffa_v1_1;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020016pub mod memory_management;
17pub mod partition_info;
18
Balint Dobszaya5846852025-02-26 15:38:53 +010019/// Constant for 4K page size. On many occasions the FF-A spec defines memory size as count of 4K
20/// pages, regardless of the current translation granule.
Balint Dobszay3aad9572025-01-17 16:54:11 +010021pub const FFA_PAGE_SIZE_4K: usize = 4096;
22
Balint Dobszaya5846852025-02-26 15:38:53 +010023/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
24/// with the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +010025#[derive(Debug, Error)]
26pub enum Error {
27 #[error("Unrecognised FF-A function ID {0}")]
28 UnrecognisedFunctionId(u32),
29 #[error("Unrecognised FF-A feature ID {0}")]
30 UnrecognisedFeatureId(u8),
31 #[error("Unrecognised FF-A error code {0}")]
32 UnrecognisedErrorCode(i32),
33}
34
35impl From<Error> for FfaError {
36 fn from(value: Error) -> Self {
37 match value {
38 Error::UnrecognisedFunctionId(_) | Error::UnrecognisedFeatureId(_) => {
39 Self::NotSupported
40 }
41 Error::UnrecognisedErrorCode(_) => Self::InvalidParameters,
42 }
43 }
44}
Balint Dobszay5bf492f2024-07-29 17:21:32 +020045
Balint Dobszaya5846852025-02-26 15:38:53 +010046/// An FF-A instance is a valid combination of two FF-A components at an exception level boundary.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020047#[derive(PartialEq, Clone, Copy)]
48pub enum Instance {
Balint Dobszaya5846852025-02-26 15:38:53 +010049 /// The instance between the SPMC and SPMD.
Balint Dobszay5bf492f2024-07-29 17:21:32 +020050 SecurePhysical,
Balint Dobszaya5846852025-02-26 15:38:53 +010051 /// The instance between the SPMC and a physical SP (contains the SP's endpoint ID).
Balint Dobszay5bf492f2024-07-29 17:21:32 +020052 SecureVirtual(u16),
53}
54
Balint Dobszaya5846852025-02-26 15:38:53 +010055/// Function IDs of the various FF-A interfaces.
Andrew Walbran969b9252024-11-25 15:35:42 +000056#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay3aad9572025-01-17 16:54:11 +010057#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFunctionId))]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020058#[repr(u32)]
59pub enum FuncId {
60 Error = 0x84000060,
61 Success32 = 0x84000061,
62 Success64 = 0xc4000061,
63 Interrupt = 0x84000062,
64 Version = 0x84000063,
65 Features = 0x84000064,
66 RxAcquire = 0x84000084,
67 RxRelease = 0x84000065,
68 RxTxMap32 = 0x84000066,
69 RxTxMap64 = 0xc4000066,
70 RxTxUnmap = 0x84000067,
71 PartitionInfoGet = 0x84000068,
72 IdGet = 0x84000069,
73 SpmIdGet = 0x84000085,
74 MsgWait = 0x8400006b,
75 Yield = 0x8400006c,
76 Run = 0x8400006d,
77 NormalWorldResume = 0x8400007c,
78 MsgSend2 = 0x84000086,
79 MsgSendDirectReq32 = 0x8400006f,
80 MsgSendDirectReq64 = 0xc400006f,
81 MsgSendDirectResp32 = 0x84000070,
82 MsgSendDirectResp64 = 0xc4000070,
83 MemDonate32 = 0x84000071,
84 MemDonate64 = 0xc4000071,
85 MemLend32 = 0x84000072,
86 MemLend64 = 0xc4000072,
87 MemShare32 = 0x84000073,
88 MemShare64 = 0xc4000073,
89 MemRetrieveReq32 = 0x84000074,
90 MemRetrieveReq64 = 0xc4000074,
91 MemRetrieveResp = 0x84000075,
92 MemRelinquish = 0x84000076,
93 MemReclaim = 0x84000077,
94 MemPermGet32 = 0x84000088,
95 MemPermGet64 = 0xc4000088,
96 MemPermSet32 = 0x84000089,
97 MemPermSet64 = 0xc4000089,
98 ConsoleLog32 = 0x8400008a,
99 ConsoleLog64 = 0xc400008a,
100}
101
Balint Dobszaya5846852025-02-26 15:38:53 +0100102/// Error status codes used by the `FFA_ERROR` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100103#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
104#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
105#[repr(i32)]
106pub enum FfaError {
107 #[error("Not supported")]
108 NotSupported = -1,
109 #[error("Invalid parameters")]
110 InvalidParameters = -2,
111 #[error("No memory")]
112 NoMemory = -3,
113 #[error("Busy")]
114 Busy = -4,
115 #[error("Interrupted")]
116 Interrupted = -5,
117 #[error("Denied")]
118 Denied = -6,
119 #[error("Retry")]
120 Retry = -7,
121 #[error("Aborted")]
122 Aborted = -8,
123 #[error("No data")]
124 NoData = -9,
125}
126
Balint Dobszaya5846852025-02-26 15:38:53 +0100127/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200128#[derive(Debug, Eq, PartialEq, Clone, Copy)]
Balint Dobszay3aad9572025-01-17 16:54:11 +0100129pub struct TargetInfo {
130 pub endpoint_id: u16,
131 pub vcpu_id: u16,
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200132}
133
Balint Dobszay3aad9572025-01-17 16:54:11 +0100134impl From<u32> for TargetInfo {
135 fn from(value: u32) -> Self {
136 Self {
137 endpoint_id: (value >> 16) as u16,
138 vcpu_id: value as u16,
139 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200140 }
141}
142
Balint Dobszay3aad9572025-01-17 16:54:11 +0100143impl From<TargetInfo> for u32 {
144 fn from(value: TargetInfo) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100145 ((value.endpoint_id as u32) << 16) | value.vcpu_id as u32
Andrew Walbran0d315812024-11-25 15:36:36 +0000146 }
Balint Dobszay3aad9572025-01-17 16:54:11 +0100147}
Andrew Walbran0d315812024-11-25 15:36:36 +0000148
Balint Dobszaya5846852025-02-26 15:38:53 +0100149/// Arguments for the `FFA_SUCCESS` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100150#[derive(Debug, Eq, PartialEq, Clone, Copy)]
151pub enum SuccessArgs {
152 Result32([u32; 6]),
153 Result64([u64; 6]),
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200154}
155
Balint Dobszaya5846852025-02-26 15:38:53 +0100156/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
Andrew Walbran19970ba2024-11-25 15:35:00 +0000157#[derive(Clone, Copy, Eq, PartialEq)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200158pub struct Version(pub u16, pub u16);
159
160impl From<u32> for Version {
161 fn from(val: u32) -> Self {
162 Self((val >> 16) as u16, val as u16)
163 }
164}
165
166impl From<Version> for u32 {
167 fn from(v: Version) -> Self {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100168 ((v.0 as u32) << 16) | v.1 as u32
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200169 }
170}
171
Andrew Walbran19970ba2024-11-25 15:35:00 +0000172impl Display for Version {
173 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
174 write!(f, "{}.{}", self.0, self.1)
175 }
176}
177
178impl Debug for Version {
179 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
180 Display::fmt(self, f)
181 }
182}
183
Balint Dobszaya5846852025-02-26 15:38:53 +0100184/// Feature IDs used by the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100185#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
186#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
187#[repr(u8)]
188pub enum FeatureId {
189 NotificationPendingInterrupt = 0x1,
190 ScheduleReceiverInterrupt = 0x2,
191 ManagedExitInterrupt = 0x3,
192}
Balint Dobszayc8802492025-01-15 18:11:39 +0100193
Balint Dobszaya5846852025-02-26 15:38:53 +0100194/// Arguments for the `FFA_FEATURES` interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100195#[derive(Debug, Eq, PartialEq, Clone, Copy)]
196pub enum Feature {
197 FuncId(FuncId),
198 FeatureId(FeatureId),
199}
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200200
Balint Dobszay3aad9572025-01-17 16:54:11 +0100201impl TryFrom<u32> for Feature {
202 type Error = Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200203
Balint Dobszay3aad9572025-01-17 16:54:11 +0100204 fn try_from(value: u32) -> Result<Self, Self::Error> {
205 let res = if (value >> 31) & 1 == 1 {
206 Self::FuncId(value.try_into()?)
207 } else {
208 Self::FeatureId((value as u8).try_into()?)
209 };
210
211 Ok(res)
212 }
213}
214
215impl From<Feature> for u32 {
216 fn from(value: Feature) -> Self {
217 match value {
218 Feature::FuncId(func_id) => (1 << 31) | func_id as u32,
219 Feature::FeatureId(feature_id) => feature_id as u32,
220 }
221 }
222}
223
Balint Dobszaya5846852025-02-26 15:38:53 +0100224/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100225#[derive(Debug, Eq, PartialEq, Clone, Copy)]
226pub enum RxTxAddr {
227 Addr32 { rx: u32, tx: u32 },
228 Addr64 { rx: u64, tx: u64 },
229}
230
Balint Dobszaya5846852025-02-26 15:38:53 +0100231/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100232#[derive(Debug, Eq, PartialEq, Clone, Copy)]
233pub enum DirectMsgArgs {
234 Args32([u32; 5]),
235 Args64([u64; 5]),
236}
237
Balint Dobszaya5846852025-02-26 15:38:53 +0100238/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
239/// descriptor. Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX
240/// buffer is not used to transmit the transaction descriptor.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100241#[derive(Debug, Eq, PartialEq, Clone, Copy)]
242pub enum MemOpBuf {
243 Buf32 { addr: u32, page_cnt: u32 },
244 Buf64 { addr: u64, page_cnt: u32 },
245}
246
Balint Dobszaya5846852025-02-26 15:38:53 +0100247/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100248#[derive(Debug, Eq, PartialEq, Clone, Copy)]
249pub enum MemAddr {
250 Addr32(u32),
251 Addr64(u64),
252}
253
Balint Dobszaya5846852025-02-26 15:38:53 +0100254/// Argument for the `FFA_CONSOLE_LOG` interface. Currently only supports x0..x7 instead of x0..x17.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100255#[derive(Debug, Eq, PartialEq, Clone, Copy)]
256pub enum ConsoleLogChars {
257 Reg32([u32; 6]),
258 Reg64([u64; 6]),
259}
260
Balint Dobszaya5846852025-02-26 15:38:53 +0100261/// FF-A "message types", the terminology used by the spec is "interfaces". The interfaces are used
262/// by FF-A components for communication at an FF-A instance. The spec also describes the valid FF-A
263/// instances and conduits for each interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100264#[derive(Debug, Eq, PartialEq, Clone, Copy)]
265pub enum Interface {
266 Error {
267 target_info: TargetInfo,
268 error_code: FfaError,
269 },
270 Success {
271 target_info: u32,
272 args: SuccessArgs,
273 },
274 Interrupt {
275 target_info: TargetInfo,
276 interrupt_id: u32,
277 },
278 Version {
279 input_version: Version,
280 },
281 VersionOut {
282 output_version: Version,
283 },
284 Features {
285 feat_id: Feature,
286 input_properties: u32,
287 },
288 RxAcquire {
289 vm_id: u16,
290 },
291 RxRelease {
292 vm_id: u16,
293 },
294 RxTxMap {
295 addr: RxTxAddr,
296 page_cnt: u32,
297 },
298 RxTxUnmap {
299 id: u16,
300 },
301 PartitionInfoGet {
302 uuid: Uuid,
303 flags: u32,
304 },
305 IdGet,
306 SpmIdGet,
307 MsgWait,
308 Yield,
309 Run {
310 target_info: TargetInfo,
311 },
312 NormalWorldResume,
313 MsgSend2 {
314 sender_vm_id: u16,
315 flags: u32,
316 },
317 MsgSendDirectReq {
318 src_id: u16,
319 dst_id: u16,
320 flags: u32,
321 args: DirectMsgArgs,
322 },
323 MsgSendDirectResp {
324 src_id: u16,
325 dst_id: u16,
326 flags: u32,
327 args: DirectMsgArgs,
328 },
329 MemDonate {
330 total_len: u32,
331 frag_len: u32,
332 buf: Option<MemOpBuf>,
333 },
334 MemLend {
335 total_len: u32,
336 frag_len: u32,
337 buf: Option<MemOpBuf>,
338 },
339 MemShare {
340 total_len: u32,
341 frag_len: u32,
342 buf: Option<MemOpBuf>,
343 },
344 MemRetrieveReq {
345 total_len: u32,
346 frag_len: u32,
347 buf: Option<MemOpBuf>,
348 },
349 MemRetrieveResp {
350 total_len: u32,
351 frag_len: u32,
352 },
353 MemRelinquish,
354 MemReclaim {
355 handle: memory_management::Handle,
356 flags: u32,
357 },
358 MemPermGet {
359 addr: MemAddr,
360 },
361 MemPermSet {
362 addr: MemAddr,
363 page_cnt: u32,
364 mem_perm: u32,
365 },
366 ConsoleLog {
367 char_cnt: u8,
368 char_lists: ConsoleLogChars,
369 },
370}
371
372impl TryFrom<[u64; 8]> for Interface {
373 type Error = Error;
374
375 fn try_from(regs: [u64; 8]) -> Result<Self, Error> {
376 let fid = FuncId::try_from(regs[0] as u32)?;
377
378 let msg = match fid {
379 FuncId::Error => Self::Error {
380 target_info: (regs[1] as u32).into(),
381 error_code: FfaError::try_from(regs[2] as i32)?,
382 },
383 FuncId::Success32 => Self::Success {
384 target_info: regs[1] as u32,
385 args: SuccessArgs::Result32([
386 regs[2] as u32,
387 regs[3] as u32,
388 regs[4] as u32,
389 regs[5] as u32,
390 regs[6] as u32,
391 regs[7] as u32,
392 ]),
393 },
394 FuncId::Success64 => Self::Success {
395 target_info: regs[1] as u32,
396 args: SuccessArgs::Result64([regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]]),
397 },
398 FuncId::Interrupt => Self::Interrupt {
399 target_info: (regs[1] as u32).into(),
400 interrupt_id: regs[2] as u32,
401 },
402 FuncId::Version => Self::Version {
403 input_version: (regs[1] as u32).into(),
404 },
405 FuncId::Features => Self::Features {
406 feat_id: (regs[1] as u32).try_into()?,
407 input_properties: regs[2] as u32,
408 },
409 FuncId::RxAcquire => Self::RxAcquire {
410 vm_id: regs[1] as u16,
411 },
412 FuncId::RxRelease => Self::RxRelease {
413 vm_id: regs[1] as u16,
414 },
415 FuncId::RxTxMap32 => {
416 let addr = RxTxAddr::Addr32 {
417 rx: regs[2] as u32,
418 tx: regs[1] as u32,
419 };
420 let page_cnt = regs[3] as u32;
421
422 Self::RxTxMap { addr, page_cnt }
423 }
424 FuncId::RxTxMap64 => {
425 let addr = RxTxAddr::Addr64 {
426 rx: regs[2],
427 tx: regs[1],
428 };
429 let page_cnt = regs[3] as u32;
430
431 Self::RxTxMap { addr, page_cnt }
432 }
433 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u16 },
434 FuncId::PartitionInfoGet => {
435 let uuid_words = [
436 regs[1] as u32,
437 regs[2] as u32,
438 regs[3] as u32,
439 regs[4] as u32,
440 ];
441 let mut bytes: [u8; 16] = [0; 16];
442 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
443 bytes[i] = b;
444 }
445 Self::PartitionInfoGet {
446 uuid: Uuid::from_bytes(bytes),
447 flags: regs[5] as u32,
448 }
449 }
450 FuncId::IdGet => Self::IdGet,
451 FuncId::SpmIdGet => Self::SpmIdGet,
452 FuncId::MsgWait => Self::MsgWait,
453 FuncId::Yield => Self::Yield,
454 FuncId::Run => Self::Run {
455 target_info: (regs[1] as u32).into(),
456 },
457 FuncId::NormalWorldResume => Self::NormalWorldResume,
458 FuncId::MsgSend2 => Self::MsgSend2 {
459 sender_vm_id: regs[1] as u16,
460 flags: regs[2] as u32,
461 },
462 FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
463 src_id: (regs[1] >> 16) as u16,
464 dst_id: regs[1] as u16,
465 flags: regs[2] as u32,
466 args: DirectMsgArgs::Args32([
467 regs[3] as u32,
468 regs[4] as u32,
469 regs[5] as u32,
470 regs[6] as u32,
471 regs[7] as u32,
472 ]),
473 },
474 FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
475 src_id: (regs[1] >> 16) as u16,
476 dst_id: regs[1] as u16,
477 flags: regs[2] as u32,
478 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
479 },
480 FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
481 src_id: (regs[1] >> 16) as u16,
482 dst_id: regs[1] as u16,
483 flags: regs[2] as u32,
484 args: DirectMsgArgs::Args32([
485 regs[3] as u32,
486 regs[4] as u32,
487 regs[5] as u32,
488 regs[6] as u32,
489 regs[7] as u32,
490 ]),
491 },
492 FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
493 src_id: (regs[1] >> 16) as u16,
494 dst_id: regs[1] as u16,
495 flags: regs[2] as u32,
496 args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
497 },
498 FuncId::MemDonate32 => Self::MemDonate {
499 total_len: regs[1] as u32,
500 frag_len: regs[2] as u32,
501 buf: if regs[3] != 0 && regs[4] != 0 {
502 Some(MemOpBuf::Buf32 {
503 addr: regs[3] as u32,
504 page_cnt: regs[4] as u32,
505 })
506 } else {
507 None
508 },
509 },
510 FuncId::MemDonate64 => Self::MemDonate {
511 total_len: regs[1] as u32,
512 frag_len: regs[2] as u32,
513 buf: if regs[3] != 0 && regs[4] != 0 {
514 Some(MemOpBuf::Buf64 {
515 addr: regs[3],
516 page_cnt: regs[4] as u32,
517 })
518 } else {
519 None
520 },
521 },
522 FuncId::MemLend32 => Self::MemLend {
523 total_len: regs[1] as u32,
524 frag_len: regs[2] as u32,
525 buf: if regs[3] != 0 && regs[4] != 0 {
526 Some(MemOpBuf::Buf32 {
527 addr: regs[3] as u32,
528 page_cnt: regs[4] as u32,
529 })
530 } else {
531 None
532 },
533 },
534 FuncId::MemLend64 => Self::MemLend {
535 total_len: regs[1] as u32,
536 frag_len: regs[2] as u32,
537 buf: if regs[3] != 0 && regs[4] != 0 {
538 Some(MemOpBuf::Buf64 {
539 addr: regs[3],
540 page_cnt: regs[4] as u32,
541 })
542 } else {
543 None
544 },
545 },
546 FuncId::MemShare32 => Self::MemShare {
547 total_len: regs[1] as u32,
548 frag_len: regs[2] as u32,
549 buf: if regs[3] != 0 && regs[4] != 0 {
550 Some(MemOpBuf::Buf32 {
551 addr: regs[3] as u32,
552 page_cnt: regs[4] as u32,
553 })
554 } else {
555 None
556 },
557 },
558 FuncId::MemShare64 => Self::MemShare {
559 total_len: regs[1] as u32,
560 frag_len: regs[2] as u32,
561 buf: if regs[3] != 0 && regs[4] != 0 {
562 Some(MemOpBuf::Buf64 {
563 addr: regs[3],
564 page_cnt: regs[4] as u32,
565 })
566 } else {
567 None
568 },
569 },
570 FuncId::MemRetrieveReq32 => Self::MemRetrieveReq {
571 total_len: regs[1] as u32,
572 frag_len: regs[2] as u32,
573 buf: if regs[3] != 0 && regs[4] != 0 {
574 Some(MemOpBuf::Buf32 {
575 addr: regs[3] as u32,
576 page_cnt: regs[4] as u32,
577 })
578 } else {
579 None
580 },
581 },
582 FuncId::MemRetrieveReq64 => Self::MemRetrieveReq {
583 total_len: regs[1] as u32,
584 frag_len: regs[2] as u32,
585 buf: if regs[3] != 0 && regs[4] != 0 {
586 Some(MemOpBuf::Buf64 {
587 addr: regs[3],
588 page_cnt: regs[4] as u32,
589 })
590 } else {
591 None
592 },
593 },
594 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
595 total_len: regs[1] as u32,
596 frag_len: regs[2] as u32,
597 },
598 FuncId::MemRelinquish => Self::MemRelinquish,
599 FuncId::MemReclaim => Self::MemReclaim {
600 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
601 flags: regs[3] as u32,
602 },
603 FuncId::MemPermGet32 => Self::MemPermGet {
604 addr: MemAddr::Addr32(regs[1] as u32),
605 },
606 FuncId::MemPermGet64 => Self::MemPermGet {
607 addr: MemAddr::Addr64(regs[1]),
608 },
609 FuncId::MemPermSet32 => Self::MemPermSet {
610 addr: MemAddr::Addr32(regs[1] as u32),
611 page_cnt: regs[2] as u32,
612 mem_perm: regs[3] as u32,
613 },
614 FuncId::MemPermSet64 => Self::MemPermSet {
615 addr: MemAddr::Addr64(regs[1]),
616 page_cnt: regs[2] as u32,
617 mem_perm: regs[3] as u32,
618 },
619 FuncId::ConsoleLog32 => Self::ConsoleLog {
620 char_cnt: regs[1] as u8,
621 char_lists: ConsoleLogChars::Reg32([
622 regs[2] as u32,
623 regs[3] as u32,
624 regs[4] as u32,
625 regs[5] as u32,
626 regs[6] as u32,
627 regs[7] as u32,
628 ]),
629 },
630 FuncId::ConsoleLog64 => Self::ConsoleLog {
631 char_cnt: regs[1] as u8,
632 char_lists: ConsoleLogChars::Reg64([
633 regs[2], regs[3], regs[4], regs[5], regs[6], regs[7],
634 ]),
635 },
636 };
637
638 Ok(msg)
639 }
640}
641
642impl Interface {
643 /// Returns the function ID for the call, if it has one.
644 pub fn function_id(&self) -> Option<FuncId> {
645 match self {
646 Interface::Error { .. } => Some(FuncId::Error),
647 Interface::Success { args, .. } => match args {
648 SuccessArgs::Result32(..) => Some(FuncId::Success32),
649 SuccessArgs::Result64(..) => Some(FuncId::Success64),
650 },
651 Interface::Interrupt { .. } => Some(FuncId::Interrupt),
652 Interface::Version { .. } => Some(FuncId::Version),
653 Interface::VersionOut { .. } => None,
654 Interface::Features { .. } => Some(FuncId::Features),
655 Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
656 Interface::RxRelease { .. } => Some(FuncId::RxRelease),
657 Interface::RxTxMap { addr, .. } => match addr {
658 RxTxAddr::Addr32 { .. } => Some(FuncId::RxTxMap32),
659 RxTxAddr::Addr64 { .. } => Some(FuncId::RxTxMap64),
660 },
661 Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
662 Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
663 Interface::IdGet => Some(FuncId::IdGet),
664 Interface::SpmIdGet => Some(FuncId::SpmIdGet),
665 Interface::MsgWait => Some(FuncId::MsgWait),
666 Interface::Yield => Some(FuncId::Yield),
667 Interface::Run { .. } => Some(FuncId::Run),
668 Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
669 Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
670 Interface::MsgSendDirectReq { args, .. } => match args {
671 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
672 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
673 },
674 Interface::MsgSendDirectResp { args, .. } => match args {
675 DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
676 DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
677 },
678 Interface::MemDonate { buf, .. } => match buf {
679 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemDonate64),
680 _ => Some(FuncId::MemDonate32),
681 },
682 Interface::MemLend { buf, .. } => match buf {
683 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemLend64),
684 _ => Some(FuncId::MemLend32),
685 },
686 Interface::MemShare { buf, .. } => match buf {
687 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemShare64),
688 _ => Some(FuncId::MemShare32),
689 },
690 Interface::MemRetrieveReq { buf, .. } => match buf {
691 Some(MemOpBuf::Buf64 { .. }) => Some(FuncId::MemRetrieveReq64),
692 _ => Some(FuncId::MemRetrieveReq32),
693 },
694 Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
695 Interface::MemRelinquish => Some(FuncId::MemRelinquish),
696 Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
697 Interface::MemPermGet { addr, .. } => match addr {
698 MemAddr::Addr32(_) => Some(FuncId::MemPermGet32),
699 MemAddr::Addr64(_) => Some(FuncId::MemPermGet64),
700 },
701 Interface::MemPermSet { addr, .. } => match addr {
702 MemAddr::Addr32(_) => Some(FuncId::MemPermSet32),
703 MemAddr::Addr64(_) => Some(FuncId::MemPermSet64),
704 },
705 Interface::ConsoleLog { char_lists, .. } => match char_lists {
706 ConsoleLogChars::Reg32(_) => Some(FuncId::ConsoleLog32),
707 ConsoleLogChars::Reg64(_) => Some(FuncId::ConsoleLog64),
708 },
709 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +0200710 }
711
Balint Dobszay3aad9572025-01-17 16:54:11 +0100712 /// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
713 pub fn is_32bit(&self) -> bool {
714 match self {
715 Interface::Error { .. }
716 | Interface::Interrupt { .. }
717 | Interface::Version { .. }
718 | Interface::VersionOut { .. }
719 | Interface::Features { .. }
720 | Interface::RxAcquire { .. }
721 | Interface::RxRelease { .. }
722 | Interface::RxTxUnmap { .. }
723 | Interface::PartitionInfoGet { .. }
724 | Interface::IdGet
725 | Interface::SpmIdGet
726 | Interface::MsgWait
727 | Interface::Yield
728 | Interface::Run { .. }
729 | Interface::NormalWorldResume
730 | Interface::MsgSend2 { .. }
731 | Interface::MemRetrieveResp { .. }
732 | Interface::MemRelinquish
733 | Interface::MemReclaim { .. } => true,
734 Interface::Success {
735 args: SuccessArgs::Result32(..),
736 ..
737 } => true,
738 Interface::RxTxMap {
739 addr: RxTxAddr::Addr32 { .. },
740 ..
741 } => true,
742 Interface::MsgSendDirectReq { args, .. }
743 | Interface::MsgSendDirectResp { args, .. }
744 if matches!(args, DirectMsgArgs::Args32(_)) =>
745 {
746 true
747 }
748 Interface::MemDonate { buf, .. }
749 | Interface::MemLend { buf, .. }
750 | Interface::MemShare { buf, .. }
751 | Interface::MemRetrieveReq { buf, .. }
752 if buf.is_none() || matches!(buf, Some(MemOpBuf::Buf32 { .. })) =>
753 {
754 true
755 }
756 Interface::MemPermGet { addr, .. } | Interface::MemPermSet { addr, .. }
757 if matches!(addr, MemAddr::Addr32(_)) =>
758 {
759 true
760 }
761 Interface::ConsoleLog {
762 char_lists: ConsoleLogChars::Reg32(_),
763 ..
764 } => true,
765 _ => false,
766 }
767 }
768
Balint Dobszaya5846852025-02-26 15:38:53 +0100769 /// Create register contents for an interface.
Balint Dobszay3aad9572025-01-17 16:54:11 +0100770 pub fn copy_to_array(&self, a: &mut [u64; 8]) {
771 a.fill(0);
772 if let Some(function_id) = self.function_id() {
773 a[0] = function_id as u64;
774 }
775
776 match *self {
777 Interface::Error {
778 target_info,
779 error_code,
780 } => {
781 a[1] = u32::from(target_info).into();
782 a[2] = (error_code as u32).into();
783 }
784 Interface::Success { target_info, args } => {
785 a[1] = target_info.into();
786 match args {
787 SuccessArgs::Result32(regs) => {
788 a[2] = regs[0].into();
789 a[3] = regs[1].into();
790 a[4] = regs[2].into();
791 a[5] = regs[3].into();
792 a[6] = regs[4].into();
793 a[7] = regs[5].into();
794 }
795 SuccessArgs::Result64(regs) => {
796 a[2] = regs[0];
797 a[3] = regs[1];
798 a[4] = regs[2];
799 a[5] = regs[3];
800 a[6] = regs[4];
801 a[7] = regs[5];
802 }
803 }
804 }
805 Interface::Interrupt {
806 target_info,
807 interrupt_id,
808 } => {
809 a[1] = u32::from(target_info).into();
810 a[2] = interrupt_id.into();
811 }
812 Interface::Version { input_version } => {
813 a[1] = u32::from(input_version).into();
814 }
815 Interface::VersionOut { output_version } => {
816 a[0] = u32::from(output_version).into();
817 }
818 Interface::Features {
819 feat_id,
820 input_properties,
821 } => {
822 a[1] = u32::from(feat_id).into();
823 a[2] = input_properties.into();
824 }
825 Interface::RxAcquire { vm_id } => {
826 a[1] = vm_id.into();
827 }
828 Interface::RxRelease { vm_id } => {
829 a[1] = vm_id.into();
830 }
831 Interface::RxTxMap { addr, page_cnt } => {
832 match addr {
833 RxTxAddr::Addr32 { rx, tx } => {
834 a[1] = tx.into();
835 a[2] = rx.into();
836 }
837 RxTxAddr::Addr64 { rx, tx } => {
838 a[1] = tx;
839 a[2] = rx;
840 }
841 }
842 a[3] = page_cnt.into();
843 }
844 Interface::RxTxUnmap { id } => {
845 a[1] = id.into();
846 }
847 Interface::PartitionInfoGet { uuid, flags } => {
848 let bytes = uuid.into_bytes();
849 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]).into();
850 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]).into();
851 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]).into();
852 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
853 a[5] = flags.into();
854 }
855 Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
856 Interface::Run { target_info } => {
857 a[1] = u32::from(target_info).into();
858 }
859 Interface::NormalWorldResume => {}
860 Interface::MsgSend2 {
861 sender_vm_id,
862 flags,
863 } => {
864 a[1] = sender_vm_id.into();
865 a[2] = flags.into();
866 }
867 Interface::MsgSendDirectReq {
868 src_id,
869 dst_id,
870 flags,
871 args,
872 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100873 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100874 a[2] = flags.into();
875 match args {
876 DirectMsgArgs::Args32(args) => {
877 a[3] = args[0].into();
878 a[4] = args[1].into();
879 a[5] = args[2].into();
880 a[6] = args[3].into();
881 a[7] = args[4].into();
882 }
883 DirectMsgArgs::Args64(args) => {
884 a[3] = args[0];
885 a[4] = args[1];
886 a[5] = args[2];
887 a[6] = args[3];
888 a[7] = args[4];
889 }
890 }
891 }
892 Interface::MsgSendDirectResp {
893 src_id,
894 dst_id,
895 flags,
896 args,
897 } => {
Balint Dobszaye9a3e762025-02-26 17:29:57 +0100898 a[1] = ((src_id as u64) << 16) | dst_id as u64;
Balint Dobszay3aad9572025-01-17 16:54:11 +0100899 a[2] = flags.into();
900 match args {
901 DirectMsgArgs::Args32(args) => {
902 a[3] = args[0].into();
903 a[4] = args[1].into();
904 a[5] = args[2].into();
905 a[6] = args[3].into();
906 a[7] = args[4].into();
907 }
908 DirectMsgArgs::Args64(args) => {
909 a[3] = args[0];
910 a[4] = args[1];
911 a[5] = args[2];
912 a[6] = args[3];
913 a[7] = args[4];
914 }
915 }
916 }
917 Interface::MemDonate {
918 total_len,
919 frag_len,
920 buf,
921 } => {
922 a[1] = total_len.into();
923 a[2] = frag_len.into();
924 (a[3], a[4]) = match buf {
925 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
926 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
927 None => (0, 0),
928 };
929 }
930 Interface::MemLend {
931 total_len,
932 frag_len,
933 buf,
934 } => {
935 a[1] = total_len.into();
936 a[2] = frag_len.into();
937 (a[3], a[4]) = match buf {
938 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
939 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
940 None => (0, 0),
941 };
942 }
943 Interface::MemShare {
944 total_len,
945 frag_len,
946 buf,
947 } => {
948 a[1] = total_len.into();
949 a[2] = frag_len.into();
950 (a[3], a[4]) = match buf {
951 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
952 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
953 None => (0, 0),
954 };
955 }
956 Interface::MemRetrieveReq {
957 total_len,
958 frag_len,
959 buf,
960 } => {
961 a[1] = total_len.into();
962 a[2] = frag_len.into();
963 (a[3], a[4]) = match buf {
964 Some(MemOpBuf::Buf32 { addr, page_cnt }) => (addr.into(), page_cnt.into()),
965 Some(MemOpBuf::Buf64 { addr, page_cnt }) => (addr, page_cnt.into()),
966 None => (0, 0),
967 };
968 }
969 Interface::MemRetrieveResp {
970 total_len,
971 frag_len,
972 } => {
973 a[1] = total_len.into();
974 a[2] = frag_len.into();
975 }
976 Interface::MemRelinquish => {}
977 Interface::MemReclaim { handle, flags } => {
978 let handle_regs: [u32; 2] = handle.into();
979 a[1] = handle_regs[0].into();
980 a[2] = handle_regs[1].into();
981 a[3] = flags.into();
982 }
983 Interface::MemPermGet { addr } => {
984 a[1] = match addr {
985 MemAddr::Addr32(addr) => addr.into(),
986 MemAddr::Addr64(addr) => addr,
987 };
988 }
989 Interface::MemPermSet {
990 addr,
991 page_cnt,
992 mem_perm,
993 } => {
994 a[1] = match addr {
995 MemAddr::Addr32(addr) => addr.into(),
996 MemAddr::Addr64(addr) => addr,
997 };
998 a[2] = page_cnt.into();
999 a[3] = mem_perm.into();
1000 }
1001 Interface::ConsoleLog {
1002 char_cnt,
1003 char_lists,
1004 } => {
1005 a[1] = char_cnt.into();
1006 match char_lists {
1007 ConsoleLogChars::Reg32(regs) => {
1008 a[2] = regs[0].into();
1009 a[3] = regs[1].into();
1010 a[4] = regs[2].into();
1011 a[5] = regs[3].into();
1012 a[6] = regs[4].into();
1013 a[7] = regs[5].into();
1014 }
1015 ConsoleLogChars::Reg64(regs) => {
1016 a[2] = regs[0];
1017 a[3] = regs[1];
1018 a[4] = regs[2];
1019 a[5] = regs[3];
1020 a[6] = regs[4];
1021 a[7] = regs[5];
1022 }
1023 }
1024 }
1025 }
1026 }
1027
Balint Dobszaya5846852025-02-26 15:38:53 +01001028 /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001029 pub fn success32_noargs() -> Self {
1030 Self::Success {
1031 target_info: 0,
1032 args: SuccessArgs::Result32([0, 0, 0, 0, 0, 0]),
1033 }
1034 }
1035
Balint Dobszaya5846852025-02-26 15:38:53 +01001036 /// Helper function to create an `FFA_ERROR` interface with an error code.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001037 pub fn error(error_code: FfaError) -> Self {
1038 Self::Error {
1039 target_info: TargetInfo {
1040 endpoint_id: 0,
1041 vcpu_id: 0,
1042 },
1043 error_code,
1044 }
1045 }
1046}
1047
Balint Dobszaya5846852025-02-26 15:38:53 +01001048/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
1049pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
1050/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message. Note: this
1051/// value currently differs from the spec because the library currently only supports parsing 8
1052/// registers instead of 18.
1053pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 48;
Balint Dobszay3aad9572025-01-17 16:54:11 +01001054
Balint Dobszaya5846852025-02-26 15:38:53 +01001055/// Helper function to convert the "Tightly packed list of characters" format used by the
1056/// `FFA_CONSOLE_LOG` interface into a byte slice.
Balint Dobszay3aad9572025-01-17 16:54:11 +01001057pub fn parse_console_log(
1058 char_cnt: u8,
1059 char_lists: &ConsoleLogChars,
1060 log_bytes: &mut [u8],
1061) -> Result<(), FfaError> {
1062 match char_lists {
1063 ConsoleLogChars::Reg32(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001064 if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001065 return Err(FfaError::InvalidParameters);
1066 }
1067 for (i, reg) in regs.iter().enumerate() {
1068 log_bytes[4 * i..4 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1069 }
1070 }
1071 ConsoleLogChars::Reg64(regs) => {
Balint Dobszaya5846852025-02-26 15:38:53 +01001072 if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
Balint Dobszay3aad9572025-01-17 16:54:11 +01001073 return Err(FfaError::InvalidParameters);
1074 }
1075 for (i, reg) in regs.iter().enumerate() {
1076 log_bytes[8 * i..8 * (i + 1)].copy_from_slice(&reg.to_le_bytes());
1077 }
1078 }
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001079 }
1080
Balint Dobszayc8802492025-01-15 18:11:39 +01001081 Ok(())
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001082}