Add support for handling multiple FF-A versions
This is required because a single FF-A component (i.e. an SPMC) must be
able to support various FF-A versions at runtime. Also, implement some
of the new message types from FF-A v1.2 and add support for handling 18
registers instead of 8.
Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Change-Id: Ia46dc40204698265dc4ea9ed3731275baad94949
diff --git a/src/partition_info.rs b/src/partition_info.rs
index 781f299..23e4c06 100644
--- a/src/partition_info.rs
+++ b/src/partition_info.rs
@@ -3,11 +3,21 @@
//! Implementation of FF-A partition discovery data structures.
-use crate::ffa_v1_1::partition_info_descriptor;
use thiserror::Error;
use uuid::Uuid;
use zerocopy::{FromBytes, IntoBytes};
+// This module uses FF-A v1.1 types by default.
+// FF-A v1.2 specified some previously reserved bits in the partition info properties field, but
+// this doesn't change the descriptor format.
+use crate::{ffa_v1_1::partition_info_descriptor, Version};
+
+// Sanity check to catch if the descriptor format is changed.
+const _: () = assert!(
+ size_of::<crate::ffa_v1_1::partition_info_descriptor>()
+ == size_of::<crate::ffa_v1_2::partition_info_descriptor>()
+);
+
/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
/// with the `FFA_ERROR` interface.
#[derive(Debug, Error)]
@@ -55,6 +65,12 @@
pub support_direct_req_rec: bool,
/// The partition can send direct requests.
pub support_direct_req_send: bool,
+ /// The partition supports receipt of direct requests via the FFA_MSG_SEND_DIRECT_REQ2 ABI.
+ /// Added in FF-A v1.2
+ pub support_direct_req2_rec: Option<bool>,
+ /// The partition can send direct requests via the FFA_MSG_SEND_DIRECT_REQ2 ABI.
+ /// Added in FF-A v1.2
+ pub support_direct_req2_send: Option<bool>,
/// The partition can send and receive indirect messages.
pub support_indirect_msg: bool,
/// The partition supports receipt of notifications.
@@ -75,113 +91,134 @@
const SUBSCRIBE_VM_CREATED_SHIFT: usize = 6;
const SUBSCRIBE_VM_DESTROYED_SHIFT: usize = 7;
const IS_AARCH64_SHIFT: usize = 8;
+ const SUPPORT_DIRECT_REQ2_REC_SHIFT: usize = 9;
+ const SUPPORT_DIRECT_REQ2_SEND_SHIFT: usize = 10;
}
-struct PartPropWrapper(PartitionIdType, PartitionProperties);
+fn create_partition_properties(
+ version: Version,
+ id_type: PartitionIdType,
+ properties: PartitionProperties,
+) -> (u32, u16) {
+ let exec_ctx_count_or_proxy_id = match id_type {
+ PartitionIdType::PeEndpoint {
+ execution_ctx_count,
+ } => execution_ctx_count,
+ PartitionIdType::SepidIndep => 0,
+ PartitionIdType::SepidDep { proxy_endpoint_id } => proxy_endpoint_id,
+ PartitionIdType::Aux => 0,
+ };
-impl From<PartPropWrapper> for (u32, u16) {
- fn from(value: PartPropWrapper) -> Self {
- let exec_ctx_count_or_proxy_id = match value.0 {
- PartitionIdType::PeEndpoint {
- execution_ctx_count,
- } => execution_ctx_count,
- PartitionIdType::SepidIndep => 0,
- PartitionIdType::SepidDep { proxy_endpoint_id } => proxy_endpoint_id,
- PartitionIdType::Aux => 0,
- };
+ let mut prop_bits = match id_type {
+ PartitionIdType::PeEndpoint { .. } => {
+ let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT;
- let mut props = match value.0 {
- PartitionIdType::PeEndpoint { .. } => {
- let mut p = PartitionIdType::PE_ENDPOINT << PartitionIdType::SHIFT;
-
- if value.1.support_direct_req_rec {
- p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT;
- if value.1.subscribe_vm_created {
- // TODO: how to handle if ABI is invoked at NS phys instance?
- p |= 1 << PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT
- }
- if value.1.subscribe_vm_destroyed {
- // TODO: how to handle if ABI is invoked at NS phys instance?
- p |= 1 << PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT
- }
+ if properties.support_direct_req_rec {
+ p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT;
+ if properties.subscribe_vm_created {
+ // TODO: how to handle if ABI is invoked at NS phys instance?
+ p |= 1 << PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT
}
- if value.1.support_direct_req_send {
- p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT
+ if properties.subscribe_vm_destroyed {
+ // TODO: how to handle if ABI is invoked at NS phys instance?
+ p |= 1 << PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT
}
- if value.1.support_indirect_msg {
- p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT
- }
- if value.1.support_notif_rec {
- p |= 1 << PartitionProperties::SUPPORT_NOTIF_REC_SHIFT
- }
-
- p
}
- PartitionIdType::SepidIndep => PartitionIdType::SEPID_INDEP << PartitionIdType::SHIFT,
- PartitionIdType::SepidDep { .. } => {
- PartitionIdType::SEPID_DEP << PartitionIdType::SHIFT
- }
- PartitionIdType::Aux => PartitionIdType::AUX << PartitionIdType::SHIFT,
- };
- if value.1.is_aarch64 {
- props |= 1 << PartitionProperties::IS_AARCH64_SHIFT
+ if properties.support_direct_req_send {
+ p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT
+ }
+
+ // For v1.2 and later it's mandatory to specify these properties
+ if version >= Version(1, 2) {
+ if properties.support_direct_req2_rec.unwrap() {
+ p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ2_REC_SHIFT
+ }
+
+ if properties.support_direct_req2_send.unwrap() {
+ p |= 1 << PartitionProperties::SUPPORT_DIRECT_REQ2_SEND_SHIFT
+ }
+ }
+
+ if properties.support_indirect_msg {
+ p |= 1 << PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT
+ }
+
+ if properties.support_notif_rec {
+ p |= 1 << PartitionProperties::SUPPORT_NOTIF_REC_SHIFT
+ }
+
+ p
}
+ PartitionIdType::SepidIndep => PartitionIdType::SEPID_INDEP << PartitionIdType::SHIFT,
+ PartitionIdType::SepidDep { .. } => PartitionIdType::SEPID_DEP << PartitionIdType::SHIFT,
+ PartitionIdType::Aux => PartitionIdType::AUX << PartitionIdType::SHIFT,
+ };
- (props, exec_ctx_count_or_proxy_id)
+ if properties.is_aarch64 {
+ prop_bits |= 1 << PartitionProperties::IS_AARCH64_SHIFT
}
+
+ (prop_bits, exec_ctx_count_or_proxy_id)
}
-impl From<(u32, u16)> for PartPropWrapper {
- fn from(value: (u32, u16)) -> Self {
- let part_id_type = match (value.0 >> PartitionIdType::SHIFT) & PartitionIdType::MASK {
- PartitionIdType::PE_ENDPOINT => PartitionIdType::PeEndpoint {
- execution_ctx_count: value.1,
- },
- PartitionIdType::SEPID_INDEP => PartitionIdType::SepidIndep,
- PartitionIdType::SEPID_DEP => PartitionIdType::SepidDep {
- proxy_endpoint_id: value.1,
- },
- PartitionIdType::AUX => PartitionIdType::Aux,
- _ => panic!(), // The match is exhaustive for a 2-bit value
- };
+fn parse_partition_properties(
+ version: Version,
+ prop_bits: u32,
+ id_type: u16,
+) -> (PartitionIdType, PartitionProperties) {
+ let part_id_type = match (prop_bits >> PartitionIdType::SHIFT) & PartitionIdType::MASK {
+ PartitionIdType::PE_ENDPOINT => PartitionIdType::PeEndpoint {
+ execution_ctx_count: id_type,
+ },
+ PartitionIdType::SEPID_INDEP => PartitionIdType::SepidIndep,
+ PartitionIdType::SEPID_DEP => PartitionIdType::SepidDep {
+ proxy_endpoint_id: id_type,
+ },
+ PartitionIdType::AUX => PartitionIdType::Aux,
+ _ => panic!(), // The match is exhaustive for a 2-bit value
+ };
- let mut part_props = PartitionProperties::default();
+ let mut part_props = PartitionProperties::default();
- if (value.0 >> PartitionIdType::SHIFT) & PartitionIdType::MASK
- == PartitionIdType::PE_ENDPOINT
- {
- if (value.0 >> PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT) & 0b1 == 1 {
- part_props.support_direct_req_rec = true;
+ if matches!(part_id_type, PartitionIdType::PeEndpoint { .. }) {
+ if (prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ_REC_SHIFT) & 0b1 == 1 {
+ part_props.support_direct_req_rec = true;
- if (value.0 >> PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT) & 0b1 == 1 {
- part_props.subscribe_vm_created = true;
- }
-
- if (value.0 >> PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT) & 0b1 == 1 {
- part_props.subscribe_vm_destroyed = true;
- }
+ if (prop_bits >> PartitionProperties::SUBSCRIBE_VM_CREATED_SHIFT) & 0b1 == 1 {
+ part_props.subscribe_vm_created = true;
}
- if (value.0 >> PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT) & 0b1 == 1 {
- part_props.support_direct_req_send = true;
- }
-
- if (value.0 >> PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT) & 0b1 == 1 {
- part_props.support_indirect_msg = true;
- }
-
- if (value.0 >> PartitionProperties::SUPPORT_NOTIF_REC_SHIFT) & 0b1 == 1 {
- part_props.support_notif_rec = true;
+ if (prop_bits >> PartitionProperties::SUBSCRIBE_VM_DESTROYED_SHIFT) & 0b1 == 1 {
+ part_props.subscribe_vm_destroyed = true;
}
}
- if (value.0 >> PartitionProperties::IS_AARCH64_SHIFT) & 0b1 == 1 {
- part_props.is_aarch64 = true;
+ if (prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ_SEND_SHIFT) & 0b1 == 1 {
+ part_props.support_direct_req_send = true;
}
- PartPropWrapper(part_id_type, part_props)
+ if version >= Version(1, 2) {
+ part_props.support_direct_req2_rec =
+ Some((prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ2_REC_SHIFT) & 0b1 == 1);
+ part_props.support_direct_req2_send =
+ Some((prop_bits >> PartitionProperties::SUPPORT_DIRECT_REQ2_SEND_SHIFT) & 0b1 == 1);
+ }
+
+ if (prop_bits >> PartitionProperties::SUPPORT_INDIRECT_MSG_SHIFT) & 0b1 == 1 {
+ part_props.support_indirect_msg = true;
+ }
+
+ if (prop_bits >> PartitionProperties::SUPPORT_NOTIF_REC_SHIFT) & 0b1 == 1 {
+ part_props.support_notif_rec = true;
+ }
}
+
+ if (prop_bits >> PartitionProperties::IS_AARCH64_SHIFT) & 0b1 == 1 {
+ part_props.is_aarch64 = true;
+ }
+
+ (part_id_type, part_props)
}
/// Partition information descriptor, returned by the `FFA_PARTITION_INFO_GET` interface.
@@ -194,11 +231,13 @@
}
impl PartitionInfo {
- const DESC_SIZE: usize = size_of::<partition_info_descriptor>();
+ pub const DESC_SIZE: usize = size_of::<partition_info_descriptor>();
/// Serialize a list of partition information descriptors into a buffer. The `fill_uuid`
/// parameter controls whether the UUID field of the descriptor will be filled.
- pub fn pack(descriptors: &[PartitionInfo], buf: &mut [u8], fill_uuid: bool) {
+ pub fn pack(version: Version, descriptors: &[PartitionInfo], buf: &mut [u8], fill_uuid: bool) {
+ assert!((Version(1, 1)..=Version(1, 2)).contains(&version));
+
let mut offset = 0;
for desc in descriptors {
@@ -210,7 +249,7 @@
(
desc_raw.partition_props,
desc_raw.exec_ctx_count_or_proxy_id,
- ) = PartPropWrapper(desc.partition_id_type, desc.props).into();
+ ) = create_partition_properties(version, desc.partition_id_type, desc.props);
if fill_uuid {
desc_raw.uuid.copy_from_slice(desc.uuid.as_bytes());
@@ -224,6 +263,7 @@
/// Iterator of partition information descriptors.
pub struct PartitionInfoIterator<'a> {
+ version: Version,
buf: &'a [u8],
offset: usize,
count: usize,
@@ -231,7 +271,9 @@
impl<'a> PartitionInfoIterator<'a> {
/// Create an iterator of partition information descriptors from a buffer.
- pub fn new(buf: &'a [u8], count: usize) -> Result<Self, Error> {
+ pub fn new(version: Version, buf: &'a [u8], count: usize) -> Result<Self, Error> {
+ assert!((Version(1, 1)..=Version(1, 2)).contains(&version));
+
let Some(total_size) = count.checked_mul(PartitionInfo::DESC_SIZE) else {
return Err(Error::InvalidBufferSize);
};
@@ -241,6 +283,7 @@
}
Ok(Self {
+ version,
buf,
offset: 0,
count,
@@ -265,18 +308,19 @@
let partition_id = desc_raw.partition_id;
- let wrapper = PartPropWrapper::from((
+ let (partition_id_type, props) = parse_partition_properties(
+ self.version,
desc_raw.partition_props,
desc_raw.exec_ctx_count_or_proxy_id,
- ));
+ );
let uuid = Uuid::from_bytes(desc_raw.uuid);
let desc = PartitionInfo {
uuid,
partition_id,
- partition_id_type: wrapper.0,
- props: wrapper.1,
+ partition_id_type,
+ props,
};
return Some(Ok(desc));
@@ -309,6 +353,8 @@
subscribe_vm_created: true,
subscribe_vm_destroyed: true,
is_aarch64: true,
+ support_direct_req2_rec: Some(true),
+ support_direct_req2_send: Some(true),
},
};
@@ -324,13 +370,15 @@
subscribe_vm_created: false,
subscribe_vm_destroyed: false,
is_aarch64: true,
+ support_direct_req2_rec: None,
+ support_direct_req2_send: None,
},
};
let mut buf = [0u8; 0xff];
- PartitionInfo::pack(&[desc1, desc2], &mut buf, true);
+ PartitionInfo::pack(Version(1, 2), &[desc1, desc2], &mut buf, true);
- let mut descriptors = PartitionInfoIterator::new(&buf, 2).unwrap();
+ let mut descriptors = PartitionInfoIterator::new(Version(1, 2), &buf, 2).unwrap();
let desc1_check = descriptors.next().unwrap().unwrap();
let desc2_check = descriptors.next().unwrap().unwrap();