FF-A: map normal world rx/tx buffers to the SPMC

The SPMC can receive an FF-A RXTX map request to register
the NWd Hypervisor or OS kernel rx/tx buffers. In the SPMC
this request comes from the physical FF-A interface.
The buffers are mapped non-secure in the SPMC S-EL2 Stage-1
translation regime.

Change-Id: I65947f081b55e125edfd81e5e540a09dc8f915d9
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index f8d0008..1c32ecf 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -64,6 +64,7 @@
     ":panic",
     ":std",
     ":vm",
+    "//src/arch/${plat_arch}:arch",
     "//src/arch/${plat_arch}/hypervisor",
     "//src/arch/${plat_arch}/hypervisor:tee",
     "//vmlib",
diff --git a/src/api.c b/src/api.c
index b55ae09..c33d9eb 100644
--- a/src/api.c
+++ b/src/api.c
@@ -9,6 +9,7 @@
 #include "hf/api.h"
 
 #include "hf/arch/cpu.h"
+#include "hf/arch/mm.h"
 #include "hf/arch/tee.h"
 #include "hf/arch/timer.h"
 
@@ -759,6 +760,7 @@
 				    struct vm_locked vm_locked,
 				    paddr_t pa_send_begin, paddr_t pa_send_end,
 				    paddr_t pa_recv_begin, paddr_t pa_recv_end,
+				    uint32_t extra_attributes,
 				    struct mpool *local_page_pool)
 {
 	bool ret;
@@ -766,7 +768,7 @@
 	/* Map the send page as read-only in the hypervisor address space. */
 	vm_locked.vm->mailbox.send =
 		mm_identity_map(mm_stage1_locked, pa_send_begin, pa_send_end,
-				MM_MODE_R, local_page_pool);
+				MM_MODE_R | extra_attributes, local_page_pool);
 	if (!vm_locked.vm->mailbox.send) {
 		/* TODO: partial defrag of failed range. */
 		/* Recover any memory consumed in failed mapping. */
@@ -780,7 +782,7 @@
 	 */
 	vm_locked.vm->mailbox.recv =
 		mm_identity_map(mm_stage1_locked, pa_recv_begin, pa_recv_end,
-				MM_MODE_W, local_page_pool);
+				MM_MODE_W | extra_attributes, local_page_pool);
 	if (!vm_locked.vm->mailbox.recv) {
 		/* TODO: partial defrag of failed range. */
 		/* Recover any memory consumed in failed mapping. */
@@ -833,6 +835,7 @@
 	paddr_t pa_recv_end;
 	uint32_t orig_send_mode;
 	uint32_t orig_recv_mode;
+	uint32_t extra_attributes;
 
 	/* We only allow these to be setup once. */
 	if (vm_locked.vm->mailbox.send || vm_locked.vm->mailbox.recv) {
@@ -904,9 +907,12 @@
 		goto fail_undo_send;
 	}
 
+	/* Get extra send/recv pages mapping attributes for the given VM ID. */
+	extra_attributes = arch_mm_extra_attributes_from_vm(vm_locked.vm->id);
+
 	if (!api_vm_configure_stage1(mm_stage1_locked, vm_locked, pa_send_begin,
 				     pa_send_end, pa_recv_begin, pa_recv_end,
-				     local_page_pool)) {
+				     extra_attributes, local_page_pool)) {
 		goto fail_undo_send_and_recv;
 	}
 
diff --git a/src/arch/aarch64/hypervisor/tee.c b/src/arch/aarch64/hypervisor/tee.c
index f642a0c..5637230 100644
--- a/src/arch/aarch64/hypervisor/tee.c
+++ b/src/arch/aarch64/hypervisor/tee.c
@@ -16,13 +16,27 @@
 
 #include "smc.h"
 
+#if SECURE_WORLD == 0
+
+alignas(PAGE_SIZE) static uint8_t tee_send_buffer[HF_MAILBOX_SIZE];
+alignas(PAGE_SIZE) static uint8_t tee_recv_buffer[HF_MAILBOX_SIZE];
+
+#endif
+
 void arch_tee_init(void)
 {
-	struct vm *tee_vm = vm_find(HF_TEE_VM_ID);
+#if SECURE_WORLD == 0
+
+	struct vm *tee_vm = vm_find(HF_OTHER_WORLD_ID);
 	struct ffa_value ret;
 	uint32_t func;
 
 	CHECK(tee_vm != NULL);
+
+	/* Setup TEE VM RX/TX buffers */
+	tee_vm->mailbox.send = &tee_send_buffer;
+	tee_vm->mailbox.recv = &tee_recv_buffer;
+
 	/*
 	 * Note that send and recv are swapped around, as the send buffer from
 	 * Hafnium's perspective is the recv buffer from the EL3 dispatcher's
@@ -49,6 +63,7 @@
 		      ret.func);
 	}
 	dlog_verbose("TEE finished setting up buffers.\n");
+#endif
 }
 
 struct ffa_value arch_tee_call(struct ffa_value args)
diff --git a/src/arch/aarch64/mm.c b/src/arch/aarch64/mm.c
index 5bfced3..0abe43e 100644
--- a/src/arch/aarch64/mm.c
+++ b/src/arch/aarch64/mm.c
@@ -695,3 +695,11 @@
 
 	return true;
 }
+
+/**
+ * Return the arch specific mm mode for send/recv pages of given VM ID.
+ */
+uint32_t arch_mm_extra_attributes_from_vm(ffa_vm_id_t id)
+{
+	return (id == HF_HYPERVISOR_VM_ID) ? MM_MODE_NS : 0;
+}
diff --git a/src/arch/fake/BUILD.gn b/src/arch/fake/BUILD.gn
index cbdecaa..382227e 100644
--- a/src/arch/fake/BUILD.gn
+++ b/src/arch/fake/BUILD.gn
@@ -7,7 +7,7 @@
 config("arch_config") {
 }
 
-source_set("fake") {
+source_set("arch") {
   sources = [
     "mm.c",
     "timer.c",
diff --git a/src/arch/fake/hypervisor/BUILD.gn b/src/arch/fake/hypervisor/BUILD.gn
index 8d41d5e..f542206 100644
--- a/src/arch/fake/hypervisor/BUILD.gn
+++ b/src/arch/fake/hypervisor/BUILD.gn
@@ -9,7 +9,7 @@
     "cpu.c",
   ]
   deps = [
-    "//src/arch/fake",
+    "//src/arch/fake:arch",
   ]
 }
 
diff --git a/src/arch/fake/mm.c b/src/arch/fake/mm.c
index f71dd81..96407ac 100644
--- a/src/arch/fake/mm.c
+++ b/src/arch/fake/mm.c
@@ -160,3 +160,10 @@
 	(void)table;
 	return true;
 }
+
+uint32_t arch_mm_extra_attributes_from_vm(ffa_vm_id_t id)
+{
+	(void)id;
+
+	return 0;
+}
diff --git a/src/load.c b/src/load.c
index 97e4b34..871c94f 100644
--- a/src/load.c
+++ b/src/load.c
@@ -29,9 +29,6 @@
 #include "vmapi/hf/call.h"
 #include "vmapi/hf/ffa.h"
 
-alignas(PAGE_SIZE) static uint8_t tee_send_buffer[HF_MAILBOX_SIZE];
-alignas(PAGE_SIZE) static uint8_t tee_recv_buffer[HF_MAILBOX_SIZE];
-
 /**
  * Copies data to an unmapped location by mapping it for write, copying the
  * data, then unmapping it.
@@ -662,7 +659,7 @@
 	      struct boot_params_update *update, struct mpool *ppool)
 {
 	struct vm *primary;
-	struct vm *tee;
+	struct vm *other_world_vm;
 	struct mem_range mem_ranges_available[MAX_MEM_RANGES];
 	struct vm_locked primary_vm_locked;
 	size_t i;
@@ -675,13 +672,19 @@
 	}
 
 	/*
-	 * Initialise the dummy VM which represents TrustZone, and set up its
-	 * RX/TX buffers.
+	 * Initialise the dummy VM which represents the opposite world:
+	 * -TrustZone (or the SPMC) when running the Hypervisor
+	 * -the Hypervisor when running TZ/SPMC
 	 */
-	tee = vm_init(HF_TEE_VM_ID, 0, ppool);
-	CHECK(tee != NULL);
-	tee->mailbox.send = &tee_send_buffer;
-	tee->mailbox.recv = &tee_recv_buffer;
+	other_world_vm = vm_init(HF_OTHER_WORLD_ID, MAX_CPUS, ppool);
+	CHECK(other_world_vm != NULL);
+
+	for (i = 0; i < MAX_CPUS; i++) {
+		struct vcpu *vcpu = vm_get_vcpu(other_world_vm, i);
+		struct cpu *cpu = cpu_find_index(i);
+
+		vcpu->cpu = cpu;
+	}
 
 	static_assert(
 		sizeof(mem_ranges_available) == sizeof(params->mem_ranges),
diff --git a/src/vm.c b/src/vm.c
index a021d77..2ad3516 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -19,7 +19,7 @@
 #include "vmapi/hf/call.h"
 
 static struct vm vms[MAX_VMS];
-static struct vm tee_vm;
+static struct vm other_world;
 static ffa_vm_count_t vm_count;
 
 struct vm *vm_init(ffa_vm_id_t id, ffa_vcpu_count_t vcpu_count,
@@ -28,8 +28,8 @@
 	uint32_t i;
 	struct vm *vm;
 
-	if (id == HF_TEE_VM_ID) {
-		vm = &tee_vm;
+	if (id == HF_OTHER_WORLD_ID) {
+		vm = &other_world;
 	} else {
 		uint16_t vm_index = id - HF_VM_ID_OFFSET;
 
@@ -97,15 +97,15 @@
 {
 	uint16_t index;
 
-	/* Check that this is not a reserved ID. */
-	if (id < HF_VM_ID_OFFSET) {
+	if (id == HF_OTHER_WORLD_ID) {
+		if (other_world.id == HF_OTHER_WORLD_ID) {
+			return &other_world;
+		}
 		return NULL;
 	}
 
-	if (id == HF_TEE_VM_ID) {
-		if (tee_vm.id == HF_TEE_VM_ID) {
-			return &tee_vm;
-		}
+	/* Check that this is not a reserved ID. */
+	if (id < HF_VM_ID_OFFSET) {
 		return NULL;
 	}