Initial version
Add some common FF-A functionality. Supported features (roughly):
- define FF-A function IDs and error codes
- create boot info descriptor
- create partition info descriptor
- create and parse memory transaction descriptor
- parse memory relinquish descriptor
- parse console log message
Limitations apply, code quality is not production ready.
Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Change-Id: Ibb3fde9d4c0d0d9b8823bb84cdcf23eb3f9d087a
diff --git a/src/boot_info.rs b/src/boot_info.rs
new file mode 100644
index 0000000..553c7c5
--- /dev/null
+++ b/src/boot_info.rs
@@ -0,0 +1,182 @@
+// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+use uuid::Uuid;
+
+pub enum BootInfoName {
+ NullTermString(&'static str),
+ Uuid(Uuid),
+}
+
+#[derive(Clone, Copy)]
+pub enum BootInfoStdType {
+ Fdt = 0,
+ Hob = 1,
+}
+
+pub enum BootInfoType {
+ Std(BootInfoStdType),
+ Impdef(u8),
+}
+
+pub enum BootInfoContents {
+ Address(usize),
+ Value(u64),
+}
+
+pub struct BootInfoDescriptor {
+ /// Name of boot information passed to the consumer
+ pub name: BootInfoName,
+
+ /// Type of boot information passed to the consumer
+ pub typ: BootInfoType,
+
+ /// Size (in bytes) of boot information identified by the Name and Type fields
+ pub size: u32,
+
+ pub contents: BootInfoContents,
+}
+
+impl BootInfoDescriptor {
+ pub fn create(descriptors: &[BootInfoDescriptor], buf: &mut [u8]) {
+ // Offset from the base of the header to the first element in the boot info descriptor array
+ // Must be 8 byte aligned
+ const DESC_ARRAY_OFFSET: usize = 32;
+
+ /// In FF-A v1.1, Table 5.8: Boot information descriptor is 32 bytes long
+ const DESC_SIZE: usize = 32;
+
+ // assert!(descriptors.len() <= u32::MAX as usize);
+ let desc_cnt = descriptors.len();
+
+ // Add the already known fields, later we have to add the sizes referenced by the individual descriptors
+ let mut total_size = 0usize;
+ total_size = total_size.checked_add(DESC_ARRAY_OFFSET).unwrap();
+ total_size = total_size
+ .checked_add(desc_cnt.checked_mul(DESC_SIZE).unwrap())
+ .unwrap();
+
+ // Create the boot info header starting at offset 0 in the buffer
+ // Offset 0, length 4: Hexadecimal value 0x0FFA to identify the header
+ buf[0..4].copy_from_slice(&0x0ffa_u32.to_le_bytes());
+
+ // Offset 4, length 4: Version of the boot information blob encoded as in FFA_VERSION_GET
+ buf[4..8].copy_from_slice(&0x0001_0001_u32.to_le_bytes());
+
+ // Offset 12, length 4: Size of each boot information descriptor in the array
+ buf[12..16].copy_from_slice(&(DESC_SIZE as u32).to_le_bytes());
+
+ // Offset 16, length 4: Count of boot information descriptors in the array
+ buf[16..20].copy_from_slice(&(desc_cnt as u32).to_le_bytes());
+
+ // Offset 20, length 4: Offset to array of boot information descriptors
+ buf[20..24].copy_from_slice(&(DESC_ARRAY_OFFSET as u32).to_le_bytes());
+
+ // Offset 24, length 8: Reserved (MBZ)
+ buf[24..32].fill(0);
+
+ // Fill the boot info descriptor array, all offset based from DESC_ARRAY_OFFSET
+ let mut offset = DESC_ARRAY_OFFSET;
+ for desc in descriptors {
+ // Offset 0, length 16: Name of boot information passed to the consumer
+ match &desc.name {
+ BootInfoName::NullTermString(name) => {
+ assert!(name.is_ascii());
+ let name_len = name.len().min(15);
+ buf[offset..offset + name_len].copy_from_slice(&name.as_bytes()[..name_len]);
+ buf[offset + name_len..offset + 16].fill(0); // Make sure it's null terminated
+ }
+ BootInfoName::Uuid(uuid) => {
+ buf[offset..offset + 16].copy_from_slice(&uuid.to_bytes_le());
+ }
+ }
+
+ // Offset 16, length 1: Type of boot information passed to the consumer
+ let info_type = match desc.typ {
+ BootInfoType::Std(std_type) => (std_type as u8) & 0b0111_1111,
+ BootInfoType::Impdef(typ) => (0b1 << 7) | typ,
+ };
+ buf[offset + 16] = info_type;
+
+ // Offset 17, length 1: Reserved (MBZ)
+ buf[offset + 17] = 0;
+
+ // Offset 18, length 2: Flags to describe properties of boot information associated with this descriptor
+ let mut flags = 0u16;
+ if let BootInfoName::Uuid(_) = &desc.name {
+ flags |= 0b1;
+ }
+ if let BootInfoContents::Value(_) = desc.contents {
+ flags |= 0b1 << 2;
+ }
+ buf[offset + 18..offset + 20].copy_from_slice(&flags.to_le_bytes());
+
+ // Offset 20, length 4: Size (in bytes) of boot information identified by the Name and Type fields.
+ match desc.contents {
+ BootInfoContents::Address(_) => {
+ total_size = total_size.checked_add(desc.size as usize).unwrap();
+ }
+ BootInfoContents::Value(_) => {
+ assert!((1..=8).contains(&desc.size));
+ }
+ }
+ buf[offset + 20..offset + 24].copy_from_slice(&desc.size.to_le_bytes());
+
+ // Offset 24, length 8: Value or address of boot information identified by the Name and Type fields.
+ // Value or address of boot information identified by the Name and Type fields.
+ //
+ // If in the Flags field, bit\[3:2\] = b'0,
+ // * The address has the same attributes as the boot information blob address described in
+ // 5.4.3 Boot information address.
+ // * Size field contains the length (in bytes) of boot information at the specified address.
+ //
+ // If in the Flags field, bit\[3:2\] = b’1,
+ // * Size field contains the exact size of the value specified in this field.
+ // * Size is >=1 bytes and <= 8 bytes.
+ let content = match desc.contents {
+ BootInfoContents::Address(addr) => addr as u64,
+ BootInfoContents::Value(val) => val,
+ };
+ buf[offset + 24..offset + 32].copy_from_slice(&content.to_le_bytes());
+
+ offset += DESC_SIZE;
+ }
+
+ // TODO: add padding size between boot information referenced by the descriptors
+
+ // Offset 8, length 4: Size of boot information blob spanning contiguous memory
+ assert!(buf.len() <= u32::MAX as usize);
+ assert!(total_size <= buf.len());
+ buf[8..12].copy_from_slice(&(total_size as u32).to_le_bytes());
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use uuid::uuid;
+
+ #[test]
+ fn boot_info() {
+ let desc1 = BootInfoDescriptor {
+ name: BootInfoName::NullTermString(&"test1234test1234"),
+ typ: BootInfoType::Impdef(0xab),
+ size: 4,
+ contents: BootInfoContents::Value(0xbeef),
+ };
+
+ let fdt = [0u8; 0xff];
+ let desc2 = BootInfoDescriptor {
+ name: BootInfoName::Uuid(uuid!("12345678-1234-1234-1234-123456789abc")),
+ typ: BootInfoType::Std(BootInfoStdType::Fdt),
+ size: 0xff,
+ contents: BootInfoContents::Address(&fdt as *const u8 as usize),
+ };
+
+ let mut buf = [0u8; 0x1ff];
+ BootInfoDescriptor::create(&[desc1, desc2], &mut buf);
+
+ println!("{:#x?}", &buf[0..0x0f]);
+ }
+}