VHE: Tests: Allow FF-A partitions to be loaded by hafnium in NWd

This patch makes changes so that partitions (EL0 host applications or
VMs) can be marked as an FF-A partition in their manifests and still be
loaded. Today's design assumes that if a partition is an FF-A partition,
it is pre-loaded by some other entity and hafnium does not need to load.
This works well for the FVP where either trusted firmware or FVP command
line options can be used to load FF-A partitions in memory prior to
running code. On qemu, this capability does not exist today.
To provide this ability in qemu, we can modify hftest.py and other test
infrastructure to do the same thing as FVP and pre-load FF-A partitions
into memory, but this patch uses a different approach. Here, we add a
new flag that can be added in the hafnium/spmc manifest that indicates
to hafnium that the partition and its manifest still need to be loaded
from the initrd, like normal.
When a partition is not an FF-A partition (marked by is_ffa_partition in
the manifest), the loading rules of hafnium remain unchanged. When a
partition is marked as an FF-A partition, it can either be
pre-loaded (hyp_loaded not in manifest) or it can be explicitly loaded
from the initrd by specifying hyp_loaded in the manifest for hafnium.
Note that qemu currently only supports normal world, so this new field
(hyp_loaded) is not expected to be used in the secure world.
This patch also uses this new feature for all the normal world EL0
partition tests so that they can be marked as FF-A partitions and still
be loaded by the hypervisor like normal.

With this change, the main use case that is enabled is that an FF-A
partition (EL1 VMs and EL0 host applications) can be loaded on qemu.
Also  the partition manifest can be compliant with FF-A, without having
to extend or pollute hafniums default hypervisor manifest to include
fields such as execution-ctx-count, memory regions etc.

Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: If98eb9b6cbd14fc30d6d4e78d2d260a6beb97aa9
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 6f46cdd..15fd844 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -8,6 +8,7 @@
 
 #include "hf/ffa.h"
 #include "hf/ffa_internal.h"
+#include "hf/manifest.h"
 #include "hf/vcpu.h"
 #include "hf/vm.h"
 
@@ -308,3 +309,16 @@
 
 	return false;
 }
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+				       paddr_t fdt_addr,
+				       size_t fdt_allocated_size,
+				       const struct manifest_vm *manifest_vm,
+				       struct mpool *ppool)
+{
+	(void)stage1_locked;
+	(void)fdt_addr;
+	(void)fdt_allocated_size;
+	(void)manifest_vm;
+	(void)ppool;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 411bbdd..d1f4607 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -642,3 +642,33 @@
 
 	*ret_count = vm_count;
 }
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+				       paddr_t fdt_addr,
+				       size_t fdt_allocated_size,
+				       const struct manifest_vm *manifest_vm,
+				       struct mpool *ppool)
+{
+	struct fdt partition_fdt;
+
+	/*
+	 * If the partition is an FF-A partition and is not
+	 * hypervisor loaded, the manifest is passed in the
+	 * partition package and is parsed during
+	 * manifest_init() and secondary fdt should be empty.
+	 */
+	CHECK(manifest_vm->is_hyp_loaded);
+	CHECK(mm_identity_map(stage1_locked, fdt_addr,
+			      pa_add(fdt_addr, fdt_allocated_size), MM_MODE_R,
+			      ppool) != NULL);
+	// NOLINTNEXTLINE(performance-no-int-to-ptr)
+	CHECK(fdt_init_from_ptr(&partition_fdt, (void *)pa_addr(fdt_addr),
+				fdt_allocated_size) == true);
+	CHECK(parse_ffa_manifest(&partition_fdt,
+				 (struct manifest_vm *)manifest_vm) ==
+	      MANIFEST_SUCCESS);
+	CHECK(sanity_check_ffa_manifest((struct manifest_vm *)manifest_vm) ==
+	      MANIFEST_SUCCESS);
+	CHECK(mm_unmap(stage1_locked, fdt_addr,
+		       pa_add(fdt_addr, fdt_allocated_size), ppool) == true);
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index a7b9ba6..4e0074a 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -1237,3 +1237,18 @@
 	(void)partitions;
 	(void)ret_count;
 }
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+				       paddr_t fdt_addr,
+				       size_t fdt_allocated_size,
+				       const struct manifest_vm *manifest_vm,
+				       struct mpool *ppool)
+{
+	(void)stage1_locked;
+	(void)fdt_addr;
+	(void)fdt_allocated_size;
+	(void)manifest_vm;
+	(void)ppool;
+	/* should never be called in SPMC */
+	CHECK(false);
+}
diff --git a/src/load.c b/src/load.c
index 0aebb54..0f80c12 100644
--- a/src/load.c
+++ b/src/load.c
@@ -249,7 +249,7 @@
 	size_t i;
 	bool ret;
 
-	if (manifest_vm->is_ffa_partition) {
+	if (manifest_vm->is_ffa_partition && !manifest_vm->is_hyp_loaded) {
 		primary_begin = pa_init(manifest_vm->partition.load_addr);
 		primary_entry = ipa_add(ipa_from_pa(primary_begin),
 					manifest_vm->partition.ep_offset);
@@ -483,6 +483,12 @@
 			return false;
 		}
 
+		if (manifest_vm->is_ffa_partition) {
+			plat_ffa_parse_partition_manifest(
+				stage1_locked, fdt_addr, fdt_allocated_size,
+				manifest_vm, ppool);
+		}
+
 		if (!fdt_patch_mem(stage1_locked, fdt_addr, fdt_allocated_size,
 				   mem_begin, mem_end, ppool)) {
 			dlog_error("Unable to patch FDT.\n");
@@ -887,7 +893,8 @@
 
 		mem_size = align_up(manifest_vm->secondary.mem_size, PAGE_SIZE);
 
-		if (manifest_vm->is_ffa_partition) {
+		if (manifest_vm->is_ffa_partition &&
+		    !manifest->vm[i].is_hyp_loaded) {
 			secondary_mem_begin =
 				pa_init(manifest_vm->partition.load_addr);
 			secondary_mem_end = pa_init(
diff --git a/src/manifest.c b/src/manifest.c
index 4699c20..ceb4782 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -12,7 +12,6 @@
 #include "hf/assert.h"
 #include "hf/check.h"
 #include "hf/dlog.h"
-#include "hf/fdt.h"
 #include "hf/static_assert.h"
 #include "hf/std.h"
 
@@ -304,6 +303,8 @@
 
 	TRY(read_bool(node, "is_ffa_partition", &vm->is_ffa_partition));
 
+	TRY(read_bool(node, "hyp_loaded", &vm->is_hyp_loaded));
+
 	TRY(read_string(node, "debug_name", &vm->debug_name));
 
 	TRY(read_optional_uint32list(node, "smc_whitelist", &smcs));
@@ -540,8 +541,8 @@
 	return MANIFEST_SUCCESS;
 }
 
-static enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
-						    struct manifest_vm *vm)
+enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
+					     struct manifest_vm *vm)
 {
 	unsigned int i = 0;
 	struct uint32list_iter uuid;
@@ -664,8 +665,7 @@
 	return MANIFEST_SUCCESS;
 }
 
-static enum manifest_return_code sanity_check_ffa_manifest(
-	struct manifest_vm *vm)
+enum manifest_return_code sanity_check_ffa_manifest(struct manifest_vm *vm)
 {
 	uint16_t ffa_version_major;
 	uint16_t ffa_version_minor;
@@ -917,7 +917,11 @@
 
 		TRY(parse_vm_common(&vm_node, &manifest->vm[i], vm_id));
 
-		if (manifest->vm[i].is_ffa_partition) {
+		CHECK(!manifest->vm[i].is_hyp_loaded ||
+		      manifest->vm[i].is_ffa_partition);
+
+		if (manifest->vm[i].is_ffa_partition &&
+		    !manifest->vm[i].is_hyp_loaded) {
 			TRY(parse_ffa_partition_package(stage1_locked, &vm_node,
 							&manifest->vm[i], vm_id,
 							ppool));