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/partition_info.rs b/src/partition_info.rs
new file mode 100644
index 0000000..5301cb7
--- /dev/null
+++ b/src/partition_info.rs
@@ -0,0 +1,121 @@
+// 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 PartitionIdType {
+    PeEndpoint(u16),
+    SepidIndep,
+    SepidDep(u16),
+    Aux,
+}
+
+pub struct PartInfoDesc {
+    pub partition_id: u16,
+    pub uuid: Uuid,
+    pub id_type: PartitionIdType,
+    pub support_direct_req_rec: bool,
+    pub support_direct_req_send: bool,
+    pub support_indirect_msg: bool,
+    pub support_notif_rec: bool,
+    pub subscribe_vm_created: bool,
+    pub subscribe_vm_destroyed: bool,
+    pub is_aarch64: bool,
+}
+
+impl PartInfoDesc {
+    pub const SIZE: usize = 24;
+}
+
+pub fn create_partition_info(buf: &mut [u8], descriptors: &[PartInfoDesc], fill_uuid: bool) {
+    let mut offset = 0;
+
+    for desc in descriptors {
+        // Offset 0, length 2: 16-bit ID of the partition, stream or auxiliary endpoint.
+        buf[offset..offset + 2].copy_from_slice(&desc.partition_id.to_le_bytes());
+
+        // Offset 2, length 2: Execution context count or Proxy partition ID
+        match desc.id_type {
+            PartitionIdType::PeEndpoint(exec_ctx_cnt) => {
+                buf[offset + 2..offset + 4].copy_from_slice(&exec_ctx_cnt.to_le_bytes())
+            }
+            PartitionIdType::SepidDep(id) => {
+                buf[offset + 2..offset + 4].copy_from_slice(&id.to_le_bytes())
+            }
+            _ => buf[offset + 2..offset + 4].fill(0),
+        }
+
+        // Offset 4, length 4: Flags to determine partition properties.
+        let mut props = 0u32;
+        match desc.id_type {
+            PartitionIdType::PeEndpoint(_) => {
+                if desc.support_direct_req_rec {
+                    props |= 0b1;
+                    if desc.subscribe_vm_created {
+                        // TODO: check NS phys instance
+                        props |= 0b1 << 6
+                    }
+                    if desc.subscribe_vm_destroyed {
+                        // TODO: check NS phys instance
+                        props |= 0b1 << 7
+                    }
+                }
+                if desc.support_direct_req_send {
+                    props |= 0b1 << 1
+                }
+                if desc.support_indirect_msg {
+                    props |= 0b1 << 2
+                }
+                if desc.support_notif_rec {
+                    props |= 0b1 << 3
+                }
+            }
+            PartitionIdType::SepidIndep => props |= 0b01 << 4,
+            PartitionIdType::SepidDep(_) => props |= 0b10 << 4,
+            PartitionIdType::Aux => props |= 0b11 << 4,
+        }
+        if desc.is_aarch64 {
+            props |= 0b1 << 8
+        }
+        buf[offset + 4..offset + 8].copy_from_slice(&props.to_le_bytes());
+
+        // Offset 8, length 16: Partition UUID if the Nil UUID was specified. Reserved (MBZ) otherwise
+        if fill_uuid {
+            buf[offset + 8..offset + 24].copy_from_slice(desc.uuid.as_bytes());
+        } else {
+            buf[offset + 8..offset + 24].fill(0);
+        }
+
+        offset += PartInfoDesc::SIZE;
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use uuid::uuid;
+
+    #[test]
+    fn part_info() {
+        let desc = PartInfoDesc {
+            partition_id: 0x8001,
+            uuid: uuid!("12345678-1234-1234-1234-123456789abc"),
+            id_type: PartitionIdType::PeEndpoint(1),
+            support_direct_req_rec: true,
+            support_direct_req_send: true,
+            support_indirect_msg: false,
+            support_notif_rec: false,
+            subscribe_vm_created: true,
+            subscribe_vm_destroyed: true,
+            is_aarch64: true,
+        };
+
+        let mut buf = [0u8; 0xff];
+        create_partition_info(&mut buf, &[desc], true);
+
+        println!("{:#x?}", &buf[0..0x0f]);
+
+        assert_eq!(0x8001_u16, u16::from_le_bytes([buf[0], buf[1]]));
+    }
+}