refactor: introduce the partition_pkg type
To be able to load partition packages with the format
of transfer lists, introduce intermediate representation,
which holds all the ranges relevant for the loading of the
SP.
The SP Package is translated into this intermediate
representation.
Subsequent patches do the same for the transfer list structure.
The mapping of SPs artefacts (i.e. partition manifest, and
area of boot information) are mapped and unmapped as necessary,
using the structure partition_pkg.
The memory ranges introduced so far:
- Partition Manager.
- SPs image.
- Hob range(though it remains unused).
Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: Ic9d0850202617a88070953f0f9075f78a1c8d7b6
diff --git a/inc/hf/boot_info.h b/inc/hf/boot_info.h
index 0be30e5..f1b0095 100644
--- a/inc/hf/boot_info.h
+++ b/inc/hf/boot_info.h
@@ -10,10 +10,10 @@
#include "hf/fdt.h"
#include "hf/ffa.h"
-#include "hf/sp_pkg.h"
+#include "hf/partition_pkg.h"
#define FFA_BOOT_INFO_SIG 0xFFAU
#define FFA_BOOT_INFO_VERSION 0x10001U
-bool ffa_boot_info_node(struct fdt_node *boot_info_node, vaddr_t pkg_address,
- struct sp_pkg_header *pkg_header);
+bool ffa_boot_info_node(struct fdt_node *boot_info_node,
+ struct partition_pkg *pkg);
diff --git a/inc/hf/partition_pkg.h b/inc/hf/partition_pkg.h
new file mode 100644
index 0000000..bdc03b8
--- /dev/null
+++ b/inc/hf/partition_pkg.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024 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/addr.h"
+#include "hf/boot_params.h"
+#include "hf/types.h"
+
+/**
+ * Aggregates all the necessary ranges needed for Hafnium to
+ * load an SP.
+ */
+struct partition_pkg {
+ /* Memory range for the partition manifest. */
+ struct mem_range pm;
+ /* Memory range for the image. */
+ struct mem_range img;
+ /* Memory range for the HOB list. - optional, if absent set to 0. */
+ struct mem_range hob;
+ /* Memory range for the FF-A boot info descriptors. */
+ struct mem_range boot_info;
+ /* Memory range for the totality of the package. */
+ struct mem_range total;
+};
+
+bool partition_pkg_init(struct mm_stage1_locked stage1_locked,
+ paddr_t pkg_start, struct partition_pkg *pkg,
+ struct mpool *ppool);
+
+void partition_pkg_deinit(struct mm_stage1_locked stage1_locked,
+ struct partition_pkg *pkg, struct mpool *ppool);
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 958caf9..c1a9ece 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -54,6 +54,7 @@
"cpu.c",
"hf_ipi.c",
"manifest.c",
+ "partition_pkg.c",
"sp_pkg.c",
"timer_mgmt.c",
"vcpu.c",
diff --git a/src/boot_info.c b/src/boot_info.c
index 72f8746..47ff26a 100644
--- a/src/boot_info.c
+++ b/src/boot_info.c
@@ -91,20 +91,24 @@
* Looks for the FF-A manifest boot information node, and writes the
* requested information into the boot info memory.
*/
-bool ffa_boot_info_node(struct fdt_node *boot_info_node, vaddr_t pkg_address,
- struct sp_pkg_header *pkg_header)
+bool ffa_boot_info_node(struct fdt_node *boot_info_node,
+ struct partition_pkg *pkg)
{
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);
+ struct ffa_boot_info_header *boot_info_header;
+ const size_t boot_info_size =
+ pa_difference(pkg->boot_info.begin, pkg->boot_info.end);
const size_t max_boot_info_desc_count =
(boot_info_size -
offsetof(struct ffa_boot_info_header, boot_info)) /
sizeof(struct ffa_boot_info_desc);
assert(boot_info_node != NULL);
- assert(pkg_header != NULL);
+ assert(pkg != NULL);
+
+ boot_info_header = (struct ffa_boot_info_header *)ptr_from_va(
+ va_from_pa(pkg->boot_info.begin));
+
assert(boot_info_header != NULL);
/*
@@ -127,21 +131,22 @@
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)));
+ ipaddr_t manifest_address = ipa_from_pa(pkg->pm.begin);
+ const uint32_t pm_size =
+ pa_difference(pkg->pm.begin, pkg->pm.end);
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);
+ boot_info_write_desc(boot_info_header,
+ FFA_BOOT_INFO_FLAG_CONTENT_FORMAT_ADDR,
+ true, FFA_BOOT_INFO_TYPE_ID_FDT, 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;
+ boot_info_header->info_blob_size += pm_size;
/*
* Flush the data cache in case partition initializes with
diff --git a/src/manifest.c b/src/manifest.c
index a77bba2..d20a0cf 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -27,7 +27,7 @@
#include "hf/mem_range.h"
#include "hf/mm.h"
#include "hf/mpool.h"
-#include "hf/sp_pkg.h"
+#include "hf/partition_pkg.h"
#include "hf/static_assert.h"
#include "hf/std.h"
@@ -1490,11 +1490,12 @@
{
enum manifest_return_code ret = MANIFEST_ERROR_NOT_COMPATIBLE;
uintpaddr_t load_address;
- struct sp_pkg_header header;
+ struct partition_pkg pkg;
struct fdt sp_fdt;
- vaddr_t pkg_start;
- vaddr_t manifest_address;
+ void *pm_ptr;
+ size_t pm_size;
struct fdt_node boot_info_node;
+ size_t total_mem_size;
/*
* This must have been hinted as being an FF-A partition,
@@ -1511,23 +1512,25 @@
assert(load_address != 0U);
- if (!sp_pkg_init(stage1_locked, pa_init(load_address), &header,
- ppool)) {
+ if (!partition_pkg_init(stage1_locked, pa_init(load_address), &pkg,
+ ppool)) {
return ret;
}
- pkg_start = va_init(load_address);
+ total_mem_size = pa_difference(pkg.total.begin, pkg.total.end);
if (vm_id != HF_PRIMARY_VM_ID &&
- sp_pkg_get_mem_size(&header) >= vm->secondary.mem_size) {
- dlog_error("Invalid package header or DT size.\n");
+ total_mem_size > (size_t)vm->secondary.mem_size) {
+ dlog_error("Partition pkg size %zx bigger than expected: %x\n",
+ total_mem_size, (uint32_t)vm->secondary.mem_size);
goto out;
}
- manifest_address = va_add(va_init(load_address), header.pm_offset);
- if (!fdt_init_from_ptr(&sp_fdt, ptr_from_va(manifest_address),
- header.pm_size)) {
- dlog_error("manifest.c: FDT failed validation.\n");
+ pm_ptr = ptr_from_va(va_from_pa(pkg.pm.begin));
+
+ pm_size = pa_difference(pkg.pm.begin, pkg.pm.end);
+ if (!fdt_init_from_ptr(&sp_fdt, pm_ptr, pm_size)) {
+ dlog_error("%s: FDT failed validation.\n", __func__);
goto out;
}
@@ -1539,15 +1542,27 @@
goto out;
}
- if (vm->partition.gp_register_num != DEFAULT_BOOT_GP_REGISTER) {
- if (header.version == SP_PKG_HEADER_VERSION_2 &&
- vm->partition.boot_info &&
- !ffa_boot_info_node(&boot_info_node, pkg_start, &header)) {
- dlog_error("Failed to process boot information.\n");
+ /* Partition subscribed to boot information. */
+ if (vm->partition.gp_register_num != DEFAULT_BOOT_GP_REGISTER &&
+ vm->partition.boot_info) {
+ /* Its package should have available space for it. */
+ if (pa_addr(pkg.boot_info.begin) == 0U) {
+ dlog_warning(
+ "Partition Package %s doesn't have boot info "
+ "space.\n",
+ vm->debug_name.data);
+ } else {
+ if (!ffa_boot_info_node(&boot_info_node, &pkg)) {
+ dlog_error(
+ "Failed to process boot "
+ "information.\n");
+ }
}
}
+
out:
- sp_pkg_deinit(stage1_locked, pkg_start, &header, ppool);
+ partition_pkg_deinit(stage1_locked, &pkg, ppool);
+
return ret;
}
diff --git a/src/partition_pkg.c b/src/partition_pkg.c
new file mode 100644
index 0000000..093de43
--- /dev/null
+++ b/src/partition_pkg.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2024 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/partition_pkg.h"
+
+#include <stdint.h>
+
+#include "hf/arch/std.h"
+
+#include "hf/addr.h"
+#include "hf/check.h"
+#include "hf/dlog.h"
+#include "hf/mm.h"
+#include "hf/sp_pkg.h"
+#include "hf/std.h"
+#include "hf/transfer_list.h"
+
+static void dump_partition_package(struct partition_pkg *pkg)
+{
+ dlog_verbose("%s: total %lx %lx\n", __func__, pa_addr(pkg->total.begin),
+ pa_addr(pkg->total.end));
+ dlog_verbose("%s: pm: %lx %lx\n", __func__, pa_addr(pkg->pm.begin),
+ pa_addr(pkg->pm.end));
+ dlog_verbose("%s: img: %lx %lx\n", __func__, pa_addr(pkg->img.begin),
+ pa_addr(pkg->img.end));
+ dlog_verbose("%s: boot_info: %lx %lx\n", __func__,
+ pa_addr(pkg->boot_info.begin),
+ pa_addr(pkg->boot_info.end));
+ if (mem_range_is_valid(pkg->hob)) {
+ dlog_verbose("%s: hob %lx %lx\n", __func__,
+ pa_addr(pkg->hob.begin), pa_addr(pkg->hob.end));
+ }
+}
+
+static bool partition_pkg_from_sp_pkg(struct mm_stage1_locked stage1_locked,
+ paddr_t pkg_start,
+ struct partition_pkg *pkg,
+ struct mpool *ppool)
+{
+ struct sp_pkg_header header;
+ bool ret = sp_pkg_init(stage1_locked, pkg_start, &header, ppool);
+ size_t total_mem_size = sp_pkg_get_mem_size(&header);
+
+ pkg->total.begin = pkg_start;
+ pkg->total.end = pa_add(pkg_start, total_mem_size);
+
+ pkg->pm.begin = pa_add(pkg_start, header.pm_offset);
+ pkg->pm.end = pa_add(pkg->pm.begin, header.pm_size);
+
+ pkg->img.begin = pa_add(pkg_start, header.img_offset);
+ pkg->img.end = pa_add(pkg->img.begin, header.img_size);
+
+ /*
+ * Repurpose the first page of the SP Package.
+ * FF-A boot info will overwrite the package, but it doesn't
+ * matter at this stage, given Hafnium already parsed it.
+ */
+ pkg->boot_info.begin = pkg_start;
+ pkg->boot_info.end = pa_add(pkg_start, header.pm_offset);
+
+ /* HOB section doesn't exist in the SP Pkg type. */
+ pkg->hob.begin = pa_init(0);
+ pkg->hob.end = pa_init(0);
+
+ dump_partition_package(pkg);
+
+ /* Map the whole package as RO. */
+ CHECK(mm_identity_map(stage1_locked, pkg->total.begin, pkg->total.end,
+ MM_MODE_R, ppool) != NULL);
+
+ return ret;
+}
+
+bool partition_pkg_init(struct mm_stage1_locked stage1_locked,
+ paddr_t pkg_start, struct partition_pkg *pkg,
+ struct mpool *ppool)
+{
+ bool ret = false;
+ paddr_t pkg_first_page = pa_add(pkg_start, PAGE_SIZE);
+ uint32_t *magic;
+ void *mapped_ptr;
+
+ /* Firstly, map a single page to be able to read package header. */
+ mapped_ptr = mm_identity_map(stage1_locked, pkg_start, pkg_first_page,
+ MM_MODE_R, ppool);
+ assert(mapped_ptr != NULL);
+ assert(pkg != NULL);
+
+ magic = (uint32_t *)mapped_ptr;
+
+ switch (*magic) {
+ case SP_PKG_HEADER_MAGIC:
+ /*
+ * Leave memory mapped in case it succeeded, to be cleared
+ * later.
+ */
+ if (!partition_pkg_from_sp_pkg(stage1_locked, pkg_start, pkg,
+ ppool)) {
+ goto out;
+ }
+ break;
+ default:
+ dlog_error("%s: invalid secure partition package %x @ %lx\n",
+ __func__, *magic, (uint64_t)magic);
+ goto out;
+ }
+
+ dump_partition_package(pkg);
+
+ /**
+ * The total memory range should encompass the remaining.
+ * Assert that none of the memory ranges are out of bounds.
+ */
+ assert(mem_range_contains_range(pkg->total, pkg->img));
+ assert(mem_range_contains_range(pkg->total, pkg->pm));
+ assert(mem_range_contains_range(pkg->total, pkg->boot_info));
+ assert(!mem_range_is_valid(pkg->hob) ||
+ mem_range_contains_range(pkg->total, pkg->hob));
+
+ /* Map Boot info section as RW. */
+ if (pa_addr(pkg->boot_info.begin) != 0U &&
+ pa_addr(pkg->boot_info.end) != 0U) {
+ CHECK(mm_identity_map(stage1_locked, pkg->boot_info.begin,
+ pkg->boot_info.end, MM_MODE_R | MM_MODE_W,
+ ppool) != NULL);
+ }
+
+ ret = true;
+
+out:
+ /* If failing unmap the memory. */
+ if (!ret) {
+ CHECK(mm_unmap(stage1_locked, pkg_start, pkg_first_page,
+ ppool));
+ }
+
+ return ret;
+}
+
+void partition_pkg_deinit(struct mm_stage1_locked stage1_locked,
+ struct partition_pkg *pkg, struct mpool *ppool)
+{
+ CHECK(mm_unmap(stage1_locked, pkg->total.begin, pkg->total.end, ppool));
+}
diff --git a/src/sp_pkg.c b/src/sp_pkg.c
index 7f432dc..4c3167d 100644
--- a/src/sp_pkg.c
+++ b/src/sp_pkg.c
@@ -72,9 +72,10 @@
paddr_t pkg_start, struct sp_pkg_header *header,
struct mpool *ppool)
{
- paddr_t pkg_end = pa_add(pkg_start, PAGE_SIZE);
-
assert(header != NULL);
+ (void)pkg_start;
+ (void)ppool;
+ (void)stage1_locked;
if (header->pm_offset % PAGE_SIZE != 0 ||
header->img_offset % PAGE_SIZE != 0) {
@@ -99,22 +100,6 @@
return false;
}
- /*
- * Remap section up to pm as RW, to allow for writing of boot info
- * descriptors, if the SP specified boot info in its manifest.
- */
- if (header->pm_offset > PAGE_SIZE) {
- pkg_end = pa_add(pkg_start, header->pm_offset);
- }
-
- CHECK(mm_identity_map(stage1_locked, pkg_start, pkg_end,
- MM_MODE_R | MM_MODE_W, ppool) != NULL);
-
- /* Map partition manifest as read-only. */
- CHECK(mm_identity_map(stage1_locked, pkg_end,
- pa_add(pkg_end, header->pm_size), MM_MODE_R,
- ppool));
-
return true;
}
@@ -126,22 +111,14 @@
bool sp_pkg_init(struct mm_stage1_locked stage1_locked, paddr_t pkg_start,
struct sp_pkg_header *header, struct mpool *ppool)
{
- paddr_t pkg_end = pa_add(pkg_start, PAGE_SIZE);
- void *pkg;
-
- /* Firstly, map a single page of package header. */
- pkg = mm_identity_map(stage1_locked, pkg_start, pkg_end, MM_MODE_R,
- ppool);
- assert(pkg != NULL);
-
- memcpy_s(header, sizeof(struct sp_pkg_header), pkg,
+ /*
+ * Assumes the page the first page of the package, has been mapped
+ * already.
+ */
+ memcpy_s(header, sizeof(struct sp_pkg_header),
+ ptr_from_va(va_from_pa(pkg_start)),
sizeof(struct sp_pkg_header));
- if (header->magic != SP_PKG_HEADER_MAGIC) {
- dlog_error("Invalid package magic.\n");
- goto exit_unmap;
- }
-
switch (header->version) {
case SP_PKG_HEADER_VERSION_1:
if (sp_pkg_init_v1(stage1_locked, pkg_start, header, ppool)) {
@@ -154,26 +131,9 @@
}
break;
default:
- dlog_error("Unrecognized Partition Pkg format.\n");
+ dlog_error("%s: Unrecognized Secure Partition Pkg format.\n",
+ __func__);
}
-exit_unmap:
- CHECK(mm_unmap(stage1_locked, pkg_start, pkg_end, ppool));
-
return false;
}
-
-/**
- * Unmap SP Pkg from Hafnium's address space.
- */
-void sp_pkg_deinit(struct mm_stage1_locked stage1_locked, vaddr_t pkg_start,
- struct sp_pkg_header *header, struct mpool *ppool)
-{
- paddr_t to_unmap_end;
-
- to_unmap_end = pa_from_va(
- va_add(pkg_start, header->pm_offset + header->pm_size));
-
- CHECK(mm_unmap(stage1_locked, pa_from_va(pkg_start), to_unmap_end,
- ppool));
-}