feat: FF-A v1.0 resources

Created header for FF-A v1.0 structures that we are currently providing
backwards compatibility for. This includes memory sharing structures and
FF-A partition info.

Change-Id: I132b8e97233f610666933c04f33dd9e9b08279eb
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/vmapi/hf/ffa.h b/inc/vmapi/hf/ffa.h
index 92cf7bc..533dcc4 100644
--- a/inc/vmapi/hf/ffa.h
+++ b/inc/vmapi/hf/ffa.h
@@ -579,26 +579,6 @@
 	struct ffa_uuid uuid;
 };
 
-/**
- * Bits[31:3] of partition properties must be zero for FF-A v1.0.
- * This corresponds to table 8.25 "Partition information descriptor"
- * in DEN0077A FF-A 1.0 REL specification.
- */
-#define FFA_PARTITION_v1_0_RES_MASK (~(UINT32_C(0x7)))
-
-/**
- * Create a struct for the "Partition information descriptor" defined for v1.0
- * which can be returned to v1.0 endpoints.
- * This corresponds to table 8.25 "Partition information descriptor"
- * in DEN0077A FF-A 1.0 REL specification.
- */
-
-struct ffa_partition_info_v1_0 {
-	ffa_vm_id_t vm_id;
-	ffa_vcpu_count_t vcpu_count;
-	ffa_partition_properties_t properties;
-};
-
 /** Length in bytes of the name in boot information descriptor. */
 #define FFA_BOOT_INFO_NAME_LEN 16
 
@@ -1008,6 +988,10 @@
 	return sizeof(struct ffa_mem_relinquish) + sizeof(ffa_vm_id_t);
 }
 
+void ffa_copy_memory_region_constituents(
+	struct ffa_memory_region_constituent *dest,
+	const struct ffa_memory_region_constituent *src);
+
 /**
  * Endpoint RX/TX descriptor, as defined by Table 13.27 in FF-A v1.1 EAC0.
  * It's used by the Hypervisor to describe the RX/TX buffers mapped by a VM
diff --git a/inc/vmapi/hf/ffa_v1_0.h b/inc/vmapi/hf/ffa_v1_0.h
new file mode 100644
index 0000000..2f64202
--- /dev/null
+++ b/inc/vmapi/hf/ffa_v1_0.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2023 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#pragma once
+
+#include "hf/ffa.h"
+#include "hf/types.h"
+
+/**
+ * Bits[31:3] of partition properties must be zero for FF-A v1.0.
+ * This corresponds to table 8.25 "Partition information descriptor"
+ * in DEN0077A FF-A 1.0 REL specification.
+ */
+#define FFA_PARTITION_v1_0_RES_MASK (~(UINT32_C(0x7)))
+
+/**
+ * Create a struct for the "Partition information descriptor" defined for v1.0
+ * which can be returned to v1.0 endpoints.
+ * This corresponds to table 8.25 "Partition information descriptor"
+ * in DEN0077A FF-A 1.0 REL specification.
+ */
+struct ffa_partition_info_v1_0 {
+	ffa_vm_id_t vm_id;
+	ffa_vcpu_count_t vcpu_count;
+	ffa_partition_properties_t properties;
+};
+
+/**
+ * Information about a set of pages which are being shared. This corresponds to
+ * table 45 of the FF-A 1.0 EAC specification, "Lend, donate or share memory
+ * transaction descriptor". Note that it is also used for retrieve requests and
+ * responses.
+ */
+struct ffa_memory_region_v1_0 {
+	/**
+	 * The ID of the VM which originally sent the memory region, i.e. the
+	 * owner.
+	 */
+	ffa_vm_id_t sender;
+	uint8_t attributes;
+	/** Reserved field, must be 0. */
+	uint8_t reserved_0;
+	/** Flags to control behaviour of the transaction. */
+	ffa_memory_region_flags_t flags;
+	ffa_memory_handle_t handle;
+	/**
+	 * An implementation defined value associated with the receiver and the
+	 * memory region.
+	 */
+	uint64_t tag;
+	/** Reserved field, must be 0. */
+	uint32_t reserved_1;
+	/**
+	 * The number of `ffa_memory_access` entries included in this
+	 * transaction.
+	 */
+	uint32_t receiver_count;
+	/**
+	 * An array of `receiver_count` endpoint memory access descriptors.
+	 * Each one specifies a memory region offset, an endpoint and the
+	 * attributes with which this memory region should be mapped in that
+	 * endpoint's page table.
+	 */
+	struct ffa_memory_access receivers[];
+};
+
+/**
+ * Gets the `ffa_composite_memory_region` for the given receiver from an
+ * `ffa_memory_region`, or NULL if it is not valid.
+ */
+static inline struct ffa_composite_memory_region *
+ffa_memory_region_get_composite_v1_0(
+	struct ffa_memory_region_v1_0 *memory_region, uint32_t receiver_index)
+{
+	uint32_t offset = memory_region->receivers[receiver_index]
+				  .composite_memory_region_offset;
+
+	if (offset == 0) {
+		return NULL;
+	}
+
+	return (struct ffa_composite_memory_region *)((uint8_t *)memory_region +
+						      offset);
+}
+
+uint32_t ffa_memory_region_init_v1_0(
+	struct ffa_memory_region_v1_0 *memory_region,
+	size_t memory_region_max_size, ffa_vm_id_t sender,
+	struct ffa_memory_access receivers[], uint32_t receiver_count,
+	const struct ffa_memory_region_constituent constituents[],
+	uint32_t constituent_count, uint32_t tag,
+	ffa_memory_region_flags_t flags, enum ffa_memory_type type,
+	enum ffa_memory_cacheability cacheability,
+	enum ffa_memory_shareability shareability, uint32_t *total_length,
+	uint32_t *fragment_length);
diff --git a/src/api.c b/src/api.c
index 3156fe7..f65bb10 100644
--- a/src/api.c
+++ b/src/api.c
@@ -30,6 +30,7 @@
 
 #include "vmapi/hf/call.h"
 #include "vmapi/hf/ffa.h"
+#include "vmapi/hf/ffa_v1_0.h"
 
 static_assert(sizeof(struct ffa_partition_info_v1_0) == 8,
 	      "Partition information descriptor size doesn't match the one in "
diff --git a/test/vmapi/ffa_secure_partitions/setup_and_discovery.c b/test/vmapi/ffa_secure_partitions/setup_and_discovery.c
index 3459123..76305af 100644
--- a/test/vmapi/ffa_secure_partitions/setup_and_discovery.c
+++ b/test/vmapi/ffa_secure_partitions/setup_and_discovery.c
@@ -8,6 +8,7 @@
 
 #include "hf/dlog.h"
 #include "hf/ffa.h"
+#include "hf/ffa_v1_0.h"
 
 #include "vmapi/hf/call.h"
 
diff --git a/test/vmapi/primary_with_secondaries/no_services.c b/test/vmapi/primary_with_secondaries/no_services.c
index 6ce646e..de6cd53 100644
--- a/test/vmapi/primary_with_secondaries/no_services.c
+++ b/test/vmapi/primary_with_secondaries/no_services.c
@@ -9,6 +9,7 @@
 #include <stdalign.h>
 #include <stdint.h>
 
+#include "hf/ffa_v1_0.h"
 #include "hf/mm.h"
 #include "hf/static_assert.h"
 #include "hf/std.h"
diff --git a/vmlib/BUILD.gn b/vmlib/BUILD.gn
index fd3a621..9024a15 100644
--- a/vmlib/BUILD.gn
+++ b/vmlib/BUILD.gn
@@ -7,5 +7,8 @@
 import("//build/toolchain/platform.gni")
 
 source_set("vmlib") {
-  sources = [ "ffa.c" ]
+  sources = [
+    "ffa.c",
+    "ffa_v1_0.c",
+  ]
 }
diff --git a/vmlib/ffa.c b/vmlib/ffa.c
index cf7f4cc..c0c4d91 100644
--- a/vmlib/ffa.c
+++ b/vmlib/ffa.c
@@ -10,6 +10,7 @@
 
 #include <stddef.h>
 
+#include "hf/ffa_v1_0.h"
 #include "hf/types.h"
 
 #if defined(__linux__) && defined(__KERNEL__)
@@ -25,7 +26,7 @@
 	      "struct ffa_endpoint_rx_tx_descriptor must be a multiple of 16 "
 	      "bytes long.");
 
-static void ffa_copy_memory_region_constituents(
+void ffa_copy_memory_region_constituents(
 	struct ffa_memory_region_constituent *dest,
 	const struct ffa_memory_region_constituent *src)
 {
diff --git a/vmlib/ffa_v1_0.c b/vmlib/ffa_v1_0.c
new file mode 100644
index 0000000..d6b6b14
--- /dev/null
+++ b/vmlib/ffa_v1_0.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2022 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include "hf/ffa_v1_0.h"
+
+#include <stddef.h>
+
+#include "hf/ffa.h"
+#include "hf/types.h"
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#else
+#include "hf/static_assert.h"
+#include "hf/std.h"
+#endif
+
+/**
+ * Initialises the header of the given `ffa_memory_region_v1_0`, not
+ * including the composite memory region offset.
+ */
+static void ffa_memory_region_init_header_v1_0(
+	struct ffa_memory_region_v1_0 *memory_region, ffa_vm_id_t sender,
+	ffa_memory_attributes_t attributes, ffa_memory_region_flags_t flags,
+	ffa_memory_handle_t handle, uint32_t tag, uint32_t receiver_count)
+{
+	memory_region->sender = sender;
+	memory_region->attributes = attributes;
+	memory_region->reserved_0 = 0;
+	memory_region->flags = flags;
+	memory_region->handle = handle;
+	memory_region->tag = tag;
+	memory_region->reserved_1 = 0;
+	memory_region->receiver_count = receiver_count;
+}
+
+/**
+ * Copies as many as possible of the given constituents to the respective
+ * memory region and sets the respective offset.
+ *
+ * Returns the number of constituents remaining which wouldn't fit, and (via
+ * return parameters) the size in bytes of the first fragment of data copied to
+ * `memory_region` (attributes, constituents and memory region header size), and
+ * the total size of the memory sharing message including all constituents.
+ */
+static uint32_t ffa_memory_region_init_constituents_v1_0(
+	struct ffa_memory_region_v1_0 *memory_region,
+	size_t memory_region_max_size,
+	const struct ffa_memory_region_constituent constituents[],
+	uint32_t constituent_count, uint32_t *total_length,
+	uint32_t *fragment_length)
+{
+	struct ffa_composite_memory_region *composite_memory_region;
+	uint32_t fragment_max_constituents;
+	uint32_t constituents_offset;
+	uint32_t count_to_copy;
+	uint32_t i;
+
+	/*
+	 * Note that `sizeof(struct_ffa_memory_region)` and `sizeof(struct
+	 * ffa_memory_access)` must both be multiples of 16 (as verified by the
+	 * asserts in `ffa_memory.c`, so it is guaranteed that the offset we
+	 * calculate here is aligned to a 64-bit boundary and so 64-bit values
+	 * can be copied without alignment faults.
+	 * If there are multiple receiver endpoints, their respective access
+	 * structure should point to the same offset value.
+	 */
+	for (i = 0U; i < memory_region->receiver_count; i++) {
+		memory_region->receivers[i].composite_memory_region_offset =
+			sizeof(struct ffa_memory_region) +
+			memory_region->receiver_count *
+				sizeof(struct ffa_memory_access);
+	}
+
+	composite_memory_region =
+		ffa_memory_region_get_composite_v1_0(memory_region, 0);
+	composite_memory_region->page_count = 0;
+	composite_memory_region->constituent_count = constituent_count;
+	composite_memory_region->reserved_0 = 0;
+
+	constituents_offset =
+		memory_region->receivers[0].composite_memory_region_offset +
+		sizeof(struct ffa_composite_memory_region);
+	fragment_max_constituents =
+		(memory_region_max_size - constituents_offset) /
+		sizeof(struct ffa_memory_region_constituent);
+
+	count_to_copy = constituent_count;
+	if (count_to_copy > fragment_max_constituents) {
+		count_to_copy = fragment_max_constituents;
+	}
+
+	for (i = 0U; i < constituent_count; i++) {
+		if (i < count_to_copy) {
+			ffa_copy_memory_region_constituents(
+				&composite_memory_region->constituents[i],
+				&constituents[i]);
+		}
+		composite_memory_region->page_count +=
+			constituents[i].page_count;
+	}
+
+	if (total_length != NULL) {
+		*total_length =
+			constituents_offset +
+			composite_memory_region->constituent_count *
+				sizeof(struct ffa_memory_region_constituent);
+	}
+	if (fragment_length != NULL) {
+		*fragment_length =
+			constituents_offset +
+			count_to_copy *
+				sizeof(struct ffa_memory_region_constituent);
+	}
+
+	return composite_memory_region->constituent_count - count_to_copy;
+}
+
+uint32_t ffa_memory_region_init_v1_0(
+	struct ffa_memory_region_v1_0 *memory_region,
+	size_t memory_region_max_size, ffa_vm_id_t sender,
+	struct ffa_memory_access receivers[], uint32_t receiver_count,
+	const struct ffa_memory_region_constituent constituents[],
+	uint32_t constituent_count, uint32_t tag,
+	ffa_memory_region_flags_t flags, enum ffa_memory_type type,
+	enum ffa_memory_cacheability cacheability,
+	enum ffa_memory_shareability shareability, uint32_t *total_length,
+	uint32_t *fragment_length)
+{
+	ffa_memory_attributes_t attributes = 0;
+
+	/* Set memory region's page attributes. */
+	ffa_set_memory_type_attr(&attributes, type);
+	ffa_set_memory_cacheability_attr(&attributes, cacheability);
+	ffa_set_memory_shareability_attr(&attributes, shareability);
+
+	ffa_memory_region_init_header_v1_0(memory_region, sender, attributes,
+					   flags, 0, tag, receiver_count);
+
+#if defined(__linux__) && defined(__KERNEL__)
+	memcpy(memory_region->receivers, receivers,
+	       receiver_count * sizeof(struct ffa_memory_access));
+#else
+	memcpy_s(memory_region->receivers,
+		 MAX_MEM_SHARE_RECIPIENTS * sizeof(struct ffa_memory_access),
+		 receivers, receiver_count * sizeof(struct ffa_memory_access));
+#endif
+
+	return ffa_memory_region_init_constituents_v1_0(
+		memory_region, memory_region_max_size, constituents,
+		constituent_count, total_length, fragment_length);
+}