Add Framework Message support to Direct Messages
Change-Id: I031a30a11f25fbae81845f1c5be243e2b70fec1b
Signed-off-by: Tomás González <tomasagustin.gonzalezorlando@arm.com>
diff --git a/src/lib.rs b/src/lib.rs
index fda75d4..ae66d12 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,6 +31,16 @@
UnrecognisedFeatureId(u8),
#[error("Unrecognised FF-A error code {0}")]
UnrecognisedErrorCode(i32),
+ #[error("Unrecognised FF-A Framework Message {0}")]
+ UnrecognisedFwkMsg(u32),
+ #[error("Unrecognised FF-A Msg Wait Flag {0}")]
+ UnrecognisedMsgWaitFlag(u32),
+ #[error("Unrecognised VM availability status {0}")]
+ UnrecognisedVmAvailabilityStatus(i32),
+ #[error("Unrecognised FF-A Warm Boot Type {0}")]
+ UnrecognisedWarmBootType(u32),
+ #[error("Invalid version {0}")]
+ InvalidVersion(u32),
}
impl From<Error> for FfaError {
@@ -39,7 +49,12 @@
Error::UnrecognisedFunctionId(_) | Error::UnrecognisedFeatureId(_) => {
Self::NotSupported
}
- Error::UnrecognisedErrorCode(_) => Self::InvalidParameters,
+ Error::UnrecognisedErrorCode(_)
+ | Error::UnrecognisedFwkMsg(_)
+ | Error::InvalidVersion(_)
+ | Error::UnrecognisedMsgWaitFlag(_)
+ | Error::UnrecognisedVmAvailabilityStatus(_)
+ | Error::UnrecognisedWarmBootType(_) => Self::InvalidParameters,
}
}
}
@@ -267,11 +282,123 @@
Addr64 { rx: u64, tx: u64 },
}
+/// Composite type for capturing success and error return codes for the VM availability messages.
+///
+/// Error codes are handled by the `FfaError` type. Having a separate type for errors helps using
+/// `Result<(), FfaError>`. If a single type would include both success and error values,
+/// then `Err(FfaError::Success)` would be incomprehensible.
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
+pub enum VmAvailabilityStatus {
+ Success,
+ Error(FfaError),
+}
+
+impl TryFrom<i32> for VmAvailabilityStatus {
+ type Error = Error;
+ fn try_from(value: i32) -> Result<Self, <Self as TryFrom<i32>>::Error> {
+ Ok(match value {
+ 0 => Self::Success,
+ error_code => Self::Error(FfaError::try_from(error_code)?),
+ })
+ }
+}
+
+impl From<VmAvailabilityStatus> for i32 {
+ fn from(value: VmAvailabilityStatus) -> Self {
+ match value {
+ VmAvailabilityStatus::Success => 0,
+ VmAvailabilityStatus::Error(error_code) => error_code.into(),
+ }
+ }
+}
+
+/// Arguments for the Power Warm Boot `FFA_MSG_SEND_DIRECT_REQ` interface.
+#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
+#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedWarmBootType))]
+#[repr(u32)]
+pub enum WarmBootType {
+ ExitFromSuspend = 0,
+ ExitFromLowPower = 1,
+}
+
/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum DirectMsgArgs {
Args32([u32; 5]),
Args64([u64; 5]),
+ /// Message for forwarding FFA_VERSION call from Normal world to the SPMC
+ VersionReq {
+ version: Version,
+ },
+ /// Response message to forwarded FFA_VERSION call from the Normal world
+ /// Contains the version returned by the SPMC or None
+ VersionResp {
+ version: Option<Version>,
+ },
+ /// Message for a power management operation initiated by a PSCI function
+ PowerPsciReq32 {
+ function_id: u32,
+ // params[i]: Input parameter in w[i] in PSCI function invocation at EL3.
+ params: [u32; 3],
+ },
+ /// Message for a power management operation initiated by a PSCI function
+ PowerPsciReq64 {
+ function_id: u32,
+ // params[i]: Input parameter in x[i] in PSCI function invocation at EL3.
+ params: [u64; 3],
+ },
+ /// Message for a warm boot
+ PowerWarmBootReq {
+ boot_type: WarmBootType,
+ },
+ /// Response message to indicate return status of the last power management request message
+ /// Return error code SUCCESS or DENIED as defined in PSCI spec. Caller is left to do the
+ /// parsing of the return status.
+ PowerPsciResp {
+ // TODO: Use arm-psci crate's return status here.
+ psci_status: i32,
+ },
+ /// Message to signal creation of a VM
+ VmCreated {
+ // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
+ // information associated with the created VM.
+ // The invalid memory region handle must be specified by the Hypervisor if this field is not
+ // used.
+ handle: memory_management::Handle,
+ vm_id: u16,
+ },
+ /// Message to acknowledge creation of a VM
+ VmCreatedAck {
+ sp_status: VmAvailabilityStatus,
+ },
+ /// Message to signal destruction of a VM
+ VmDestructed {
+ // Globally unique Handle to identify a memory region that contains IMPLEMENTATION DEFINED
+ // information associated with the created VM.
+ // The invalid memory region handle must be specified by the Hypervisor if this field is not
+ // used.
+ handle: memory_management::Handle,
+ vm_id: u16,
+ },
+ /// Message to acknowledge destruction of a VM
+ VmDestructedAck {
+ sp_status: VmAvailabilityStatus,
+ },
+}
+
+impl DirectMsgArgs {
+ // Flags for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}` interfaces.
+
+ const FWK_MSG_BITS: u32 = 1 << 31;
+ const VERSION_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1000;
+ const VERSION_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b1001;
+ const POWER_PSCI_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS;
+ const POWER_WARM_BOOT_REQ: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0001;
+ const POWER_PSCI_RESP: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0010;
+ const VM_CREATED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0100;
+ const VM_CREATED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0101;
+ const VM_DESTRUCTED: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0110;
+ const VM_DESTRUCTED_ACK: u32 = DirectMsgArgs::FWK_MSG_BITS | 0b0111;
}
/// Arguments for the `FFA_MSG_SEND_DIRECT_{REQ,RESP}2` interfaces.
@@ -363,13 +490,11 @@
MsgSendDirectReq {
src_id: u16,
dst_id: u16,
- flags: u32,
args: DirectMsgArgs,
},
MsgSendDirectResp {
src_id: u16,
dst_id: u16,
- flags: u32,
args: DirectMsgArgs,
},
MsgSendDirectReq2 {
@@ -462,10 +587,22 @@
Interface::MsgSendDirectReq { args, .. } => match args {
DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectReq32),
DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectReq64),
+ DirectMsgArgs::VersionReq { .. } => Some(FuncId::MsgSendDirectReq32),
+ DirectMsgArgs::PowerPsciReq32 { .. } => Some(FuncId::MsgSendDirectReq32),
+ DirectMsgArgs::PowerPsciReq64 { .. } => Some(FuncId::MsgSendDirectReq64),
+ DirectMsgArgs::PowerWarmBootReq { .. } => Some(FuncId::MsgSendDirectReq32),
+ DirectMsgArgs::VmCreated { .. } => Some(FuncId::MsgSendDirectReq32),
+ DirectMsgArgs::VmDestructed { .. } => Some(FuncId::MsgSendDirectReq32),
+ _ => None,
},
Interface::MsgSendDirectResp { args, .. } => match args {
DirectMsgArgs::Args32(_) => Some(FuncId::MsgSendDirectResp32),
DirectMsgArgs::Args64(_) => Some(FuncId::MsgSendDirectResp64),
+ DirectMsgArgs::VersionResp { .. } => Some(FuncId::MsgSendDirectResp32),
+ DirectMsgArgs::PowerPsciResp { .. } => Some(FuncId::MsgSendDirectResp32),
+ DirectMsgArgs::VmCreatedAck { .. } => Some(FuncId::MsgSendDirectResp32),
+ DirectMsgArgs::VmDestructedAck { .. } => Some(FuncId::MsgSendDirectResp32),
+ _ => None,
},
Interface::MsgSendDirectReq2 { .. } => Some(FuncId::MsgSendDirectReq64_2),
Interface::MsgSendDirectResp2 { .. } => Some(FuncId::MsgSendDirectResp64_2),
@@ -636,38 +773,102 @@
FuncId::MsgSendDirectReq32 => Self::MsgSendDirectReq {
src_id: (regs[1] >> 16) as u16,
dst_id: regs[1] as u16,
- flags: regs[2] as u32,
- args: DirectMsgArgs::Args32([
- regs[3] as u32,
- regs[4] as u32,
- regs[5] as u32,
- regs[6] as u32,
- regs[7] as u32,
- ]),
+ args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
+ match regs[2] as u32 {
+ DirectMsgArgs::VERSION_REQ => DirectMsgArgs::VersionReq {
+ version: Version::try_from(regs[3] as u32)?,
+ },
+ DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq32 {
+ function_id: regs[3] as u32,
+ params: [regs[4] as u32, regs[5] as u32, regs[6] as u32],
+ },
+ DirectMsgArgs::POWER_WARM_BOOT_REQ => DirectMsgArgs::PowerWarmBootReq {
+ boot_type: WarmBootType::try_from(regs[3] as u32)?,
+ },
+ DirectMsgArgs::VM_CREATED => DirectMsgArgs::VmCreated {
+ handle: memory_management::Handle::from([
+ regs[3] as u32,
+ regs[4] as u32,
+ ]),
+ vm_id: regs[5] as u16,
+ },
+ DirectMsgArgs::VM_DESTRUCTED => DirectMsgArgs::VmDestructed {
+ handle: memory_management::Handle::from([
+ regs[3] as u32,
+ regs[4] as u32,
+ ]),
+ vm_id: regs[5] as u16,
+ },
+ _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
+ }
+ } else {
+ DirectMsgArgs::Args32([
+ regs[3] as u32,
+ regs[4] as u32,
+ regs[5] as u32,
+ regs[6] as u32,
+ regs[7] as u32,
+ ])
+ },
},
FuncId::MsgSendDirectReq64 => Self::MsgSendDirectReq {
src_id: (regs[1] >> 16) as u16,
dst_id: regs[1] as u16,
- flags: regs[2] as u32,
- args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
+ args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
+ match regs[2] as u32 {
+ DirectMsgArgs::POWER_PSCI_REQ => DirectMsgArgs::PowerPsciReq64 {
+ function_id: regs[3] as u32,
+ params: [regs[4], regs[5], regs[6]],
+ },
+ _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
+ }
+ } else {
+ DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
+ },
},
FuncId::MsgSendDirectResp32 => Self::MsgSendDirectResp {
src_id: (regs[1] >> 16) as u16,
dst_id: regs[1] as u16,
- flags: regs[2] as u32,
- args: DirectMsgArgs::Args32([
- regs[3] as u32,
- regs[4] as u32,
- regs[5] as u32,
- regs[6] as u32,
- regs[7] as u32,
- ]),
+ args: if (regs[2] as u32 & DirectMsgArgs::FWK_MSG_BITS) != 0 {
+ match regs[2] as u32 {
+ DirectMsgArgs::VERSION_RESP => {
+ if regs[3] as i32 == FfaError::NotSupported.into() {
+ DirectMsgArgs::VersionResp { version: None }
+ } else {
+ DirectMsgArgs::VersionResp {
+ version: Some(Version::try_from(regs[3] as u32)?),
+ }
+ }
+ }
+ DirectMsgArgs::POWER_PSCI_RESP => DirectMsgArgs::PowerPsciResp {
+ psci_status: regs[3] as i32,
+ },
+ DirectMsgArgs::VM_CREATED_ACK => DirectMsgArgs::VmCreatedAck {
+ sp_status: (regs[3] as i32).try_into()?,
+ },
+ DirectMsgArgs::VM_DESTRUCTED_ACK => DirectMsgArgs::VmDestructedAck {
+ sp_status: (regs[3] as i32).try_into()?,
+ },
+ _ => return Err(Error::UnrecognisedFwkMsg(regs[2] as u32)),
+ }
+ } else {
+ DirectMsgArgs::Args32([
+ regs[3] as u32,
+ regs[4] as u32,
+ regs[5] as u32,
+ regs[6] as u32,
+ regs[7] as u32,
+ ])
+ },
},
FuncId::MsgSendDirectResp64 => Self::MsgSendDirectResp {
src_id: (regs[1] >> 16) as u16,
dst_id: regs[1] as u16,
- flags: regs[2] as u32,
- args: DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]]),
+ args: if (regs[2] & DirectMsgArgs::FWK_MSG_BITS as u64) != 0 {
+ return Err(Error::UnrecognisedFwkMsg(regs[2] as u32));
+ } else {
+ DirectMsgArgs::Args64([regs[3], regs[4], regs[5], regs[6], regs[7]])
+ },
},
FuncId::MemDonate32 => Self::MemDonate {
total_len: regs[1] as u32,
@@ -987,11 +1188,9 @@
Interface::MsgSendDirectReq {
src_id,
dst_id,
- flags,
args,
} => {
a[1] = ((src_id as u64) << 16) | dst_id as u64;
- a[2] = flags.into();
match args {
DirectMsgArgs::Args32(args) => {
a[3] = args[0].into();
@@ -1007,16 +1206,57 @@
a[6] = args[3];
a[7] = args[4];
}
+ DirectMsgArgs::VersionReq { version } => {
+ a[2] = DirectMsgArgs::VERSION_REQ.into();
+ a[3] = u32::from(version).into();
+ }
+ DirectMsgArgs::PowerPsciReq32 {
+ function_id,
+ params,
+ } => {
+ a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
+ a[3] = function_id.into();
+ a[4] = params[0].into();
+ a[5] = params[1].into();
+ a[6] = params[2].into();
+ }
+ DirectMsgArgs::PowerPsciReq64 {
+ function_id,
+ params,
+ } => {
+ a[2] = DirectMsgArgs::POWER_PSCI_REQ.into();
+ a[3] = function_id.into();
+ a[4] = params[0];
+ a[5] = params[1];
+ a[6] = params[2];
+ }
+ DirectMsgArgs::PowerWarmBootReq { boot_type } => {
+ a[2] = DirectMsgArgs::POWER_WARM_BOOT_REQ.into();
+ a[3] = u32::from(boot_type).into();
+ }
+ DirectMsgArgs::VmCreated { handle, vm_id } => {
+ a[2] = DirectMsgArgs::VM_CREATED.into();
+ let handle_regs: [u32; 2] = handle.into();
+ a[3] = handle_regs[0].into();
+ a[4] = handle_regs[1].into();
+ a[5] = vm_id.into();
+ }
+ DirectMsgArgs::VmDestructed { handle, vm_id } => {
+ a[2] = DirectMsgArgs::VM_DESTRUCTED.into();
+ let handle_regs: [u32; 2] = handle.into();
+ a[3] = handle_regs[0].into();
+ a[4] = handle_regs[1].into();
+ a[5] = vm_id.into();
+ }
+ _ => panic!("Malformed MsgSendDirectReq interface"),
}
}
Interface::MsgSendDirectResp {
src_id,
dst_id,
- flags,
args,
} => {
a[1] = ((src_id as u64) << 16) | dst_id as u64;
- a[2] = flags.into();
match args {
DirectMsgArgs::Args32(args) => {
a[3] = args[0].into();
@@ -1032,6 +1272,26 @@
a[6] = args[3];
a[7] = args[4];
}
+ DirectMsgArgs::VersionResp { version } => {
+ a[2] = DirectMsgArgs::VERSION_RESP.into();
+ match version {
+ None => a[3] = i32::from(FfaError::NotSupported) as u64,
+ Some(ver) => a[3] = u32::from(ver).into(),
+ }
+ }
+ DirectMsgArgs::PowerPsciResp { psci_status } => {
+ a[2] = DirectMsgArgs::POWER_PSCI_RESP.into();
+ a[3] = psci_status as u64;
+ }
+ DirectMsgArgs::VmCreatedAck { sp_status } => {
+ a[2] = DirectMsgArgs::VM_CREATED_ACK.into();
+ a[4] = i32::from(sp_status) as u64;
+ }
+ DirectMsgArgs::VmDestructedAck { sp_status } => {
+ a[2] = DirectMsgArgs::VM_DESTRUCTED_ACK.into();
+ a[3] = i32::from(sp_status) as u64;
+ }
+ _ => panic!("Malformed MsgSendDirectResp interface"),
}
}
Interface::MemDonate {