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/boot_info.rs b/src/boot_info.rs
index c9c45fb..9d902cf 100644
--- a/src/boot_info.rs
+++ b/src/boot_info.rs
@@ -16,15 +16,18 @@
//! - S-EL2 SPMC and a S-EL0 SP.
//! - S-EL1 SPMC and a S-EL0 SP.
-use crate::{
- ffa_v1_1::{boot_info_descriptor, boot_info_header},
- Version,
-};
use core::ffi::CStr;
use thiserror::Error;
use uuid::Uuid;
use zerocopy::{FromBytes, IntoBytes};
+// This module uses FF-A v1.1 types by default.
+// FF-A v1.2 didn't introduce any changes to the data stuctures used by this module.
+use crate::{
+ ffa_v1_1::{boot_info_descriptor, boot_info_header},
+ Version,
+};
+
/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
/// with the `FFA_ERROR` interface.
#[derive(Debug, Error)]
@@ -244,7 +247,14 @@
/// virtual address where the buffer is mapped to). This is necessary since there are
/// self-references within the serialized data structure which must be described with an
/// absolute address according to the FF-A spec.
- pub fn pack(descriptors: &[BootInfo], buf: &mut [u8], mapped_addr: Option<usize>) {
+ pub fn pack(
+ version: Version,
+ descriptors: &[BootInfo],
+ buf: &mut [u8],
+ mapped_addr: Option<usize>,
+ ) {
+ assert!((Version(1, 1)..=Version(1, 2)).contains(&version));
+
// Offset from the base of the header to the first element in the boot info descriptor array
// Must be 8 byte aligned, but otherwise we're free to choose any value here.
// Let's just pack the array right after the header.
@@ -365,7 +375,7 @@
let header_raw = boot_info_header {
signature: 0x0ffa,
- version: Version(1, 1).into(),
+ version: version.into(),
boot_info_blob_size: total_offset as u32,
boot_info_desc_size: DESC_SIZE as u32,
boot_info_desc_count: desc_cnt as u32,
@@ -377,7 +387,7 @@
}
/// Validate and return the boot information header
- fn get_header(buf: &[u8]) -> Result<&boot_info_header, Error> {
+ fn get_header(version: Version, buf: &[u8]) -> Result<&boot_info_header, Error> {
let (header_raw, _) =
boot_info_header::ref_from_prefix(buf).map_err(|_| Error::InvalidHeader)?;
@@ -385,9 +395,9 @@
return Err(Error::InvalidSignature);
}
- let version = Version::from(header_raw.version);
- if version != Version(1, 1) {
- return Err(Error::InvalidVersion(version));
+ let header_version = header_raw.version.into();
+ if header_version != version {
+ return Err(Error::InvalidVersion(header_version));
}
Ok(header_raw)
@@ -397,8 +407,12 @@
/// consumer to map all of the boot information blob in its translation regime or copy it to
/// another memory location without parsing each element in the boot information descriptor
/// array.
- pub fn get_blob_size(buf: &[u8]) -> Result<usize, Error> {
- let header_raw = Self::get_header(buf)?;
+ pub fn get_blob_size(version: Version, buf: &[u8]) -> Result<usize, Error> {
+ if !(Version(1, 1)..=Version(1, 2)).contains(&version) {
+ return Err(Error::InvalidVersion(version));
+ }
+
+ let header_raw = Self::get_header(version, buf)?;
Ok(header_raw.boot_info_blob_size as usize)
}
@@ -414,8 +428,8 @@
impl<'a> BootInfoIterator<'a> {
/// Create an iterator of boot information descriptors from a buffer.
- pub fn new(buf: &'a [u8]) -> Result<Self, Error> {
- let header_raw = BootInfo::get_header(buf)?;
+ pub fn new(version: Version, buf: &'a [u8]) -> Result<Self, Error> {
+ let header_raw = BootInfo::get_header(version, buf)?;
if buf.len() < header_raw.boot_info_blob_size as usize {
return Err(Error::InvalidBufferSize);
@@ -551,8 +565,13 @@
let mut buf = [0u8; 0x1ff];
let buf_addr = buf.as_ptr() as usize;
- BootInfo::pack(&[desc1.clone(), desc2.clone()], &mut buf, Some(buf_addr));
- let mut descriptors = BootInfoIterator::new(&buf).unwrap();
+ BootInfo::pack(
+ Version(1, 1),
+ &[desc1.clone(), desc2.clone()],
+ &mut buf,
+ Some(buf_addr),
+ );
+ let mut descriptors = BootInfoIterator::new(Version(1, 1), &buf).unwrap();
let desc1_check = descriptors.next().unwrap().unwrap();
let desc2_check = descriptors.next().unwrap().unwrap();