feat: consume spmc manifest ns memory nodes

The SPMC manifest provisions for NS memory ranges. The SPMC is aware
about the platform specific NS memory that a normal world client is able
to share/lend/donate. Similarly, it provides information about which NS
memory regions a SP is allowed to map in its SP manifest.

Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I3f1545f79ce36e544387c707c7e024fef67f0286
diff --git a/inc/hf/arch/other_world.h b/inc/hf/arch/other_world.h
index 1d34f56..af401d1 100644
--- a/inc/hf/arch/other_world.h
+++ b/inc/hf/arch/other_world.h
@@ -8,8 +8,11 @@
 
 #pragma once
 
+#include "hf/boot_params.h"
 #include "hf/ffa.h"
 #include "hf/vm.h"
 
-bool arch_other_world_vm_init(struct vm *other_world_vm, struct mpool *ppool);
+bool arch_other_world_vm_init(struct vm *other_world_vm,
+			      const struct boot_params *params,
+			      struct mpool *ppool);
 struct ffa_value arch_other_world_call(struct ffa_value args);
diff --git a/inc/hf/boot_params.h b/inc/hf/boot_params.h
index 667f7bde..c828d07 100644
--- a/inc/hf/boot_params.h
+++ b/inc/hf/boot_params.h
@@ -29,6 +29,8 @@
 	size_t cpu_count;
 	struct mem_range mem_ranges[MAX_MEM_RANGES];
 	size_t mem_ranges_count;
+	struct mem_range ns_mem_ranges[MAX_MEM_RANGES];
+	size_t ns_mem_ranges_count;
 	struct mem_range device_mem_ranges[MAX_DEVICE_MEM_RANGES];
 	size_t device_mem_ranges_count;
 	paddr_t initrd_begin;
diff --git a/src/arch/aarch64/hypervisor/other_world.c b/src/arch/aarch64/hypervisor/other_world.c
index 652b645..a58aa76 100644
--- a/src/arch/aarch64/hypervisor/other_world.c
+++ b/src/arch/aarch64/hypervisor/other_world.c
@@ -17,28 +17,51 @@
 
 #include "smc.h"
 
-bool arch_other_world_vm_init(struct vm *other_world_vm, struct mpool *ppool)
+bool arch_other_world_vm_init(struct vm *other_world_vm,
+			      const struct boot_params *params,
+			      struct mpool *ppool)
 {
+	const char *err_msg =
+		"Unable to initialise address space for Other world VM.\n";
 	struct vm_locked other_world_vm_locked;
 	bool ret = false;
+	uint32_t i;
 
-	/* Map 1TB address range to "Other world VM" Stage-2 */
 	other_world_vm_locked = vm_lock(other_world_vm);
 
-	if (!vm_identity_map(other_world_vm_locked, pa_init(0),
-			     pa_init(UINT64_C(1024) * 1024 * 1024 * 1024),
-			     MM_MODE_R | MM_MODE_W | MM_MODE_X | MM_MODE_NS,
-			     ppool, NULL)) {
-		dlog_error(
-			"Unable to initialise address space for "
-			"Hypervisor VM.\n");
-		goto out;
-	}
-
 	/* Enabling all communication methods for the other world. */
 	other_world_vm->messaging_method =
 		FFA_PARTITION_DIRECT_REQ_RECV | FFA_PARTITION_DIRECT_REQ_SEND;
 
+	/*
+	 * If no NS memory ranges provided, map the full 1TB system address
+	 * space to the other world VM.
+	 */
+	if (params->ns_mem_ranges_count == 0) {
+		dlog_warning("Missing NS memory ranges, default to 1TB.\n");
+		if (!vm_identity_map(
+			    other_world_vm_locked, pa_init(0),
+			    pa_init(UINT64_C(1024) * 1024 * 1024 * 1024),
+			    MM_MODE_R | MM_MODE_W | MM_MODE_X | MM_MODE_NS,
+			    ppool, NULL)) {
+			dlog_error("%s", err_msg);
+			goto out;
+		}
+	}
+
+	/* Map NS mem ranges to "Other world VM" Stage-2 PTs. */
+	for (i = 0; i < params->ns_mem_ranges_count; i++) {
+		if (!vm_identity_map(
+			    other_world_vm_locked,
+			    params->ns_mem_ranges[i].begin,
+			    params->ns_mem_ranges[i].end,
+			    MM_MODE_R | MM_MODE_W | MM_MODE_X | MM_MODE_NS,
+			    ppool, NULL)) {
+			dlog_error("%s", err_msg);
+			goto out;
+		}
+	}
+
 	ret = true;
 
 out:
diff --git a/src/boot_flow/common.c b/src/boot_flow/common.c
index 20b5deb..3e93c33 100644
--- a/src/boot_flow/common.c
+++ b/src/boot_flow/common.c
@@ -17,6 +17,7 @@
 bool boot_flow_get_params(struct boot_params *p, const struct fdt *fdt)
 {
 	struct string memory = STRING_INIT("memory");
+	struct string ns_memory = STRING_INIT("ns-memory");
 	struct string device_memory = STRING_INIT("device-memory");
 
 	p->mem_ranges_count = 0;
@@ -29,7 +30,9 @@
 				      &p->mem_ranges_count, MAX_MEM_RANGES) &&
 	       fdt_find_memory_ranges(fdt, &device_memory, p->device_mem_ranges,
 				      &p->device_mem_ranges_count,
-				      MAX_DEVICE_MEM_RANGES);
+				      MAX_DEVICE_MEM_RANGES) &&
+	       fdt_find_memory_ranges(fdt, &ns_memory, p->ns_mem_ranges,
+				      &p->ns_mem_ranges_count, MAX_MEM_RANGES);
 }
 
 /**
diff --git a/src/load.c b/src/load.c
index df18403..4ed3c0c 100644
--- a/src/load.c
+++ b/src/load.c
@@ -929,7 +929,8 @@
 	return true;
 }
 
-static bool init_other_world_vm(struct mpool *ppool)
+static bool init_other_world_vm(const struct boot_params *params,
+				struct mpool *ppool)
 {
 	struct vm *other_world_vm;
 	size_t i;
@@ -949,7 +950,7 @@
 		vcpu->cpu = cpu;
 	}
 
-	return arch_other_world_vm_init(other_world_vm, ppool);
+	return arch_other_world_vm_init(other_world_vm, params, ppool);
 }
 
 /*
@@ -979,7 +980,7 @@
 		}
 	}
 
-	if (!init_other_world_vm(ppool)) {
+	if (!init_other_world_vm(params, ppool)) {
 		return false;
 	}