blob: efd5256c191eb8d1079e642f658dbfb0c624d080 [file] [log] [blame]
// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
// SPDX-License-Identifier: MIT OR Apache-2.0
#![cfg_attr(not(test), no_std)]
use core::fmt::{self, Debug, Display, Formatter};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use thiserror::Error;
use uuid::Uuid;
pub mod boot_info;
mod ffa_v1_1;
pub mod memory_management;
pub mod partition_info;
pub const FFA_PAGE_SIZE: usize = 4096;
#[derive(PartialEq, Clone, Copy)]
pub enum Instance {
SecurePhysical,
SecureVirtual(u16),
}
/// FF-A v1.1, Table 12.2: Error status codes
#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
#[repr(i32)]
pub enum Error {
#[error("Not supported")]
NotSupported = -1,
#[error("Invalid parameters")]
InvalidParameters = -2,
#[error("No memory")]
NoMemory = -3,
#[error("Busy")]
Busy = -4,
#[error("Interrupted")]
Interrupted = -5,
#[error("Denied")]
Denied = -6,
#[error("Retry")]
Retry = -7,
#[error("Aborted")]
Aborted = -8,
#[error("No data")]
NoData = -9,
}
/// An integer couldn't be converted to a [`FuncId`] because it is not a recognised function.
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
#[error("Unrecognised function ID {0} for FF-A")]
pub struct UnrecognisedFunctionIdError(u32);
/// FF-A v1.1: Function IDs
#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
#[num_enum(error_type(name = UnrecognisedFunctionIdError, constructor = UnrecognisedFunctionIdError))]
#[repr(u32)]
pub enum FuncId {
Error = 0x84000060,
Success32 = 0x84000061,
Success64 = 0xc4000061,
Interrupt = 0x84000062,
Version = 0x84000063,
Features = 0x84000064,
RxAcquire = 0x84000084,
RxRelease = 0x84000065,
RxTxMap32 = 0x84000066,
RxTxMap64 = 0xc4000066,
RxTxUnmap = 0x84000067,
PartitionInfoGet = 0x84000068,
IdGet = 0x84000069,
SpmIdGet = 0x84000085,
MsgWait = 0x8400006b,
Yield = 0x8400006c,
Run = 0x8400006d,
NormalWorldResume = 0x8400007c,
MsgSend2 = 0x84000086,
MsgSendDirectReq32 = 0x8400006f,
MsgSendDirectReq64 = 0xc400006f,
MsgSendDirectResp32 = 0x84000070,
MsgSendDirectResp64 = 0xc4000070,
MemDonate32 = 0x84000071,
MemDonate64 = 0xc4000071,
MemLend32 = 0x84000072,
MemLend64 = 0xc4000072,
MemShare32 = 0x84000073,
MemShare64 = 0xc4000073,
MemRetrieveReq32 = 0x84000074,
MemRetrieveReq64 = 0xc4000074,
MemRetrieveResp = 0x84000075,
MemRelinquish = 0x84000076,
MemReclaim = 0x84000077,
MemPermGet32 = 0x84000088,
MemPermGet64 = 0xc4000088,
MemPermSet32 = 0x84000089,
MemPermSet64 = 0xc4000089,
ConsoleLog32 = 0x8400008a,
ConsoleLog64 = 0xc400008a,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Interface {
Error {
target_info: u32,
error_code: Error,
},
Success {
target_info: u32,
result_regs: [u64; 6],
is_32bit: bool,
},
Interrupt {
endpoint_id: u32,
interrupt_id: u32,
},
Version {
input_version: u32,
},
VersionOut {
output_version: u32,
},
Features {
feat_id: u32,
input_properties: u32,
},
RxAcquire {
vm_id: u32,
},
RxRelease {
vm_id: u32,
},
RxTxMap {
tx_addr: u64,
rx_addr: u64,
page_cnt: u32,
is_32bit: bool,
},
RxTxUnmap {
id: u32,
},
PartitionInfoGet {
uuid: Uuid,
flags: u32,
},
IdGet,
SpmIdGet,
MsgWait,
Yield,
Run {
target_info: u32,
},
NormalWorldResume,
MsgSend2 {
sender_vm_id: u32,
flags: u32,
},
MsgSendDirectReq {
src_id: u16,
dst_id: u16,
flags: u32,
args: [u64; 5],
is_32bit: bool,
},
MsgSendDirectResp {
src_id: u16,
dst_id: u16,
flags: u32,
args: [u64; 5],
is_32bit: bool,
},
MemDonate {
total_len: u32,
frag_len: u32,
address: u64,
page_cnt: u32,
is_32bit: bool,
},
MemLend {
total_len: u32,
frag_len: u32,
address: u64,
page_cnt: u32,
is_32bit: bool,
},
MemShare {
total_len: u32,
frag_len: u32,
address: u64,
page_cnt: u32,
is_32bit: bool,
},
MemRetrieveReq {
total_len: u32,
frag_len: u32,
address: u64,
page_cnt: u32,
is_32bit: bool,
},
MemRetrieveResp {
total_len: u32,
frag_len: u32,
},
MemRelinquish,
MemReclaim {
handle: memory_management::Handle,
flags: u32,
},
MemPermGet {
base_addr: u64,
is_32bit: bool,
},
MemPermSet {
base_addr: u64,
page_cnt: u32,
mem_perm: u32,
is_32bit: bool,
},
ConsoleLog {
char_cnt: u32,
char_lists: [u64; 6],
is_32bit: bool,
},
}
impl TryFrom<[u64; 8]> for Interface {
type Error = UnrecognisedFunctionIdError;
fn try_from(regs: [u64; 8]) -> Result<Self, UnrecognisedFunctionIdError> {
let fid = FuncId::try_from(regs[0] as u32)?;
let msg = match fid {
FuncId::Error => Self::Error {
target_info: regs[1] as u32,
error_code: Error::try_from(regs[2] as i32).unwrap(),
},
FuncId::Success32 | FuncId::Success64 => {
let target_info = regs[1] as u32;
let mut result_regs = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
let mut is_32bit = false;
if fid == FuncId::Success32 {
result_regs[0] &= u32::MAX as u64;
result_regs[1] &= u32::MAX as u64;
result_regs[2] &= u32::MAX as u64;
result_regs[3] &= u32::MAX as u64;
result_regs[4] &= u32::MAX as u64;
result_regs[5] &= u32::MAX as u64;
is_32bit = true;
}
Self::Success {
target_info,
result_regs,
is_32bit,
}
}
FuncId::Interrupt => Self::Interrupt {
endpoint_id: regs[1] as u32,
interrupt_id: regs[2] as u32,
},
FuncId::Version => Self::Version {
input_version: regs[1] as u32,
},
FuncId::Features => Self::Features {
feat_id: regs[1] as u32,
input_properties: regs[2] as u32,
},
FuncId::RxAcquire => Self::RxAcquire {
vm_id: regs[1] as u32,
},
FuncId::RxRelease => Self::RxRelease {
vm_id: regs[1] as u32,
},
FuncId::RxTxMap32 | FuncId::RxTxMap64 => {
let mut tx_addr = regs[1];
let mut rx_addr = regs[2];
let page_cnt = regs[3] as u32;
let mut is_32bit = false;
if fid == FuncId::RxTxMap32 {
tx_addr &= u32::MAX as u64;
rx_addr &= u32::MAX as u64;
is_32bit = true;
}
Self::RxTxMap {
tx_addr,
rx_addr,
page_cnt,
is_32bit,
}
}
FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u32 },
FuncId::PartitionInfoGet => {
let uuid_words = [
regs[1] as u32,
regs[2] as u32,
regs[3] as u32,
regs[4] as u32,
];
let mut bytes: [u8; 16] = [0; 16];
for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
bytes[i] = b;
}
Self::PartitionInfoGet {
uuid: Uuid::from_bytes(bytes),
flags: regs[5] as u32,
}
}
FuncId::IdGet => Self::IdGet,
FuncId::SpmIdGet => Self::SpmIdGet,
FuncId::MsgWait => Self::MsgWait,
FuncId::Yield => Self::Yield,
FuncId::Run => Self::Run {
target_info: regs[1] as u32,
},
FuncId::NormalWorldResume => Self::NormalWorldResume,
FuncId::MsgSend2 => Self::MsgSend2 {
sender_vm_id: regs[1] as u32,
flags: regs[2] as u32,
},
FuncId::MsgSendDirectReq32 | FuncId::MsgSendDirectReq64 => {
let src_id = (regs[1] >> 16) as u16;
let dst_id = regs[1] as u16;
let flags = regs[2] as u32;
let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
let mut is_32bit = false;
if fid == FuncId::MsgSendDirectReq32 {
args[0] &= u32::MAX as u64;
args[1] &= u32::MAX as u64;
args[2] &= u32::MAX as u64;
args[3] &= u32::MAX as u64;
args[4] &= u32::MAX as u64;
is_32bit = true;
}
Self::MsgSendDirectReq {
src_id,
dst_id,
flags,
args,
is_32bit,
}
}
FuncId::MsgSendDirectResp32 | FuncId::MsgSendDirectResp64 => {
let src_id = (regs[1] >> 16) as u16;
let dst_id = regs[1] as u16;
let flags = regs[2] as u32;
let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
let mut is_32bit = false;
if fid == FuncId::MsgSendDirectResp32 {
args[0] &= u32::MAX as u64;
args[1] &= u32::MAX as u64;
args[2] &= u32::MAX as u64;
args[3] &= u32::MAX as u64;
args[4] &= u32::MAX as u64;
is_32bit = true;
}
Self::MsgSendDirectResp {
src_id,
dst_id,
flags,
args,
is_32bit,
}
}
FuncId::MemDonate32 | FuncId::MemDonate64 => {
let total_len = regs[1] as u32;
let frag_len = regs[2] as u32;
let mut address = regs[3];
let page_cnt = regs[4] as u32;
let mut is_32bit = false;
if fid == FuncId::MemDonate32 {
address &= u32::MAX as u64;
is_32bit = true;
}
Self::MemDonate {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
}
}
FuncId::MemLend32 | FuncId::MemLend64 => {
let total_len = regs[1] as u32;
let frag_len = regs[2] as u32;
let mut address = regs[3];
let page_cnt = regs[4] as u32;
let mut is_32bit = false;
if fid == FuncId::MemLend32 {
address &= u32::MAX as u64;
is_32bit = true;
}
Self::MemLend {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
}
}
FuncId::MemShare32 | FuncId::MemShare64 => {
let total_len = regs[1] as u32;
let frag_len = regs[2] as u32;
let mut address = regs[3];
let page_cnt = regs[4] as u32;
let mut is_32bit = false;
if fid == FuncId::MemShare32 {
address &= u32::MAX as u64;
is_32bit = true;
}
Self::MemShare {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
}
}
FuncId::MemRetrieveReq32 | FuncId::MemRetrieveReq64 => {
let total_len = regs[1] as u32;
let frag_len = regs[2] as u32;
let mut address = regs[3];
let page_cnt = regs[4] as u32;
let mut is_32bit = false;
if fid == FuncId::MemRetrieveReq32 {
address &= u32::MAX as u64;
is_32bit = true;
}
Self::MemRetrieveReq {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
}
}
FuncId::MemRetrieveResp => Self::MemRetrieveResp {
total_len: regs[1] as u32,
frag_len: regs[2] as u32,
},
FuncId::MemRelinquish => Self::MemRelinquish,
FuncId::MemReclaim => Self::MemReclaim {
handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
flags: regs[3] as u32,
},
FuncId::MemPermGet32 | FuncId::MemPermGet64 => {
let mut base_addr = regs[1];
let mut is_32bit = false;
if fid == FuncId::MemPermGet32 {
base_addr &= u32::MAX as u64;
is_32bit = true;
}
Self::MemPermGet {
base_addr,
is_32bit,
}
}
FuncId::MemPermSet32 | FuncId::MemPermSet64 => {
let mut base_addr = regs[1];
let page_cnt = regs[2] as u32;
let mem_perm = regs[3] as u32;
let mut is_32bit = false;
if fid == FuncId::MemPermSet32 {
base_addr &= u32::MAX as u64;
is_32bit = true;
}
Self::MemPermSet {
base_addr,
page_cnt,
mem_perm,
is_32bit,
}
}
FuncId::ConsoleLog32 | FuncId::ConsoleLog64 => {
let char_cnt = regs[1] as u32;
let mut char_lists = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
let mut is_32bit = false;
if fid == FuncId::ConsoleLog32 {
char_lists[0] &= u32::MAX as u64;
char_lists[1] &= u32::MAX as u64;
char_lists[2] &= u32::MAX as u64;
char_lists[3] &= u32::MAX as u64;
char_lists[4] &= u32::MAX as u64;
char_lists[5] &= u32::MAX as u64;
is_32bit = true;
}
Self::ConsoleLog {
char_cnt,
char_lists,
is_32bit,
}
}
};
Ok(msg)
}
}
impl Interface {
/// Returns the function ID for the call, if it has one.
pub fn function_id(&self) -> Option<FuncId> {
match self {
Interface::Error { .. } => Some(FuncId::Error),
Interface::Success {
is_32bit: false, ..
} => Some(FuncId::Success64),
Interface::Success { is_32bit: true, .. } => Some(FuncId::Success32),
Interface::Interrupt { .. } => Some(FuncId::Interrupt),
Interface::Version { .. } => Some(FuncId::Version),
Interface::VersionOut { .. } => None,
Interface::Features { .. } => Some(FuncId::Features),
Interface::RxAcquire { .. } => Some(FuncId::RxAcquire),
Interface::RxRelease { .. } => Some(FuncId::RxRelease),
Interface::RxTxMap {
is_32bit: false, ..
} => Some(FuncId::RxTxMap64),
Interface::RxTxMap { is_32bit: true, .. } => Some(FuncId::RxTxMap32),
Interface::RxTxUnmap { .. } => Some(FuncId::RxTxUnmap),
Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
Interface::IdGet => Some(FuncId::IdGet),
Interface::SpmIdGet => Some(FuncId::SpmIdGet),
Interface::MsgWait => Some(FuncId::MsgWait),
Interface::Yield => Some(FuncId::Yield),
Interface::Run { .. } => Some(FuncId::Run),
Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
Interface::MsgSend2 { .. } => Some(FuncId::MsgSend2),
Interface::MsgSendDirectReq {
is_32bit: false, ..
} => Some(FuncId::MsgSendDirectReq64),
Interface::MsgSendDirectReq { is_32bit: true, .. } => Some(FuncId::MsgSendDirectReq32),
Interface::MsgSendDirectResp {
is_32bit: false, ..
} => Some(FuncId::MsgSendDirectResp64),
Interface::MsgSendDirectResp { is_32bit: true, .. } => {
Some(FuncId::MsgSendDirectResp32)
}
Interface::MemDonate {
is_32bit: false, ..
} => Some(FuncId::MemDonate64),
Interface::MemDonate { is_32bit: true, .. } => Some(FuncId::MemDonate32),
Interface::MemLend {
is_32bit: false, ..
} => Some(FuncId::MemLend64),
Interface::MemLend { is_32bit: true, .. } => Some(FuncId::MemLend32),
Interface::MemShare {
is_32bit: false, ..
} => Some(FuncId::MemShare64),
Interface::MemShare { is_32bit: true, .. } => Some(FuncId::MemShare32),
Interface::MemRetrieveReq {
is_32bit: false, ..
} => Some(FuncId::MemRetrieveReq64),
Interface::MemRetrieveReq { is_32bit: true, .. } => Some(FuncId::MemRetrieveReq32),
Interface::MemRetrieveResp { .. } => Some(FuncId::MemRetrieveResp),
Interface::MemRelinquish => Some(FuncId::MemRelinquish),
Interface::MemReclaim { .. } => Some(FuncId::MemReclaim),
Interface::MemPermGet {
is_32bit: false, ..
} => Some(FuncId::MemPermGet64),
Interface::MemPermGet { is_32bit: true, .. } => Some(FuncId::MemPermGet32),
Interface::MemPermSet {
is_32bit: false, ..
} => Some(FuncId::MemPermSet64),
Interface::MemPermSet { is_32bit: true, .. } => Some(FuncId::MemPermSet32),
Interface::ConsoleLog {
is_32bit: false, ..
} => Some(FuncId::ConsoleLog64),
Interface::ConsoleLog { is_32bit: true, .. } => Some(FuncId::ConsoleLog32),
}
}
/// Returns true if this is a 32-bit call, or false if it is a 64-bit call.
pub fn is_32bit(&self) -> bool {
match self {
Interface::Error { .. }
| Interface::Interrupt { .. }
| Interface::Version { .. }
| Interface::VersionOut { .. }
| Interface::Features { .. }
| Interface::RxAcquire { .. }
| Interface::RxRelease { .. }
| Interface::RxTxUnmap { .. }
| Interface::PartitionInfoGet { .. }
| Interface::IdGet
| Interface::SpmIdGet
| Interface::MsgWait
| Interface::Yield
| Interface::Run { .. }
| Interface::NormalWorldResume
| Interface::MsgSend2 { .. }
| Interface::MemRetrieveResp { .. }
| Interface::MemRelinquish
| Interface::MemReclaim { .. } => true,
Interface::Success { is_32bit, .. }
| Interface::RxTxMap { is_32bit, .. }
| Interface::MsgSendDirectReq { is_32bit, .. }
| Interface::MsgSendDirectResp { is_32bit, .. }
| Interface::MemDonate { is_32bit, .. }
| Interface::MemLend { is_32bit, .. }
| Interface::MemShare { is_32bit, .. }
| Interface::MemRetrieveReq { is_32bit, .. }
| Interface::MemPermGet { is_32bit, .. }
| Interface::MemPermSet { is_32bit, .. }
| Interface::ConsoleLog { is_32bit, .. } => *is_32bit,
}
}
pub fn copy_to_array(&self, a: &mut [u64; 8]) {
a.fill(0);
if let Some(function_id) = self.function_id() {
a[0] = function_id as u64;
}
match *self {
Interface::Error {
target_info,
error_code,
} => {
a[1] = target_info as u64;
a[2] = error_code as u32 as u64;
}
Interface::Success {
target_info,
result_regs,
is_32bit,
} => {
a[1] = target_info as u64;
if is_32bit {
a[2] = result_regs[0] & u32::MAX as u64;
a[3] = result_regs[1] & u32::MAX as u64;
a[4] = result_regs[2] & u32::MAX as u64;
a[5] = result_regs[3] & u32::MAX as u64;
a[6] = result_regs[4] & u32::MAX as u64;
a[7] = result_regs[5] & u32::MAX as u64;
} else {
a[2] = result_regs[0];
a[3] = result_regs[1];
a[4] = result_regs[2];
a[5] = result_regs[3];
a[6] = result_regs[4];
a[7] = result_regs[5];
}
}
Interface::Interrupt {
endpoint_id,
interrupt_id,
} => {
a[1] = endpoint_id as u64;
a[2] = interrupt_id as u64;
}
Interface::Version { input_version } => {
a[1] = input_version as u64;
}
Interface::VersionOut { output_version } => {
a[0] = output_version as u64;
}
Interface::Features {
feat_id,
input_properties,
} => {
a[1] = feat_id as u64;
a[2] = input_properties as u64;
}
Interface::RxAcquire { vm_id } => {
a[1] = vm_id as u64;
}
Interface::RxRelease { vm_id } => {
a[1] = vm_id as u64;
}
Interface::RxTxMap {
tx_addr,
rx_addr,
page_cnt,
is_32bit,
} => {
a[3] = page_cnt as u64;
if is_32bit {
a[1] = tx_addr & u32::MAX as u64;
a[2] = rx_addr & u32::MAX as u64;
} else {
a[1] = tx_addr;
a[2] = rx_addr;
}
}
Interface::RxTxUnmap { id } => {
a[1] = id as u64;
}
Interface::PartitionInfoGet { uuid, flags } => {
let bytes = uuid.to_bytes_le();
a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as u64;
a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64;
a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as u64;
a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]) as u64;
a[5] = flags as u64;
}
Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
Interface::Run { target_info } => {
a[1] = target_info as u64;
}
Interface::NormalWorldResume => {}
Interface::MsgSend2 {
sender_vm_id,
flags,
} => {
a[1] = sender_vm_id as u64;
a[2] = flags as u64;
}
Interface::MsgSendDirectReq {
src_id,
dst_id,
flags,
args,
is_32bit,
} => {
a[1] = (src_id as u64) << 16 | dst_id as u64;
a[2] = flags as u64;
if is_32bit {
a[3] = args[0] & u32::MAX as u64;
a[4] = args[1] & u32::MAX as u64;
a[5] = args[2] & u32::MAX as u64;
a[6] = args[3] & u32::MAX as u64;
a[7] = args[4] & u32::MAX as u64;
} else {
a[3] = args[0];
a[4] = args[1];
a[5] = args[2];
a[6] = args[3];
a[7] = args[4];
}
}
Interface::MsgSendDirectResp {
src_id,
dst_id,
flags,
args,
is_32bit,
} => {
a[1] = (src_id as u64) << 16 | dst_id as u64;
a[2] = flags as u64;
if is_32bit {
a[3] = args[0] & u32::MAX as u64;
a[4] = args[1] & u32::MAX as u64;
a[5] = args[2] & u32::MAX as u64;
a[6] = args[3] & u32::MAX as u64;
a[7] = args[4] & u32::MAX as u64;
} else {
a[3] = args[0];
a[4] = args[1];
a[5] = args[2];
a[6] = args[3];
a[7] = args[4];
}
}
Interface::MemDonate {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
} => {
a[1] = total_len as u64;
a[2] = frag_len as u64;
a[4] = page_cnt as u64;
if is_32bit {
a[3] = address & u32::MAX as u64;
} else {
a[3] = address;
}
}
Interface::MemLend {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
} => {
a[1] = total_len as u64;
a[2] = frag_len as u64;
a[4] = page_cnt as u64;
if is_32bit {
a[3] = address & u32::MAX as u64;
} else {
a[3] = address;
}
}
Interface::MemShare {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
} => {
a[1] = total_len as u64;
a[2] = frag_len as u64;
a[4] = page_cnt as u64;
if is_32bit {
a[3] = address & u32::MAX as u64;
} else {
a[3] = address;
}
}
Interface::MemRetrieveReq {
total_len,
frag_len,
address,
page_cnt,
is_32bit,
} => {
a[1] = total_len as u64;
a[2] = frag_len as u64;
a[4] = page_cnt as u64;
if is_32bit {
a[3] = address & u32::MAX as u64;
} else {
a[3] = address;
}
}
Interface::MemRetrieveResp {
total_len,
frag_len,
} => {
a[1] = total_len as u64;
a[2] = frag_len as u64;
}
Interface::MemRelinquish => {}
Interface::MemReclaim { handle, flags } => {
let handle_regs: [u32; 2] = handle.into();
a[1] = handle_regs[0] as u64;
a[2] = handle_regs[1] as u64;
a[3] = flags as u64;
}
Interface::MemPermGet {
base_addr,
is_32bit,
} => {
if is_32bit {
a[1] = base_addr & u32::MAX as u64;
} else {
a[1] = base_addr;
}
}
Interface::MemPermSet {
base_addr,
page_cnt,
mem_perm,
is_32bit,
} => {
a[2] = page_cnt as u64;
a[3] = mem_perm as u64;
if is_32bit {
a[1] = base_addr & u32::MAX as u64;
} else {
a[1] = base_addr;
}
}
Interface::ConsoleLog {
char_cnt,
char_lists,
is_32bit,
} => {
a[1] = char_cnt as u64;
if is_32bit {
a[2] = char_lists[0] & u32::MAX as u64;
a[3] = char_lists[1] & u32::MAX as u64;
a[4] = char_lists[2] & u32::MAX as u64;
a[5] = char_lists[3] & u32::MAX as u64;
a[6] = char_lists[4] & u32::MAX as u64;
a[7] = char_lists[5] & u32::MAX as u64;
} else {
a[2] = char_lists[0];
a[3] = char_lists[1];
a[4] = char_lists[2];
a[5] = char_lists[3];
a[6] = char_lists[4];
a[7] = char_lists[5];
}
}
}
}
/// Helper function to create an FFA_SUCCESS interface without any arguments
pub fn success32_noargs() -> Self {
Self::Success {
target_info: 0,
result_regs: [0, 0, 0, 0, 0, 0],
is_32bit: true,
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Version(pub u16, pub u16);
impl From<u32> for Version {
fn from(val: u32) -> Self {
Self((val >> 16) as u16, val as u16)
}
}
impl From<Version> for u32 {
fn from(v: Version) -> Self {
(v.0 as u32) << 16 | v.1 as u32
}
}
impl Display for Version {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}.{}", self.0, self.1)
}
}
impl Debug for Version {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
pub const CONSOLE_LOG_32_MAX_MSG_LEN: usize = 24;
pub const CONSOLE_LOG_64_MAX_MSG_LEN: usize = 48;
pub fn parse_console_log(
char_cnt: u32,
char_lists: &[u64; 6],
is_32bit: bool,
log_bytes: &mut [u8],
) -> Result<(), Error> {
const CHAR_COUNT_MASK: u32 = 0xff;
let char_count = (char_cnt & CHAR_COUNT_MASK) as usize;
let (max_length, reg_size) = if is_32bit {
(CONSOLE_LOG_32_MAX_MSG_LEN, 4)
} else {
(CONSOLE_LOG_64_MAX_MSG_LEN, 8)
};
if char_count < 1 || char_count > max_length {
return Err(Error::InvalidParameters);
}
for i in 0..=5 {
log_bytes[reg_size * i..reg_size * (i + 1)]
.copy_from_slice(&char_lists[i].to_le_bytes()[0..reg_size]);
}
Ok(())
}