libsp: Add memory descriptor handler functions.
The patch contains functions for building and parsing the structures of
memory transaction. These functions enable the user to describe the
memory regions and their access specification to share/lend/donate
and retrieve.
Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I927fbfc857b06a34a727be2d5c6d89ed7db4445c
diff --git a/components/messaging/ffa/libsp/component.cmake b/components/messaging/ffa/libsp/component.cmake
index 60bc507..27768ce 100644
--- a/components/messaging/ffa/libsp/component.cmake
+++ b/components/messaging/ffa/libsp/component.cmake
@@ -12,6 +12,7 @@
"${CMAKE_CURRENT_LIST_DIR}/aarch64/ffa_syscalls_a64.S"
"${CMAKE_CURRENT_LIST_DIR}/ffa.c"
"${CMAKE_CURRENT_LIST_DIR}/ffa_interrupt_handler.c"
+ "${CMAKE_CURRENT_LIST_DIR}/ffa_memory_descriptors.c"
"${CMAKE_CURRENT_LIST_DIR}/sp_rxtx.c"
)
@@ -20,6 +21,7 @@
${CMAKE_CURRENT_LIST_DIR}/include/ffa_api_types.h
${CMAKE_CURRENT_LIST_DIR}/include/ffa_api.h
${CMAKE_CURRENT_LIST_DIR}/include/ffa_internal_api.h
+ ${CMAKE_CURRENT_LIST_DIR}/include/ffa_memory_descriptors.h
${CMAKE_CURRENT_LIST_DIR}/include/sp_api_defines.h
${CMAKE_CURRENT_LIST_DIR}/include/sp_api_types.h
${CMAKE_CURRENT_LIST_DIR}/include/sp_api.h
diff --git a/components/messaging/ffa/libsp/ffa_memory_descriptors.c b/components/messaging/ffa/libsp/ffa_memory_descriptors.c
new file mode 100644
index 0000000..cd430bb
--- /dev/null
+++ b/components/messaging/ffa/libsp/ffa_memory_descriptors.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "ffa_memory_descriptors.h"
+#include "ffa_api.h"
+#include <assert.h>
+#include <string.h>
+
+static struct ffa_mem_transaction_desc *
+get_mem_transaction_desc(struct ffa_mem_transaction_buffer *buffer)
+{
+ assert(sizeof(struct ffa_mem_transaction_desc) <= buffer->length);
+ return (struct ffa_mem_transaction_desc *)buffer->buffer;
+}
+
+static uintptr_t get_offset_in_buffer(struct ffa_mem_transaction_buffer *buffer,
+ void *object)
+{
+ return (uintptr_t)(((uint8_t *)object) - ((uint8_t *)buffer->buffer));
+}
+
+static struct ffa_composite_mem_region_desc *
+get_composite_desc_by_offset(struct ffa_mem_transaction_buffer *buffer,
+ uint32_t offset)
+{
+ void *ptr = NULL;
+
+ assert(offset + sizeof(struct ffa_composite_mem_region_desc) <=
+ buffer->length);
+ ptr = (((uint8_t *)buffer->buffer) + offset);
+
+ return (struct ffa_composite_mem_region_desc *)ptr;
+}
+
+static uint32_t
+get_composite_desc_offset(struct ffa_mem_transaction_buffer *buffer)
+{
+ const struct ffa_mem_access_desc *access_desc = NULL;
+
+ if (ffa_get_mem_access_desc_count(buffer) == 0)
+ return 0;
+
+ /*
+ * All access descriptors have the same offset so we use the first one
+ * if it exists.
+ */
+ access_desc = ffa_get_mem_access_desc(buffer, 0);
+ return access_desc->composite_mem_region_desc_offset;
+}
+
+static struct ffa_composite_mem_region_desc *
+get_composite_desc(struct ffa_mem_transaction_buffer *buffer)
+{
+ uint32_t offset = 0;
+
+ offset = get_composite_desc_offset(buffer);
+
+ return get_composite_desc_by_offset(buffer, offset);
+}
+
+void ffa_init_mem_transaction_buffer(void *address, size_t length,
+ struct ffa_mem_transaction_buffer *buffer)
+{
+ buffer->buffer = address;
+ buffer->length = length;
+ buffer->used = 0;
+}
+
+void ffa_init_mem_transaction_desc(struct ffa_mem_transaction_buffer *buffer,
+ uint16_t sender_id, uint8_t mem_region_attr,
+ uint32_t flags, uint64_t handle,
+ uint64_t tag)
+{
+ struct ffa_mem_transaction_desc *transaction = NULL;
+
+ transaction = get_mem_transaction_desc(buffer);
+
+ transaction->sender_id = sender_id;
+ transaction->mem_region_attr = mem_region_attr;
+ transaction->reserved_mbz0 = 0;
+ transaction->flags = flags;
+ transaction->handle = handle;
+ transaction->tag = tag;
+ transaction->reserved_mbz1 = 0;
+ transaction->mem_access_desc_count = 0;
+
+ buffer->used = sizeof(struct ffa_mem_transaction_desc);
+}
+
+const struct ffa_mem_transaction_desc *
+ffa_get_mem_transaction_desc(struct ffa_mem_transaction_buffer *buffer)
+{
+ return get_mem_transaction_desc(buffer);
+}
+
+void ffa_reserve_mem_access_desc(struct ffa_mem_transaction_buffer *buffer,
+ size_t count)
+{
+ const struct ffa_mem_transaction_desc *transaction = NULL;
+ size_t required_size = 0;
+ uint32_t __maybe_unused composite_offset = 0;
+
+ transaction = ffa_get_mem_transaction_desc(buffer);
+ if (count <= transaction->mem_access_desc_count) {
+ /* Prevent shrinking below the current count */
+ return;
+ }
+
+ /* Checking if the descriptors fit in the buffer */
+ required_size = sizeof(struct ffa_mem_transaction_desc);
+ required_size += sizeof(struct ffa_mem_access_desc) * count;
+
+ assert(required_size <= buffer->length);
+
+ /*
+ * Checking if the descriptor array won't overlap with the composite
+ * memory region descriptor if it exists
+ */
+ composite_offset = get_composite_desc_offset(buffer);
+ assert(composite_offset == 0 || required_size <= composite_offset);
+
+ if (buffer->used < required_size)
+ buffer->used = required_size;
+}
+
+uint32_t ffa_add_mem_access_desc(struct ffa_mem_transaction_buffer *buffer,
+ uint16_t endpoint_id, uint8_t mem_access_perm,
+ uint8_t flags)
+{
+ struct ffa_mem_transaction_desc *transaction = NULL;
+ struct ffa_mem_access_desc *access_desc = NULL;
+ struct ffa_mem_access_perm_desc *access_perm_desc = NULL;
+ uint32_t index = 0;
+ uint32_t composite_offset = 0;
+ size_t required_size = 0;
+
+ /* Get next access descriptor index */
+ transaction = get_mem_transaction_desc(buffer);
+ index = transaction->mem_access_desc_count;
+
+ assert(index != UINT32_MAX);
+
+ /* Allocating access descriptor */
+ required_size = sizeof(struct ffa_mem_transaction_desc);
+ required_size += sizeof(struct ffa_mem_access_desc) * (index + 1);
+ assert(required_size <= buffer->length);
+
+ /*
+ * Checking if the descriptor array won't overlap with the composite
+ * memory region descriptor if it exists
+ */
+ composite_offset = get_composite_desc_offset(buffer);
+ assert(composite_offset == 0 || required_size <= composite_offset);
+
+ if (buffer->used < required_size)
+ buffer->used = required_size;
+
+ transaction->mem_access_desc_count++;
+
+ /* Initializing access descriptor */
+ access_desc = &transaction->mem_access_desc[index];
+
+ access_perm_desc = &access_desc->mem_access_perm_desc;
+ access_perm_desc->endpoint_id = endpoint_id;
+ access_perm_desc->mem_access_permissions = mem_access_perm;
+ access_perm_desc->flags = flags;
+
+ /*
+ * Assigning the composite memory descriptor offset as it is either 0
+ * for indicating that the composite descriptor has not been added to
+ * the transaction buffer or setting it the point to the valid and
+ * only composite descriptor.
+ */
+ access_desc->composite_mem_region_desc_offset = composite_offset;
+ access_desc->reserved_mbz = 0;
+
+ return index;
+}
+
+uint32_t
+ffa_get_mem_access_desc_count(struct ffa_mem_transaction_buffer *buffer)
+{
+ const struct ffa_mem_transaction_desc *transaction = NULL;
+
+ transaction = ffa_get_mem_transaction_desc(buffer);
+
+ return transaction->mem_access_desc_count;
+}
+
+const struct ffa_mem_access_desc *
+ffa_get_mem_access_desc(struct ffa_mem_transaction_buffer *buffer,
+ uint32_t descriptor_index)
+{
+ struct ffa_mem_transaction_desc *transaction = NULL;
+ struct ffa_mem_access_desc *access_desc = NULL;
+ size_t offset = 0;
+
+ transaction = get_mem_transaction_desc(buffer);
+
+ assert(descriptor_index < transaction->mem_access_desc_count);
+
+ access_desc = &transaction->mem_access_desc[descriptor_index];
+
+ /* Validating if the whole descriptor is within the buffer boundaries */
+ offset = get_offset_in_buffer(buffer, access_desc);
+ offset += sizeof(struct ffa_mem_access_desc);
+ assert(offset <= buffer->length);
+
+ return access_desc;
+}
+
+void ffa_add_memory_region(struct ffa_mem_transaction_buffer *buffer,
+ const void *address, uint32_t page_count)
+{
+ struct ffa_mem_transaction_desc *transaction = NULL;
+
+ struct ffa_composite_mem_region_desc *comp_desc = NULL;
+ struct ffa_constituent_mem_region_desc *region_desc = NULL;
+ size_t required_size = 0;
+ uint32_t range_index = 0;
+ uint32_t offset = 0;
+
+ transaction = get_mem_transaction_desc(buffer);
+
+ assert(transaction->mem_access_desc_count > 0);
+
+ offset = get_composite_desc_offset(buffer);
+
+ if (offset == 0) {
+ /* Adding new composite descriptor */
+ struct ffa_mem_access_desc *access_desc = NULL;
+ uint32_t i = 0;
+
+ /*
+ * Allocate composite memory regions descriptor to the end of
+ * the currently used area
+ */
+ required_size = buffer->used +
+ sizeof(struct ffa_composite_mem_region_desc);
+
+ /* Overflow and truncation checks */
+ assert(required_size <= buffer->length);
+ assert(buffer->used == (size_t)((uint32_t)buffer->used));
+
+ offset = buffer->used;
+ buffer->used = required_size;
+
+ /*
+ * Setting composite memory region descriptor offset in all the
+ * memory access descriptors
+ */
+ for (i = 0; i < transaction->mem_access_desc_count; i++) {
+ access_desc = &transaction->mem_access_desc[i];
+ access_desc->composite_mem_region_desc_offset = offset;
+ }
+
+ /* Initializing composite descriptor values */
+ comp_desc = get_composite_desc_by_offset(buffer, offset);
+ comp_desc->total_page_count = 0;
+ comp_desc->address_range_count = 0;
+ comp_desc->reserved_mbz = 0;
+ } else {
+ /* The composite descriptor already exists */
+ comp_desc = get_composite_desc_by_offset(buffer, offset);
+ }
+
+ range_index = comp_desc->address_range_count;
+ required_size = buffer->used +
+ sizeof(struct ffa_constituent_mem_region_desc);
+ assert(required_size <= buffer->length);
+ buffer->used = required_size;
+
+ comp_desc->total_page_count += page_count;
+ comp_desc->address_range_count++;
+
+ region_desc = &comp_desc->constituent_mem_region_desc[range_index];
+
+ region_desc->address = (uintptr_t)address;
+ region_desc->page_count = page_count;
+ region_desc->reserved_mbz = 0;
+}
+
+const struct ffa_composite_mem_region_desc *
+ffa_get_memory_region(struct ffa_mem_transaction_buffer *buffer)
+{
+ struct ffa_composite_mem_region_desc *desc = NULL;
+ size_t __maybe_unused end_offset = 0;
+
+ desc = get_composite_desc(buffer);
+
+ /*
+ * Checking if the constituent region descriptors are also in the buffer
+ */
+ end_offset = ((uint8_t *)desc) - (uint8_t *)buffer->buffer;
+ end_offset += sizeof(struct ffa_composite_mem_region_desc);
+ end_offset += desc->address_range_count *
+ sizeof(struct ffa_constituent_mem_region_desc);
+ assert(end_offset <= buffer->length);
+
+ return desc;
+}
diff --git a/components/messaging/ffa/libsp/include/ffa_memory_descriptors.h b/components/messaging/ffa/libsp/include/ffa_memory_descriptors.h
new file mode 100644
index 0000000..918a103
--- /dev/null
+++ b/components/messaging/ffa/libsp/include/ffa_memory_descriptors.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_INCLUDE_FFA_MEMORY_DESCRIPTORS_H_
+#define LIBSP_INCLUDE_FFA_MEMORY_DESCRIPTORS_H_
+
+/**
+ * @file ffa_memory_descriptor.h
+ * @brief The functions of this file were made to help building and parsing
+ * memory transaction descriptors.
+ */
+
+#include "ffa_api_types.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Helper buffer descriptor type for passing buffer pointer and length
+ * along the current buffer usage.
+ */
+struct ffa_mem_transaction_buffer {
+ void *buffer;
+ size_t length;
+ size_t used;
+};
+
+/**
+ * @brief Fills the buffer descriptor to use the area specified by the
+ * address and length parameters.
+ *
+ * @param[in] address The buffer address
+ * @param[in] length The buffer length
+ * @param[out] buffer The buffer descriptor
+ */
+void ffa_init_mem_transaction_buffer(void *address, size_t length,
+ struct ffa_mem_transaction_buffer *buffer);
+
+/**
+ * @brief Initializes the memory transaction descriptor (see Table 5.19) in
+ * the transaction buffer.
+ *
+ * @param[in] buffer The buffer descriptor
+ * @param[in] sender_id ID of the Owner endpoint
+ * @param[in] mem_region_attr The memory region attributes
+ * @param[in] flags The transaction flags
+ * @param[in] handle Memory region handle
+ * @param[in] tag Memory region tag
+ */
+void ffa_init_mem_transaction_desc(struct ffa_mem_transaction_buffer *buffer,
+ uint16_t sender_id, uint8_t mem_region_attr,
+ uint32_t flags, uint64_t handle,
+ uint64_t tag);
+
+/**
+ * @brief Queries the memory transaction descriptor (see Table 5.19) from
+ * the transaction buffer.
+ *
+ * @param[in] buffer The buffer descriptor
+ *
+ * @return Pointer to the transaction descriptor.
+ */
+const struct ffa_mem_transaction_desc *
+ffa_get_mem_transaction_desc(struct ffa_mem_transaction_buffer *buffer);
+
+/**
+ * @brief Reserves space for the memory access descriptors. In case of
+ * alternately adding memory access descriptors and adding memory
+ * regions to these descriptors the descriptor add will panic unless
+ * there was a sufficient amount of space reserved by this function.
+ *
+ * @param[in] buffer The buffer descriptor
+ * @param[in] count Memory access descriptor count to reserve
+ */
+void ffa_reserve_mem_access_desc(struct ffa_mem_transaction_buffer *buffer,
+ size_t count);
+
+/**
+ * @brief Adds a memory access descriptor (see Table 5.16).
+ *
+ * @param[in] buffer The buffer descriptor
+ * @param[in] endpoint_id 16-bit ID of endpoint to which the memory access
+ * permissions apply
+ * @param[in] mem_access_perm Permissions used to access a memory region
+ * @param[in] flags ABI specific flags
+ *
+ * @return Index of the newly added descriptor
+ */
+uint32_t ffa_add_mem_access_desc(struct ffa_mem_transaction_buffer *buffer,
+ uint16_t endpoint_id, uint8_t mem_access_perm,
+ uint8_t flags);
+
+/**
+ * @brief Queries the count of the memory access descriptors (see Table
+ * 5.16) from the transaction buffer.
+ *
+ * @param[in] buffer The buffer descriptor
+ *
+ * @return Descriptor count
+ */
+uint32_t
+ffa_get_mem_access_desc_count(struct ffa_mem_transaction_buffer *buffer);
+
+/**
+ * @brief Queries the memory access descriptor (see Table 5.16) from the
+ * transaction buffer.
+ *
+ * @param[in] buffer The buffer descriptor
+ * @param[in] descriptor_index The descriptor index
+ *
+ * @return Pointer to the memory access descriptor
+ */
+const struct ffa_mem_access_desc *
+ffa_get_mem_access_desc(struct ffa_mem_transaction_buffer *buffer,
+ uint32_t descriptor_index);
+
+/**
+ * @brief Adds a memory region to the transaction (see Table 5.13 and 5.14)
+ *
+ * @param[in] buffer The buffer descriptor
+ * @param[in] address The address of the region
+ * @param[in] page_count The size of the region in 4K pages
+ */
+void ffa_add_memory_region(struct ffa_mem_transaction_buffer *buffer,
+ const void *address, uint32_t page_count);
+
+/**
+ * @brief Queries the memory region descriptor (see Table 5.13 and 5.14)
+ * from the transaction buffer.
+ *
+ * @param[in] buffer The buffer descriptor
+ *
+ * @return Pointer to the memory region descriptor
+ */
+const struct ffa_composite_mem_region_desc *
+ffa_get_memory_region(struct ffa_mem_transaction_buffer *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_INCLUDE_FFA_MEMORY_DESCRIPTORS_H_ */