Add README and doc comments
Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Change-Id: Ie4cf762558b181139e1456887a0e4687b0243564
diff --git a/src/boot_info.rs b/src/boot_info.rs
index 30850e5..446ff08 100644
--- a/src/boot_info.rs
+++ b/src/boot_info.rs
@@ -1,6 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
// SPDX-License-Identifier: MIT OR Apache-2.0
+//! Implementation of the FF-A Boot information protocol.
+//!
+//! An SP or SPMC could rely on boot information for their initialization e.g. a flattened device
+//! tree with nodes to describe the devices and memory regions assigned to the SP or SPMC. FF-A
+//! specifies a protocol that can be used by a producer to pass boot information to a consumer at a
+//! Secure FF-A instance. The Framework assumes that the boot information protocol is used by a
+//! producer and consumer pair that reside at adjacent exception levels as listed below.
+//! - SPMD (producer) and an SPMC (consumer) in either S-EL1 or S-EL2.
+//! - An SPMC (producer) and SP (consumer) pair listed below.
+//! - EL3 SPMC and a Logical S-EL1 SP.
+//! - S-EL2 SPMC and Physical S-EL1 SP.
+//! - EL3 SPMC and a S-EL0 SP.
+//! - 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,
@@ -10,6 +25,8 @@
use uuid::Uuid;
use zerocopy::{FromBytes, IntoBytes};
+/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
+/// with the `FFA_ERROR` interface.
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid standard type {0}")]
@@ -42,12 +59,14 @@
}
}
+/// Name of boot information descriptor.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BootInfoName<'a> {
NullTermString(&'a CStr),
Uuid(Uuid),
}
+/// ID for supported standard boot information types.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum BootInfoStdId {
@@ -72,6 +91,7 @@
const HOB: u8 = 1;
}
+/// ID for implementation defined boot information type.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BootInfoImpdefId(pub u8);
@@ -81,6 +101,7 @@
}
}
+/// Boot information type.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BootInfoType {
Std(BootInfoStdId),
@@ -122,6 +143,7 @@
const ID_MASK: u8 = 0b0111_1111;
}
+/// Boot information contents.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BootInfoContents<'a> {
Address { content_buf: &'a [u8] },
@@ -208,6 +230,7 @@
}
}
+/// Boot information descriptor.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BootInfo<'a> {
pub name: BootInfoName<'a>,
@@ -216,10 +239,15 @@
}
impl BootInfo<'_> {
+ /// Serialize a list of boot information descriptors into a buffer. The `mapped_addr` parameter
+ /// should contain the address of the buffer in the consumers translation regime (typically a
+ /// 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>) {
// 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.
+ // Let's just pack the array right after the header.
const DESC_ARRAY_OFFSET: usize = size_of::<boot_info_header>().next_multiple_of(8);
const DESC_SIZE: usize = size_of::<boot_info_descriptor>();
@@ -365,11 +393,10 @@
Ok(header_raw)
}
- /// Get the size of the boot information blob spanning contiguous memory.
- ///
- /// This enables a 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.
+ /// Get the size of the boot information blob spanning contiguous memory. This enables a
+ /// 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)?;
@@ -377,6 +404,7 @@
}
}
+/// Iterator of boot information descriptors.
pub struct BootInfoIterator<'a> {
buf: &'a [u8],
offset: usize,
@@ -385,6 +413,7 @@
}
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)?;
diff --git a/src/lib.rs b/src/lib.rs
index 6f353f3..d4855b8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#![cfg_attr(not(test), no_std)]
+#![deny(clippy::undocumented_unsafe_blocks)]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![doc = include_str!("../README.md")]
use core::fmt::{self, Debug, Display, Formatter};
use num_enum::{IntoPrimitive, TryFromPrimitive};
@@ -13,10 +16,12 @@
pub mod memory_management;
pub mod partition_info;
-// On many occasions the FF-A spec defines memory size as count of 4K pages,
-// regardless of the current translation granule
+/// Constant for 4K page size. On many occasions the FF-A spec defines memory size as count of 4K
+/// pages, regardless of the current translation granule.
pub const FFA_PAGE_SIZE_4K: usize = 4096;
+/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
+/// with the `FFA_ERROR` interface.
#[derive(Debug, Error)]
pub enum Error {
#[error("Unrecognised FF-A function ID {0}")]
@@ -38,13 +43,16 @@
}
}
+/// An FF-A instance is a valid combination of two FF-A components at an exception level boundary.
#[derive(PartialEq, Clone, Copy)]
pub enum Instance {
+ /// The instance between the SPMC and SPMD.
SecurePhysical,
+ /// The instance between the SPMC and a physical SP (contains the SP's endpoint ID).
SecureVirtual(u16),
}
-/// FF-A v1.1: Function IDs
+/// Function IDs of the various FF-A interfaces.
#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFunctionId))]
#[repr(u32)]
@@ -91,7 +99,7 @@
ConsoleLog64 = 0xc400008a,
}
-/// FF-A v1.1, Table 12.2: Error status codes
+/// Error status codes used by the `FFA_ERROR` interface.
#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedErrorCode))]
#[repr(i32)]
@@ -116,6 +124,7 @@
NoData = -9,
}
+/// Endpoint ID and vCPU ID pair, used by `FFA_ERROR`, `FFA_INTERRUPT` and `FFA_RUN` interfaces.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct TargetInfo {
pub endpoint_id: u16,
@@ -137,12 +146,14 @@
}
}
+/// Arguments for the `FFA_SUCCESS` interface.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum SuccessArgs {
Result32([u32; 6]),
Result64([u64; 6]),
}
+/// Version number of the FF-A implementation, `.0` is the major, `.1` is minor the version.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Version(pub u16, pub u16);
@@ -170,6 +181,7 @@
}
}
+/// Feature IDs used by the `FFA_FEATURES` interface.
#[derive(Clone, Copy, Debug, Eq, IntoPrimitive, PartialEq, TryFromPrimitive)]
#[num_enum(error_type(name = Error, constructor = Error::UnrecognisedFeatureId))]
#[repr(u8)]
@@ -179,6 +191,7 @@
ManagedExitInterrupt = 0x3,
}
+/// Arguments for the `FFA_FEATURES` interface.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Feature {
FuncId(FuncId),
@@ -208,36 +221,46 @@
}
}
+/// RXTX buffer descriptor, used by `FFA_RXTX_MAP`.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum RxTxAddr {
Addr32 { rx: u32, tx: u32 },
Addr64 { rx: u64, tx: u64 },
}
+/// 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]),
}
+/// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
+/// descriptor. Used by `FFA_MEM_{DONATE,LEND,SHARE,RETRIEVE_REQ}` interfaces, only when the TX
+/// buffer is not used to transmit the transaction descriptor.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum MemOpBuf {
Buf32 { addr: u32, page_cnt: u32 },
Buf64 { addr: u64, page_cnt: u32 },
}
+/// Memory address argument for `FFA_MEM_PERM_{GET,SET}` interfaces.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum MemAddr {
Addr32(u32),
Addr64(u64),
}
+/// Argument for the `FFA_CONSOLE_LOG` interface. Currently only supports x0..x7 instead of x0..x17.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum ConsoleLogChars {
Reg32([u32; 6]),
Reg64([u64; 6]),
}
+/// FF-A "message types", the terminology used by the spec is "interfaces". The interfaces are used
+/// by FF-A components for communication at an FF-A instance. The spec also describes the valid FF-A
+/// instances and conduits for each interface.
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Interface {
Error {
@@ -743,6 +766,7 @@
}
}
+ /// Create register contents for an interface.
pub fn copy_to_array(&self, a: &mut [u64; 8]) {
a.fill(0);
if let Some(function_id) = self.function_id() {
@@ -1001,7 +1025,7 @@
}
}
- /// Helper function to create an FFA_SUCCESS interface without any arguments
+ /// Helper function to create an `FFA_SUCCESS` interface without any arguments.
pub fn success32_noargs() -> Self {
Self::Success {
target_info: 0,
@@ -1009,7 +1033,7 @@
}
}
- /// Helper function to create an FFA_ERROR interface without any arguments
+ /// Helper function to create an `FFA_ERROR` interface with an error code.
pub fn error(error_code: FfaError) -> Self {
Self::Error {
target_info: TargetInfo {
@@ -1021,9 +1045,15 @@
}
}
-pub const CONSOLE_LOG_32_MAX_MSG_LEN: u8 = 24;
-pub const CONSOLE_LOG_64_MAX_MSG_LEN: u8 = 48;
+/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG32` message.
+pub const CONSOLE_LOG_32_MAX_CHAR_CNT: u8 = 24;
+/// Maximum number of characters transmitted in a single `FFA_CONSOLE_LOG64` message. Note: this
+/// value currently differs from the spec because the library currently only supports parsing 8
+/// registers instead of 18.
+pub const CONSOLE_LOG_64_MAX_CHAR_CNT: u8 = 48;
+/// Helper function to convert the "Tightly packed list of characters" format used by the
+/// `FFA_CONSOLE_LOG` interface into a byte slice.
pub fn parse_console_log(
char_cnt: u8,
char_lists: &ConsoleLogChars,
@@ -1031,7 +1061,7 @@
) -> Result<(), FfaError> {
match char_lists {
ConsoleLogChars::Reg32(regs) => {
- if !(1..=CONSOLE_LOG_32_MAX_MSG_LEN).contains(&char_cnt) {
+ if !(1..=CONSOLE_LOG_32_MAX_CHAR_CNT).contains(&char_cnt) {
return Err(FfaError::InvalidParameters);
}
for (i, reg) in regs.iter().enumerate() {
@@ -1039,7 +1069,7 @@
}
}
ConsoleLogChars::Reg64(regs) => {
- if !(1..=CONSOLE_LOG_64_MAX_MSG_LEN).contains(&char_cnt) {
+ if !(1..=CONSOLE_LOG_64_MAX_CHAR_CNT).contains(&char_cnt) {
return Err(FfaError::InvalidParameters);
}
for (i, reg) in regs.iter().enumerate() {
diff --git a/src/memory_management.rs b/src/memory_management.rs
index 777a399..e81a5ca 100644
--- a/src/memory_management.rs
+++ b/src/memory_management.rs
@@ -1,6 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
// SPDX-License-Identifier: MIT OR Apache-2.0
+//! Implementation of the FF-A Memory Management protocol.
+//!
+//! FF-A describes mechanisms and interfaces that enable FF-A components to manage access and
+//! ownership of memory regions in the physical address space. FF-A components can use a combination
+//! of Framework and Partition messages to manage memory regions in the following ways:
+//! - The Owner of a memory region can transfer its ownership to another FF-A endpoint.
+//! - The Owner of a memory region can transfer its access to one or more FF-A endpoints.
+//! - The Owner of a memory region can share access to it with one or more FF-A endpoints.
+//! - The Owner can reclaim access to a memory region after the FF-A endpoints that were granted
+//! access to that memory region have relinquished their access.
+
use crate::ffa_v1_1::{
composite_memory_region_descriptor, constituent_memory_region_descriptor,
endpoint_memory_access_descriptor, memory_access_permission_descriptor,
@@ -10,6 +21,8 @@
use thiserror::Error;
use zerocopy::{FromBytes, IntoBytes};
+/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
+/// with the `FFA_ERROR` interface.
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid cacheability attribute {0}")]
@@ -42,6 +55,7 @@
}
}
+/// Memory region handle, used to identify a composite memory region description.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Handle(pub u64);
@@ -61,6 +75,7 @@
pub const INVALID: u64 = 0xffff_ffff_ffff_ffff;
}
+/// Cacheability attribute of a memory region. Only valid for normal memory.
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[repr(u16)]
pub enum Cacheability {
@@ -88,6 +103,7 @@
const WRITE_BACK: u16 = 0b11;
}
+/// Shareability attribute of a memory region. Only valid for normal memory.
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[repr(u16)]
pub enum Shareability {
@@ -118,6 +134,7 @@
const INNER: u16 = 0b11;
}
+/// Device memory attributes.
#[derive(Debug, Default, Clone, Copy)]
#[repr(u16)]
pub enum DeviceMemAttributes {
@@ -151,6 +168,7 @@
const DEV_GRE: u16 = 0b11;
}
+/// Memory region type.
#[derive(Debug, Default, Clone, Copy)]
pub enum MemType {
#[default]
@@ -199,6 +217,7 @@
const NORMAL: u16 = 0b10;
}
+/// Memory region security attribute.
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[repr(u16)]
pub enum MemRegionSecurity {
@@ -224,6 +243,7 @@
const NON_SECURE: u16 = 0b1;
}
+/// Memory region attributes descriptor.
#[derive(Debug, Default, Clone, Copy)]
pub struct MemRegionAttributes {
pub security: MemRegionSecurity,
@@ -252,6 +272,7 @@
}
}
+/// Instruction access permissions of a memory region.
#[derive(Debug, Default, Clone, Copy)]
#[repr(u8)]
pub enum InstuctionAccessPerm {
@@ -282,6 +303,7 @@
const EXECUTABLE: u8 = 0b10;
}
+/// Data access permissions of a memory region.
#[derive(Debug, Default, Clone, Copy)]
#[repr(u8)]
pub enum DataAccessPerm {
@@ -312,6 +334,7 @@
const READ_WRITE: u8 = 0b10;
}
+/// Endpoint memory access permissions descriptor.
#[derive(Debug, Default, Clone, Copy)]
pub struct MemAccessPerm {
pub endpoint_id: u16,
@@ -320,6 +343,7 @@
pub flags: u8, // TODO
}
+/// Iterator of endpoint memory access permission descriptors.
pub struct MemAccessPermIterator<'a> {
buf: &'a [u8],
offset: usize,
@@ -327,6 +351,7 @@
}
impl<'a> MemAccessPermIterator<'a> {
+ /// Create an iterator of endpoint memory access permission descriptors from a buffer.
fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
let Some(total_size) = count
.checked_mul(size_of::<endpoint_memory_access_descriptor>())
@@ -390,12 +415,14 @@
}
}
+/// Constituent memory region descriptor.
#[derive(Debug, Default, Clone, Copy)]
pub struct ConstituentMemRegion {
pub address: u64,
pub page_cnt: u32,
}
+/// Iterator of constituent memory region descriptors.
pub struct ConstituentMemRegionIterator<'a> {
buf: &'a [u8],
offset: usize,
@@ -403,6 +430,7 @@
}
impl<'a> ConstituentMemRegionIterator<'a> {
+ /// Create an iterator of constituent memory region descriptors from a buffer.
fn new(buf: &'a [u8], count: usize, offset: usize) -> Result<Self, Error> {
let Some(total_size) = count
.checked_mul(size_of::<constituent_memory_region_descriptor>())
@@ -446,6 +474,7 @@
}
}
+/// Flags of a memory management transaction.
#[derive(Debug, Default, Clone, Copy)]
pub struct MemTransactionFlags(pub u32);
@@ -463,6 +492,8 @@
pub const HINT_VALID: u32 = 0b1 << 9;
}
+/// Memory transaction decriptor. Used by an Owner/Lender and a Borrower/Receiver in a transaction
+/// to donate, lend or share a memory region.
#[derive(Debug, Default)]
pub struct MemTransactionDesc {
pub sender_id: u16,
@@ -483,6 +514,8 @@
// region descriptor
const CONSTITUENT_ARRAY_OFFSET: usize = size_of::<composite_memory_region_descriptor>();
+ /// Serialize a memory transaction descriptor and the related constituent memory region
+ /// descriptors and endpoint memory access permission descriptors into a buffer.
pub fn pack(
&self,
constituents: &[ConstituentMemRegion],
@@ -562,6 +595,9 @@
offset
}
+ /// Deserialize a memory transaction descriptor from a buffer and return an interator of the
+ /// related endpoint memory access permission descriptors and constituent memory region
+ /// descriptors, if any.
pub fn unpack(
buf: &[u8],
) -> Result<
@@ -663,6 +699,7 @@
}
}
+/// Descriptor to relinquish a memory region. Currently only supports specifying a single endpoint.
#[derive(Debug, Default)]
pub struct MemRelinquishDesc {
pub handle: Handle,
diff --git a/src/partition_info.rs b/src/partition_info.rs
index a8025b3..781f299 100644
--- a/src/partition_info.rs
+++ b/src/partition_info.rs
@@ -1,11 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
// SPDX-License-Identifier: MIT OR Apache-2.0
+//! 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};
+/// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
+/// with the `FFA_ERROR` interface.
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid buffer size")]
@@ -20,11 +24,18 @@
}
}
+/// Type of partition identified by the partition ID.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PartitionIdType {
+ /// Partition ID is a PE endpoint ID. Contains the number of execution contexts implemented by
+ /// this partition.
PeEndpoint { execution_ctx_count: u16 },
+ /// Partition ID is a SEPID for an independent peripheral device.
SepidIndep,
+ /// Partition ID is a SEPID for an dependent peripheral device. Contains the ID of the proxy
+ /// endpoint for a dependent peripheral device.
SepidDep { proxy_endpoint_id: u16 },
+ /// Partition ID is an auxiliary ID.
Aux,
}
@@ -37,21 +48,22 @@
const AUX: u32 = 0b11;
}
+/// Properties of a partition.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct PartitionProperties {
- /// Supports receipt of direct requests
+ /// The partition supports receipt of direct requests.
pub support_direct_req_rec: bool,
- /// Can send direct requests
+ /// The partition can send direct requests.
pub support_direct_req_send: bool,
- /// Can send and receive indirect messages
+ /// The partition can send and receive indirect messages.
pub support_indirect_msg: bool,
- /// Supports receipt of notifications
+ /// The partition supports receipt of notifications.
pub support_notif_rec: bool,
- /// Must be informed about each VM that is created by the Hypervisor
+ /// The partition must be informed about each VM that is created by the Hypervisor.
pub subscribe_vm_created: bool,
- /// Must be informed about each VM that is destroyed by the Hypervisor
+ /// The partition must be informed about each VM that is destroyed by the Hypervisor.
pub subscribe_vm_destroyed: bool,
- /// Partition runs in the AArch64 execution state
+ /// The partition runs in the AArch64 execution state.
pub is_aarch64: bool,
}
@@ -172,6 +184,7 @@
}
}
+/// Partition information descriptor, returned by the `FFA_PARTITION_INFO_GET` interface.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PartitionInfo {
pub uuid: Uuid,
@@ -181,8 +194,10 @@
}
impl PartitionInfo {
- pub const DESC_SIZE: usize = size_of::<partition_info_descriptor>();
+ 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) {
let mut offset = 0;
@@ -207,6 +222,7 @@
}
}
+/// Iterator of partition information descriptors.
pub struct PartitionInfoIterator<'a> {
buf: &'a [u8],
offset: usize,
@@ -214,6 +230,7 @@
}
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> {
let Some(total_size) = count.checked_mul(PartitionInfo::DESC_SIZE) else {
return Err(Error::InvalidBufferSize);