refactor: added "sp_pkg" module
Added module "sp_pkg" to init and help operate the SP pkg, such that
hafnium can cleanly retrieve the FF-A manifest's and the boot info's
base address.
Change-Id: Ieb6925c487a4dac9b460353ba82a00d670176037
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 5ae41fd..f084cab 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -51,6 +51,7 @@
"cpu.c",
"ffa_memory.c",
"manifest.c",
+ "sp_pkg.c",
"vcpu.c",
]
diff --git a/src/manifest.c b/src/manifest.c
index 502d412..96396e4 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -12,6 +12,7 @@
#include "hf/assert.h"
#include "hf/check.h"
#include "hf/dlog.h"
+#include "hf/sp_pkg.h"
#include "hf/static_assert.h"
#include "hf/std.h"
@@ -756,92 +757,63 @@
struct manifest_vm *vm, ffa_vm_id_t vm_id, struct mpool *ppool)
{
enum manifest_return_code ret = MANIFEST_ERROR_NOT_COMPATIBLE;
- uintpaddr_t sp_pkg_addr;
- paddr_t sp_pkg_start;
- paddr_t sp_pkg_end;
- struct sp_pkg_header *sp_pkg;
- size_t sp_header_dtb_size;
- paddr_t sp_dtb_addr;
+ uintpaddr_t load_address;
+ struct sp_pkg_header header;
struct fdt sp_fdt;
+ vaddr_t pkg_start;
+ vaddr_t manifest_address;
/*
* This must have been hinted as being an FF-A partition,
* return straight with failure if this is not the case.
*/
if (!vm->is_ffa_partition) {
+ return ret;
+ }
+
+ TRY(read_uint64(node, "load_address", &load_address));
+ if (!is_aligned(load_address, PAGE_SIZE)) {
return MANIFEST_ERROR_NOT_COMPATIBLE;
}
- TRY(read_uint64(node, "load_address", &sp_pkg_addr));
- if (!is_aligned(sp_pkg_addr, PAGE_SIZE)) {
- return MANIFEST_ERROR_NOT_COMPATIBLE;
+ assert(load_address != 0U);
+
+ if (!sp_pkg_init(stage1_locked, pa_init(load_address), &header,
+ ppool)) {
+ return ret;
}
- /* Map top of package as a single page to extract the header */
- sp_pkg_start = pa_init(sp_pkg_addr);
- sp_pkg_end = pa_add(sp_pkg_start, PAGE_SIZE);
- sp_pkg = mm_identity_map(stage1_locked, sp_pkg_start,
- pa_add(sp_pkg_start, PAGE_SIZE), MM_MODE_R,
- ppool);
- CHECK(sp_pkg != NULL);
+ pkg_start = va_init(load_address);
- dlog_verbose("Package load address %#x\n", sp_pkg_addr);
-
- if (sp_pkg->magic != SP_PKG_HEADER_MAGIC) {
- dlog_error("Invalid package magic.\n");
- goto exit_unmap;
- }
-
- if (sp_pkg->version != SP_PKG_HEADER_VERSION) {
- dlog_error("Invalid package version.\n");
- goto exit_unmap;
- }
-
- /* TODO: Do not map 2 pages. */
- sp_header_dtb_size = align_up(sp_pkg->pm_size, 2 * PAGE_SIZE);
-
- if ((vm_id != HF_PRIMARY_VM_ID) &&
- (sp_header_dtb_size >= vm->secondary.mem_size)) {
+ 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");
- goto exit_unmap;
+ goto out;
}
- if (sp_header_dtb_size > PAGE_SIZE) {
- /* Map remainder of header + DTB */
- sp_pkg_end = pa_add(sp_pkg_start, sp_header_dtb_size);
-
- sp_pkg = mm_identity_map(stage1_locked, sp_pkg_start,
- sp_pkg_end, MM_MODE_R, ppool);
- CHECK(sp_pkg != NULL);
- }
-
- sp_dtb_addr = pa_add(sp_pkg_start, sp_pkg->pm_offset);
-
- /* Since the address is from pa_addr allow the cast */
- // NOLINTNEXTLINE(performance-no-int-to-ptr)
- if (!fdt_init_from_ptr(&sp_fdt, (void *)pa_addr(sp_dtb_addr),
- sp_pkg->pm_size)) {
+ 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("FDT failed validation.\n");
- goto exit_unmap;
+ goto out;
}
ret = parse_ffa_manifest(&sp_fdt, vm);
if (ret != MANIFEST_SUCCESS) {
dlog_error("Error parsing partition manifest: %s.\n",
manifest_strerror(ret));
- goto exit_unmap;
+ goto out;
}
- if (vm->partition.load_addr != sp_pkg_addr) {
+ if (vm->partition.load_addr != load_address) {
dlog_warning(
"Partition's load address at its manifest differs"
" from specified in partition's package.\n");
- vm->partition.load_addr = sp_pkg_addr;
+ vm->partition.load_addr = load_address;
}
-exit_unmap:
- CHECK(mm_unmap(stage1_locked, sp_pkg_start, sp_pkg_end, ppool));
-
+out:
+ sp_pkg_deinit(stage1_locked, pkg_start, &header, ppool);
return ret;
}
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 6c66d79..b589e05 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -14,7 +14,10 @@
#include <gmock/gmock.h>
extern "C" {
+#include "hf/arch/std.h"
+
#include "hf/manifest.h"
+#include "hf/sp_pkg.h"
}
namespace
@@ -232,7 +235,7 @@
Property("execution-ctx-count", "<1>");
Property("exception-level", "<2>");
Property("execution-state", "<0>");
- Property("entrypoint-offset", "<0x00001000>");
+ Property("entrypoint-offset", "<0x00002000>");
Property("xlat-granule", "<0>");
Property("boot-order", "<0>");
Property("messaging-method", "<4>");
@@ -650,15 +653,18 @@
{
public:
__attribute__((aligned(PAGE_SIZE))) struct sp_pkg_header spkg;
- char manifest_dtb[PAGE_SIZE] = {};
+ __attribute__((aligned(PAGE_SIZE))) char manifest_dtb[PAGE_SIZE] = {};
+ __attribute__((aligned(PAGE_SIZE))) char img[PAGE_SIZE] = {};
Partition_package(const std::vector<char> &vec)
{
// Initialise header field
spkg.magic = SP_PKG_HEADER_MAGIC;
spkg.version = SP_PKG_HEADER_VERSION;
- spkg.pm_offset = sizeof(struct sp_pkg_header);
+ spkg.pm_offset = PAGE_SIZE;
spkg.pm_size = vec.size();
+ spkg.img_offset = 2 * PAGE_SIZE;
+ spkg.img_size = ARRAY_SIZE(img);
// Copy dtb into package
std::copy(vec.begin(), vec.end(), manifest_dtb);
@@ -702,7 +708,7 @@
.Property("execution-ctx-count", "<1>")
.Property("exception-level", "<2>")
.Property("execution-state", "<0>")
- .Property("entrypoint-offset", "<0x00001000>")
+ .Property("entrypoint-offset", "<0x00002000>")
.Property("xlat-granule", "<0>")
.Property("messaging-method", "<1>")
.Build();
@@ -744,7 +750,7 @@
.Property("execution-ctx-count", "<1>")
.Property("exception-level", "<2>")
.Property("execution-state", "<0>")
- .Property("entrypoint-offset", "<0x00001000>")
+ .Property("entrypoint-offset", "<0x00002000>")
.Property("xlat-granule", "<0>")
.Property("boot-order", "<0>")
.Property("messaging-method", "<1>")
@@ -762,7 +768,7 @@
.Property("execution-ctx-count", "<1>")
.Property("exception-level", "<2>")
.Property("execution-state", "<0>")
- .Property("entrypoint-offset", "<0x00001000>")
+ .Property("entrypoint-offset", "<0x00002000>")
.Property("xlat-granule", "<3>")
.Property("boot-order", "<0>")
.Property("messaging-method", "<1>")
@@ -780,7 +786,7 @@
.Property("execution-ctx-count", "<1>")
.Property("exception-level", "<6>")
.Property("execution-state", "<0>")
- .Property("entrypoint-offset", "<0x00001000>")
+ .Property("entrypoint-offset", "<0x00002000>")
.Property("xlat-granule", "<0>")
.Property("boot-order", "<0>")
.Property("messaging-method", "<1>")
@@ -798,7 +804,7 @@
.Property("execution-ctx-count", "<1>")
.Property("exception-level", "<2>")
.Property("execution-state", "<2>")
- .Property("entrypoint-offset", "<0x00001000>")
+ .Property("entrypoint-offset", "<0x00002000>")
.Property("xlat-granule", "<0>")
.Property("boot-order", "<0>")
.Property("messaging-method", "<1>")
@@ -816,7 +822,7 @@
.Property("execution-ctx-count", "<1>")
.Property("exception-level", "<2>")
.Property("execution-state", "<0>")
- .Property("entrypoint-offset", "<0x00001000>")
+ .Property("entrypoint-offset", "<0x00002000>")
.Property("xlat-granule", "<0>")
.Property("boot-order", "<0>")
.Property("messaging-method", "<16>")
@@ -1149,7 +1155,7 @@
ASSERT_EQ(m.vm[0].partition.execution_ctx_count, 1);
ASSERT_EQ(m.vm[0].partition.run_time_el, S_EL1);
ASSERT_EQ(m.vm[0].partition.execution_state, AARCH64);
- ASSERT_EQ(m.vm[0].partition.ep_offset, 0x00001000);
+ ASSERT_EQ(m.vm[0].partition.ep_offset, 0x00002000);
ASSERT_EQ(m.vm[0].partition.xlat_granule, PAGE_4KB);
ASSERT_EQ(m.vm[0].partition.boot_order, 0);
ASSERT_EQ(m.vm[0].partition.messaging_method,
diff --git a/src/sp_pkg.c b/src/sp_pkg.c
new file mode 100644
index 0000000..62a08a3
--- /dev/null
+++ b/src/sp_pkg.c
@@ -0,0 +1,110 @@
+/*
+ * 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/sp_pkg.h"
+
+#include <stdint.h>
+
+#include "hf/arch/std.h"
+
+#include "hf/addr.h"
+#include "hf/check.h"
+#include "hf/dlog.h"
+#include "hf/std.h"
+
+/*
+ * Function initializes the Secure Partition Package:
+ * - Maps whole region up to image such that Hafnium can parse the FF-A manifest
+ * and can use the first chunk of memory for booting purposes.
+ */
+bool sp_pkg_init(struct mm_stage1_locked stage1_locked, paddr_t pkg_start,
+ struct sp_pkg_header *header, struct mpool *ppool)
+{
+ bool ret = false;
+ 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 | MM_MODE_W, ppool);
+ assert(pkg != NULL);
+
+ memcpy_s(header, sizeof(struct sp_pkg_header), pkg,
+ sizeof(struct sp_pkg_header));
+
+ if (header->magic != SP_PKG_HEADER_MAGIC) {
+ dlog_error("Invalid package magic.\n");
+ goto exit_unmap;
+ }
+
+ if (header->version != SP_PKG_HEADER_VERSION) {
+ dlog_error("Invalid package version.\n");
+ goto exit_unmap;
+ }
+
+ if (header->pm_offset % PAGE_SIZE != 0 ||
+ header->img_offset % PAGE_SIZE != 0) {
+ dlog_error("SP pkg offsets are not page aligned.\n");
+ goto exit_unmap;
+ }
+
+ if (header->pm_offset > header->img_offset) {
+ dlog_error(
+ "SP pkg offsets must be in order: boot info < "
+ "partition manifest < image offset.\n");
+ goto exit_unmap;
+ }
+
+ /*
+ * Check for overflow and then check the pm shouldn't override the
+ * image.
+ */
+ assert(UINT32_MAX - header->pm_offset >= header->pm_size);
+ if (header->pm_offset + header->pm_size > header->img_offset) {
+ dlog_error("Partition manifest bigger than its region.\n");
+ goto exit_unmap;
+ }
+
+ /*
+ * 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);
+ }
+
+ CHECK(mm_identity_map(stage1_locked, pkg_end,
+ pa_add(pkg_end, header->pm_size), MM_MODE_R,
+ ppool) != NULL);
+
+ ret = true;
+
+exit_unmap:
+ if (!ret) {
+ CHECK(mm_unmap(stage1_locked, pkg_start, pkg_end, ppool));
+ }
+
+ return ret;
+}
+
+/**
+ * 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));
+}