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/docs/Manifest.md b/docs/Manifest.md
index 0d9d16e..458b130 100644
--- a/docs/Manifest.md
+++ b/docs/Manifest.md
@@ -13,6 +13,8 @@
hypervisor {
compatible = "hafnium,hafnium";
+ spci_tee;
+
vm1 {
debug_name = "name";
kernel_filename = "vmlinuz";
@@ -38,7 +40,8 @@
of memory, 4 CPUs and, by omitting the `kernel_filename` property, a kernel
preloaded into memory. The primary VM is given all remaining memory, the same
number of CPUs as the hardware, a kernel image called `vmlinuz` and a ramdisk
-`initrd.img`. Secondaries cannot have a ramdisk.
+`initrd.img`. Secondaries cannot have a ramdisk. SPCI memory sharing with the
+TEE is enabled.
```
/dts-v1/;
@@ -47,6 +50,8 @@
hypervisor {
compatible = "hafnium,hafnium";
+ spci_tee;
+
vm1 {
debug_name = "primary VM";
kernel_filename = "vmlinuz";
diff --git a/inc/hf/arch/tee.h b/inc/hf/arch/tee.h
index 709ad37..f37fe0b 100644
--- a/inc/hf/arch/tee.h
+++ b/inc/hf/arch/tee.h
@@ -18,4 +18,5 @@
#include "hf/spci.h"
+void arch_tee_init(void);
struct spci_value arch_tee_call(struct spci_value args);
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index f1aebaf..4c3c5dc 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -50,6 +50,7 @@
* Hafnium manifest parsed from FDT.
*/
struct manifest {
+ bool spci_tee_enabled;
spci_vm_count_t vm_count;
struct manifest_vm vm[MAX_VMS];
};
diff --git a/kokoro/test.sh b/kokoro/test.sh
index 300a2b1..803add7 100755
--- a/kokoro/test.sh
+++ b/kokoro/test.sh
@@ -101,6 +101,10 @@
HFTEST_CPU+=(--log "$LOG_DIR_BASE")
fi
"${HFTEST_CPU[@]}" arch_test
+ if [ $USE_TFA == true || $USE_FVP == true ]
+ then
+ "${HFTEST_CPU[@]}" aarch64_test
+ fi
"${HFTEST_CPU[@]}" hafnium --initrd test/vmapi/arch/aarch64/aarch64_test
"${HFTEST_CPU[@]}" hafnium --initrd test/vmapi/arch/aarch64/gicv3/gicv3_test
"${HFTEST_CPU[@]}" hafnium --initrd test/vmapi/primary_only/primary_only_test
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;
diff --git a/test/arch/BUILD.gn b/test/arch/BUILD.gn
index c770dee..a2534c5 100644
--- a/test/arch/BUILD.gn
+++ b/test/arch/BUILD.gn
@@ -20,6 +20,7 @@
deps = [
":arch_test",
+ "${plat_arch}",
]
}
diff --git a/test/arch/aarch64/BUILD.gn b/test/arch/aarch64/BUILD.gn
new file mode 100644
index 0000000..c030308
--- /dev/null
+++ b/test/arch/aarch64/BUILD.gn
@@ -0,0 +1,38 @@
+# 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.
+
+import("//build/image/image.gni")
+import("//build/toolchain/platform.gni")
+
+group("aarch64") {
+ testonly = true
+
+ deps = [
+ ":aarch64_test",
+ ]
+}
+
+hypervisor("aarch64_test") {
+ testonly = true
+
+ sources = [
+ "tee_test.c",
+ ]
+
+ deps = [
+ "//src:vm",
+ "//src/arch/${plat_arch}/hypervisor:tee",
+ "//test/hftest:hftest_hypervisor",
+ ]
+}
diff --git a/test/arch/aarch64/tee_test.c b/test/arch/aarch64/tee_test.c
new file mode 100644
index 0000000..1b07a3c
--- /dev/null
+++ b/test/arch/aarch64/tee_test.c
@@ -0,0 +1,50 @@
+/*
+ * 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 <stdint.h>
+
+#include "hf/addr.h"
+#include "hf/spci.h"
+#include "hf/types.h"
+
+#include "smc.h"
+#include "test/hftest.h"
+
+alignas(SPCI_PAGE_SIZE) static uint8_t tee_send_buffer[HF_MAILBOX_SIZE];
+alignas(SPCI_PAGE_SIZE) static uint8_t tee_recv_buffer[HF_MAILBOX_SIZE];
+
+/**
+ * Make sure SPCI_RXTX_MAP to EL3 works.
+ */
+TEST(arch_tee, init)
+{
+ struct spci_value ret = arch_tee_call((struct spci_value){
+ .func = SPCI_RXTX_MAP_64,
+ .arg1 = pa_addr(pa_from_va(va_from_ptr(tee_recv_buffer))),
+ .arg2 = pa_addr(pa_from_va(va_from_ptr(tee_send_buffer))),
+ .arg3 = HF_MAILBOX_SIZE / SPCI_PAGE_SIZE});
+ uint32_t func = ret.func & ~SMCCC_CONVENTION_MASK;
+
+ /*
+ * TODO(qwandor): Remove this UNKNOWN check once we have a build of TF-A
+ * which supports SPCI memory sharing.
+ */
+ if (ret.func != SMCCC_ERROR_UNKNOWN) {
+ ASSERT_EQ(func, SPCI_SUCCESS_32);
+ }
+}