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/inc/hf/manifest.h b/inc/hf/manifest.h
index 553f99c..0bee77d 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -18,9 +18,6 @@
 #define MANIFEST_INVALID_ADDRESS UINT64_MAX
 #define MANIFEST_INVALID_ID UINT32_MAX
 
-#define SP_PKG_HEADER_MAGIC (0x474b5053)
-#define SP_PKG_HEADER_VERSION (0x2)
-
 #define SP_RTX_BUF_NAME_SIZE 10
 
 #define SP_MAX_MEMORY_REGIONS 8
@@ -162,24 +159,6 @@
 };
 
 /**
- *  Header for a FF-A partition package.
- */
-struct sp_pkg_header {
-	/** Magic used to identify a SP package. Value is "SPKG" */
-	uint32_t magic;
-	/** Version number of the header */
-	uint32_t version;
-	/** Offset in bytes to the partition manifest */
-	uint32_t pm_offset;
-	/** Size in bytes of the partition manifest */
-	uint32_t pm_size;
-	/** Offset in bytes to the base address of the partition binary */
-	uint32_t img_offset;
-	/** Size in bytes of the partition binary */
-	uint32_t img_size;
-};
-
-/**
  * Holds information about one of the VMs described in the manifest.
  */
 struct manifest_vm {
diff --git a/inc/hf/sp_pkg.h b/inc/hf/sp_pkg.h
new file mode 100644
index 0000000..5e5f545
--- /dev/null
+++ b/inc/hf/sp_pkg.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "hf/check.h"
+#include "hf/mm.h"
+#include "hf/types.h"
+
+#define SP_PKG_HEADER_MAGIC 0x474b5053U
+#define SP_PKG_HEADER_VERSION 0x2U
+
+#define SP_PKG_FLAG_BOOT_INFO UINT32_C(0x1U << 0)
+
+/**
+ *  Header for a SP Partition Package.
+ */
+struct sp_pkg_header {
+	/** Magic used to identify a SP package. Value is "SPKG". */
+	uint32_t magic;
+	/** Version number of the header. */
+	uint32_t version;
+	/** Offset in bytes to the partition manifests. */
+	uint32_t pm_offset;
+	/** Size in bytes of the partition manifest. */
+	uint32_t pm_size;
+	/** Offset in bytes to the base address of the partition binary. */
+	uint32_t img_offset;
+	/** Size in bytes of the partition binary. */
+	uint32_t img_size;
+};
+
+static inline size_t sp_pkg_get_mem_size(struct sp_pkg_header *sp_pkg)
+{
+	assert(SIZE_MAX - sp_pkg->img_offset >= (size_t)sp_pkg->img_size);
+	return (size_t)(sp_pkg->img_offset + sp_pkg->img_size);
+}
+
+bool sp_pkg_init(struct mm_stage1_locked stage1_locked, paddr_t pkg_start,
+		 struct sp_pkg_header *header, struct mpool *ppool);
+
+void sp_pkg_deinit(struct mm_stage1_locked stage1_locked, vaddr_t pkg_start,
+		   struct sp_pkg_header *header, struct mpool *ppool);
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));
+}