Tell TF-A in EL3 about TEE message buffers.

This must be enabled by a flag in the manifest, as it won't work without
the matching support in TF-A, e.g. in the case of running tests on QEMU
without TF-A.

Bug: 132429380
Change-Id: I0a0848c7b1afb416d98c0afeabcc4601abf9d193
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 3220b4e..c9ecd1a 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -40,6 +40,7 @@
   deps = [
     ":src_testable",
     "//project/${project}/${plat_name}",
+    "//src/arch/${plat_arch}/hypervisor:tee",
     plat_boot_flow,
     plat_console,
     plat_iommu,
@@ -58,7 +59,6 @@
     "panic.c",
     "spci_memory.c",
     "vcpu.c",
-    "vm.c",
   ]
 
   deps = [
@@ -69,8 +69,9 @@
     ":memiter",
     ":mm",
     ":std",
-    ":string",
+    ":vm",
     "//src/arch/${plat_arch}/hypervisor",
+    "//src/arch/${plat_arch}/hypervisor:tee",
     "//vmlib",
     plat_boot_flow,
     plat_console,
@@ -91,6 +92,12 @@
   ]
 }
 
+source_set("vm") {
+  sources = [
+    "vm.c",
+  ]
+}
+
 # Standard library functions.
 source_set("std") {
   sources = [
diff --git a/src/arch/aarch64/hypervisor/BUILD.gn b/src/arch/aarch64/hypervisor/BUILD.gn
index d5db714..67e68bd 100644
--- a/src/arch/aarch64/hypervisor/BUILD.gn
+++ b/src/arch/aarch64/hypervisor/BUILD.gn
@@ -22,6 +22,16 @@
   path = "hf/arch/offsets.h"
 }
 
+source_set("tee") {
+  public_configs = [ "//src/arch/aarch64:config" ]
+  sources = [
+    "tee.c",
+  ]
+  deps = [
+    "//src:vm",
+  ]
+}
+
 # Hypervisor specific code.
 source_set("hypervisor") {
   public_configs = [ "//src/arch/aarch64:config" ]
@@ -38,7 +48,6 @@
     "handler.c",
     "perfmon.c",
     "psci_handler.c",
-    "tee.c",
     "vm.c",
   ]
 
diff --git a/src/arch/aarch64/hypervisor/tee.c b/src/arch/aarch64/hypervisor/tee.c
index de6b094..c3885ac 100644
--- a/src/arch/aarch64/hypervisor/tee.c
+++ b/src/arch/aarch64/hypervisor/tee.c
@@ -16,10 +16,49 @@
 
 #include "hf/arch/tee.h"
 
+#include "hf/check.h"
+#include "hf/dlog.h"
+#include "hf/panic.h"
 #include "hf/spci.h"
+#include "hf/vm.h"
 
 #include "smc.h"
 
+void arch_tee_init(void)
+{
+	struct vm *tee_vm = vm_find(HF_TEE_VM_ID);
+	struct spci_value ret;
+	uint32_t func;
+
+	CHECK(tee_vm != NULL);
+	/*
+	 * 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
+	 * perspective and vice-versa.
+	 */
+	dlog_verbose("Setting up buffers for TEE.\n");
+	ret = arch_tee_call((struct spci_value){
+		.func = SPCI_RXTX_MAP_64,
+		.arg1 = pa_addr(pa_from_va(va_from_ptr(tee_vm->mailbox.recv))),
+		.arg2 = pa_addr(pa_from_va(va_from_ptr(tee_vm->mailbox.send))),
+		.arg3 = HF_MAILBOX_SIZE / SPCI_PAGE_SIZE});
+	func = ret.func & ~SMCCC_CONVENTION_MASK;
+	if (ret.func == SMCCC_ERROR_UNKNOWN) {
+		dlog_error(
+			"Unknown function setting up TEE message buffers. "
+			"Memory sharing with TEE will not work.\n");
+		return;
+	}
+	if (func == SPCI_ERROR_32) {
+		panic("Error %d setting up TEE message buffers.", ret.arg2);
+	} else if (func != SPCI_SUCCESS_32) {
+		panic("Unexpected function %#x returned setting up TEE message "
+		      "buffers.",
+		      ret.func);
+	}
+	dlog_verbose("TEE finished setting up buffers.\n");
+}
+
 struct spci_value arch_tee_call(struct spci_value args)
 {
 	return smc_forward(args.func, args.arg1, args.arg2, args.arg3,
diff --git a/src/arch/fake/hypervisor/BUILD.gn b/src/arch/fake/hypervisor/BUILD.gn
index e7e970f..1afcca6 100644
--- a/src/arch/fake/hypervisor/BUILD.gn
+++ b/src/arch/fake/hypervisor/BUILD.gn
@@ -15,9 +15,14 @@
 source_set("hypervisor") {
   sources = [
     "cpu.c",
-    "tee.c",
   ]
   deps = [
     "//src/arch/fake",
   ]
 }
+
+source_set("tee") {
+  sources = [
+    "tee.c",
+  ]
+}
diff --git a/src/init.c b/src/init.c
index 2f241b8..d224d49 100644
--- a/src/init.c
+++ b/src/init.c
@@ -19,6 +19,8 @@
 #include <stdalign.h>
 #include <stddef.h>
 
+#include "hf/arch/tee.h"
+
 #include "hf/api.h"
 #include "hf/boot_flow.h"
 #include "hf/boot_params.h"
@@ -158,5 +160,10 @@
 	/* Enable TLB invalidation for VM page table updates. */
 	mm_vm_enable_invalidation();
 
+	if (manifest.spci_tee_enabled) {
+		/* Set up message buffers for TEE dispatcher. */
+		arch_tee_init();
+	}
+
 	dlog_info("Hafnium initialisation completed\n");
 }
diff --git a/src/manifest.c b/src/manifest.c
index 438b5d0..9b80106 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -280,6 +280,8 @@
 		return MANIFEST_ERROR_NOT_COMPATIBLE;
 	}
 
+	TRY(read_bool(&hyp_node, "spci_tee", &manifest->spci_tee_enabled));
+
 	/* Iterate over reserved VM IDs and check no such nodes exist. */
 	for (i = 0; i < HF_VM_ID_OFFSET; i++) {
 		spci_vm_id_t vm_id = (spci_vm_id_t)i;