Forward messages for TEE on via an SMC to EL3.

This is needed for memory sharing with Secure World, but can also be
used for indirect messages once they are implemented for Secure World.

Bug: 132429380
Change-Id: I3418fb22d1f9639c130ccad603d3a8ef82d207ad
diff --git a/inc/hf/arch/tee.h b/inc/hf/arch/tee.h
new file mode 100644
index 0000000..709ad37
--- /dev/null
+++ b/inc/hf/arch/tee.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2020 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "hf/spci.h"
+
+struct spci_value arch_tee_call(struct spci_value args);
diff --git a/src/api.c b/src/api.c
index 5ddc5f9..825cb42 100644
--- a/src/api.c
+++ b/src/api.c
@@ -17,6 +17,7 @@
 #include "hf/api.h"
 
 #include "hf/arch/cpu.h"
+#include "hf/arch/tee.h"
 #include "hf/arch/timer.h"
 
 #include "hf/check.h"
@@ -909,9 +910,10 @@
  * Notifies the `to` VM about the message currently in its mailbox, possibly
  * with the help of the primary VM.
  */
-static void deliver_msg(struct vm_locked to, spci_vm_id_t from_id,
-			struct vcpu *current, struct vcpu **next)
+static struct spci_value deliver_msg(struct vm_locked to, spci_vm_id_t from_id,
+				     struct vcpu *current, struct vcpu **next)
 {
+	struct spci_value ret = (struct spci_value){.func = SPCI_SUCCESS_32};
 	struct spci_value primary_ret = {
 		.func = SPCI_MSG_SEND_32,
 		.arg1 = ((uint32_t)from_id << 16) | to.vm->id,
@@ -929,16 +931,29 @@
 		to.vm->mailbox.state = MAILBOX_STATE_READ;
 		*next = api_switch_to_primary(current, primary_ret,
 					      VCPU_STATE_READY);
-		return;
+		return ret;
 	}
 
 	to.vm->mailbox.state = MAILBOX_STATE_RECEIVED;
 
+	/* Messages for the TEE are sent on via the dispatcher. */
+	if (to.vm->id == HF_TEE_VM_ID) {
+		struct spci_value call = spci_msg_recv_return(to.vm);
+
+		return arch_tee_call(call);
+		/*
+		 * Don't return to the primary VM in this case, as the TEE is
+		 * not (yet) scheduled via SPCI.
+		 */
+	}
+
 	/* Return to the primary VM directly or with a switch. */
 	if (from_id != HF_PRIMARY_VM_ID) {
 		*next = api_switch_to_primary(current, primary_ret,
 					      VCPU_STATE_READY);
 	}
+
+	return ret;
 }
 
 /**
@@ -1008,9 +1023,7 @@
 	to->mailbox.recv_size = size;
 	to->mailbox.recv_sender = sender_vm_id;
 	to->mailbox.recv_func = SPCI_MSG_SEND_32;
-	ret = (struct spci_value){.func = SPCI_SUCCESS_32};
-
-	deliver_msg(to_locked, sender_vm_id, current, next);
+	ret = deliver_msg(to_locked, sender_vm_id, current, next);
 
 out:
 	vm_unlock(&to_locked);
@@ -1505,7 +1518,7 @@
 		share_func, &api_page_pool);
 
 	if (ret.func == SPCI_SUCCESS_32) {
-		deliver_msg(vm_to_from_lock.vm1, from->id, current, next);
+		ret = deliver_msg(vm_to_from_lock.vm1, from->id, current, next);
 	}
 
 out:
diff --git a/src/arch/aarch64/hypervisor/BUILD.gn b/src/arch/aarch64/hypervisor/BUILD.gn
index 25652b8..6182aaf 100644
--- a/src/arch/aarch64/hypervisor/BUILD.gn
+++ b/src/arch/aarch64/hypervisor/BUILD.gn
@@ -38,6 +38,7 @@
     "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
new file mode 100644
index 0000000..de6b094
--- /dev/null
+++ b/src/arch/aarch64/hypervisor/tee.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hf/arch/tee.h"
+
+#include "hf/spci.h"
+
+#include "smc.h"
+
+struct spci_value arch_tee_call(struct spci_value args)
+{
+	return smc_forward(args.func, args.arg1, args.arg2, args.arg3,
+			   args.arg4, args.arg5, args.arg6, args.arg7);
+}
diff --git a/src/arch/fake/hypervisor/BUILD.gn b/src/arch/fake/hypervisor/BUILD.gn
index b6435ed..e7e970f 100644
--- a/src/arch/fake/hypervisor/BUILD.gn
+++ b/src/arch/fake/hypervisor/BUILD.gn
@@ -15,6 +15,7 @@
 source_set("hypervisor") {
   sources = [
     "cpu.c",
+    "tee.c",
   ]
   deps = [
     "//src/arch/fake",
diff --git a/src/arch/fake/hypervisor/tee.c b/src/arch/fake/hypervisor/tee.c
new file mode 100644
index 0000000..317e279
--- /dev/null
+++ b/src/arch/fake/hypervisor/tee.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hf/arch/tee.h"
+
+#include "hf/dlog.h"
+#include "hf/spci.h"
+#include "hf/spci_internal.h"
+
+struct spci_value arch_tee_call(struct spci_value args)
+{
+	dlog("Attempted to call TEE function %#x\n", args.func);
+	return spci_error(SPCI_NOT_SUPPORTED);
+}