feat(boot): writing boot info to partition's memory
Implemented writing VM's boot info:
- Setting boot info header and descriptors array.
- Copying info if it has been listed in the partition's manifest.
- Providing the boot info memory address to partition in the GP register
specified in the partition's manifest.
Change-Id: I39248811289c6b8c4f4cac6080c600ce73cad993
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/hf/sp_pkg.h b/inc/hf/sp_pkg.h
index 5e5f545..0ae763c 100644
--- a/inc/hf/sp_pkg.h
+++ b/inc/hf/sp_pkg.h
@@ -41,6 +41,12 @@
return (size_t)(sp_pkg->img_offset + sp_pkg->img_size);
}
+/** Get the size of the boot information descriptors section. */
+static inline size_t sp_pkg_get_boot_info_size(struct sp_pkg_header *sp_pkg)
+{
+ return sp_pkg->pm_offset;
+}
+
bool sp_pkg_init(struct mm_stage1_locked stage1_locked, paddr_t pkg_start,
struct sp_pkg_header *header, struct mpool *ppool);
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 82428de..53651d4 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -1440,10 +1440,10 @@
current_vm_locked.vm->id,
current_vm_locked.vm->boot_order);
- if (current_vm_locked.vm->next_boot != NULL) {
+ vm_next = current_vm_locked.vm->next_boot;
+ if (vm_next != NULL) {
/* Refer FF-A v1.1 Beta0 section 7.5 Rule 2. */
current->state = VCPU_STATE_WAITING;
- vm_next = current_vm_locked.vm->next_boot;
CHECK(vm_next->initialized == false);
*next = vm_get_vcpu(vm_next, vcpu_index(current));
arch_regs_reset(*next);
@@ -1451,6 +1451,8 @@
(*next)->state = VCPU_STATE_RUNNING;
(*next)->regs_available = false;
+ vm_set_boot_info_gp_reg(vm_next, (*next));
+
ret = true;
goto out;
}
diff --git a/src/boot_info.c b/src/boot_info.c
index 2b65dee..89611ad 100644
--- a/src/boot_info.c
+++ b/src/boot_info.c
@@ -10,12 +10,84 @@
#include "hf/assert.h"
#include "hf/dlog.h"
+#include "hf/ffa.h"
#include "hf/memiter.h"
#include "hf/std.h"
#include "vmapi/hf/ffa.h"
/**
+ * Initializes the ffa_boot_info_header in accordance to the specification.
+ */
+static void ffa_boot_info_header_init(struct ffa_boot_info_header *header,
+ size_t blob_size)
+{
+ assert(header != NULL);
+ assert(blob_size != 0U);
+
+ header->signature = FFA_BOOT_INFO_SIG;
+ header->version = FFA_BOOT_INFO_VERSION;
+ header->info_blob_size = blob_size;
+ header->desc_size = sizeof(struct ffa_boot_info_desc);
+ header->desc_count = 0;
+ header->desc_offset =
+ (uint32_t)offsetof(struct ffa_boot_info_header, boot_info);
+ header->reserved = 0U;
+}
+
+static void ffa_boot_info_desc_init(struct ffa_boot_info_desc *info_desc,
+ uint8_t content_format, bool std_type,
+ uint8_t type_id, uint32_t size,
+ uint64_t content)
+{
+ assert(info_desc != NULL);
+
+ /*
+ * Init name size with 0s, as it is currently unused. Data can be
+ * identified checking the type field.
+ */
+ memset_s(info_desc, FFA_BOOT_INFO_NAME_LEN, 0, FFA_BOOT_INFO_NAME_LEN);
+
+ info_desc->type = std_type == true ? FFA_BOOT_INFO_TYPE_STD
+ : FFA_BOOT_INFO_TYPE_IMPDEF;
+ info_desc->type <<= FFA_BOOT_INFO_TYPE_SHIFT;
+ info_desc->type |= (type_id & FFA_BOOT_INFO_TYPE_ID_MASK);
+
+ info_desc->reserved = 0U;
+ info_desc->flags =
+ ((content_format << FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_SHIFT) &
+ FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_MASK);
+ info_desc->size = size;
+ info_desc->content = content;
+}
+
+/*
+ * Write initialization parameter to the boot info descriptor array.
+ */
+static void boot_info_write_desc(struct ffa_boot_info_header *header,
+ uint8_t content_format, bool std_type,
+ uint8_t type_id, uint32_t size,
+ uint64_t content,
+ const size_t max_info_desc_count)
+{
+ assert(header != NULL);
+
+ /* Check that writing the data won't surpass the blob memory limit. */
+ if (header->desc_count >= max_info_desc_count) {
+ dlog_error(
+ "Boot info memory is full. No space for a "
+ "descriptor.\n");
+ return;
+ }
+
+ ffa_boot_info_desc_init(&header->boot_info[header->desc_count],
+ content_format, std_type, type_id, size,
+ content);
+
+ header->desc_count++;
+}
+
+/**
* Looks for the FF-A manifest boot information node, and writes the
* requested information into the boot info memory.
*/
@@ -23,12 +95,26 @@
struct sp_pkg_header *pkg_header)
{
struct memiter data;
+ struct ffa_boot_info_header *boot_info_header =
+ (struct ffa_boot_info_header *)ptr_from_va(pkg_address);
+ const size_t boot_info_size = sp_pkg_get_boot_info_size(pkg_header);
+ const size_t max_boot_info_desc_count =
+ boot_info_size / sizeof(struct ffa_boot_info_desc);
assert(boot_info_node != NULL);
assert(pkg_header != NULL);
+ assert(boot_info_header != NULL);
- (void)pkg_address;
- (void)pkg_header;
+ /*
+ * FF-A v1.1 EAC0 specification states the region for the boot info
+ * descriptors, and the contents of the boot info shall be contiguous.
+ * Together they constitute the boot info blob. The are for the boot
+ * info blob is allocated in the SP's respective package.
+ * Retrieve from the SP package the size of the region for the boot info
+ * descriptors. The size of boot info contents to be incremented,
+ * depending on the info specified in the partition's FF-A manifest.
+ */
+ ffa_boot_info_header_init(boot_info_header, boot_info_size);
if (!fdt_is_compatible(boot_info_node, "arm,ffa-manifest-boot-info")) {
dlog_verbose("The node 'boot-info' is not compatible.\n");
@@ -39,7 +125,28 @@
if (fdt_read_property(boot_info_node, "ffa_manifest", &data) &&
memiter_size(&data) == 0U) {
+ ipaddr_t manifest_address = ipa_init(
+ va_addr(va_add(pkg_address, pkg_header->pm_offset)));
+
dlog_verbose(" FF-A Manifest\n");
+ boot_info_write_desc(
+ boot_info_header,
+ FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR, true,
+ FFA_BOOT_INFO_TYPE_ID_FDT, pkg_header->pm_size,
+ ipa_addr(manifest_address), max_boot_info_desc_count);
+
+ /*
+ * Incrementing the size of the boot information blob with the
+ * size of the partition's manifest.
+ */
+ boot_info_header->info_blob_size += pkg_header->pm_size;
+
+ /*
+ * Flush the data cache in case partition initializes with
+ * caches disabled.
+ */
+ arch_mm_flush_dcache((void *)boot_info_header,
+ boot_info_header->info_blob_size);
return true;
}
diff --git a/src/main.c b/src/main.c
index 32e0476..45624e5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -42,5 +42,7 @@
/* Initialize SRI for running core. */
plat_ffa_sri_init(c);
+ vm_set_boot_info_gp_reg(first_boot, vcpu);
+
return vcpu;
}
diff --git a/src/vm.c b/src/vm.c
index aa25fb8..37a4541 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -920,3 +920,16 @@
{
return vm_locked.vm->notifications.npi_injected;
}
+
+/**
+ * Sets the designated GP register that the VM expects to receive the boot
+ * info's address.
+ */
+void vm_set_boot_info_gp_reg(struct vm *vm, struct vcpu *vcpu)
+{
+ if (!vm->initialized && vm->boot_info.blob_addr.ipa != 0U) {
+ arch_regs_set_gp_reg(&vcpu->regs,
+ ipa_addr(vm->boot_info.blob_addr),
+ vm->boot_info.gp_register_num);
+ }
+}