qemu_v8: add support for Hafnium as S-EL2

Adds support for SPMC_AT_EL=2 where Hafnium is loaded at S-EL2 and
OP-TEE runs as an SP at S-EL1.

Hafnium requires both MTE and PAUTH support so make enable those
features in QEMU and TF-A as needed. The values $(MEMTAG) and $(PAUTH)
are not affected by the to allow independent configuration of OP-TEE
core.

Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
diff --git a/.gitignore b/.gitignore
index 5dd7d84..736ad05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
 .gdb_history
 gdb
 pi3.cfg
+.hafnium_checkout
diff --git a/qemu_v8.mk b/qemu_v8.mk
index d244079..43e52f2 100644
--- a/qemu_v8.mk
+++ b/qemu_v8.mk
@@ -43,10 +43,10 @@
 # Option to configure FF-A and SPM:
 # n:	disabled
 # 3:	SPMC and SPMD at EL3 (in TF-A)
-# 2:	not supported, SPMC at S-EL2 (in Hafnium), SPMD at EL3 (in TF-A)
+# 2:	SPMC at S-EL2 (in Hafnium), SPMD at EL3 (in TF-A)
 # 1:	SPMC at S-EL1 (in OP-TEE), SPMD at EL3 (in TF-A)
 SPMC_AT_EL ?= n
-ifneq ($(filter-out n 1 3,$(SPMC_AT_EL)),)
+ifneq ($(filter-out n 1 2 3,$(SPMC_AT_EL)),)
 $(error Unsupported SPMC_AT_EL value $(SPMC_AT_EL))
 endif
 
@@ -76,6 +76,8 @@
 UBOOT_PATH		?= $(ROOT)/u-boot
 UBOOT_BIN		?= $(UBOOT_PATH)/u-boot.bin
 MKIMAGE_PATH		?= $(UBOOT_PATH)/tools
+HAFNIUM_PATH		?= $(ROOT)/hafnium
+HAFNIUM_BIN		?= $(HAFNIUM_PATH)/out/reference/secure_qemu_aarch64_clang/hafnium.bin
 
 ROOTFS_GZ		?= $(BINARIES_PATH)/rootfs.cpio.gz
 ROOTFS_UGZ		?= $(BINARIES_PATH)/rootfs.cpio.uboot
@@ -90,6 +92,12 @@
 ROOTFS_ENTRY		?= 0x44000000
 ROOTFS_LOADADDR		?= 0x44000000
 
+ifeq ($(SPMC_AT_EL),2)
+BL32_DEPS		?= hafnium optee-os
+else
+BL32_DEPS		?= optee-os
+endif
+
 ifeq ($(UBOOT),y)
 BL33_BIN		?= $(UBOOT_BIN)
 BL33_DEPS		?= u-boot
@@ -162,6 +170,7 @@
 	QEMU_USE_GIC_DRIVER=$(TFA_GIC_DRIVER) \
 	ENABLE_SVE_FOR_NS=1 \
 	ENABLE_SVE_FOR_SWD=1 \
+	ENABLE_FEAT_FGT=2 \
 	BL32_RAM_LOCATION=tdram \
 	DEBUG=$(TF_A_DEBUG) \
 	LOG_LEVEL=$(TF_A_LOGLVL)
@@ -176,6 +185,22 @@
 TF_A_FLAGS_SPMC_AT_EL_1 += ENABLE_SME_FOR_NS=0 ENABLE_SME_FOR_SWD=0
 TF_A_FLAGS_SPMC_AT_EL_1 += QEMU_TOS_FW_CONFIG_DTS=../build/qemu_v8/spmc_el1_manifest.dts
 TF_A_FLAGS_SPMC_AT_EL_1 += SPMC_OPTEE=1
+TF_A_FLAGS_SPMC_AT_EL_1 += QEMU_TOS_FW_CONFIG_DTS=../build/qemu_v8/spmc_el1_manifest.dts
+TF_A_FLAGS_SPMC_AT_EL_2  = SPD=spmd 
+TF_A_FLAGS_SPMC_AT_EL_2 += ENABLE_SPE_FOR_LOWER_ELS=0
+TF_A_FLAGS_SPMC_AT_EL_2 += ENABLE_SME_FOR_NS=0 ENABLE_SME_FOR_SWD=0
+TF_A_FLAGS_SPMC_AT_EL_2 += ENABLE_FEAT_SEL2=1
+TF_A_FLAGS_SPMC_AT_EL_2 += SP_LAYOUT_FILE=../build/qemu_v8/sp_layout.json
+TF_A_FLAGS_SPMC_AT_EL_2 += NEED_FDT=yes
+TF_A_FLAGS_SPMC_AT_EL_2 += BL32=$(HAFNIUM_BIN)
+TF_A_FLAGS_SPMC_AT_EL_2 += QEMU_TOS_FW_CONFIG_DTS=../build/qemu_v8/spmc_el2_manifest.dts
+TF_A_FLAGS_SPMC_AT_EL_2 += QEMU_TB_FW_CONFIG_DTS=../build/qemu_v8/tb_fw_config.dts
+ifneq ($(PAUTH),y)
+TF_A_FLAGS_SPMC_AT_EL_2 += CTX_INCLUDE_PAUTH_REGS=1
+endif
+ifneq ($(MEMTAG),y)
+TF_A_FLAGS_SPMC_AT_EL_2 += CTX_INCLUDE_MTE_REGS=1
+endif
 TF_A_FLAGS_SPMC_AT_EL_3  = SPD=spmd SPMC_AT_EL3=1
 TF_A_FLAGS_SPMC_AT_EL_3 += CTX_INCLUDE_EL2_REGS=0 SPMD_SPM_AT_SEL2=0
 TF_A_FLAGS_SPMC_AT_EL_3 += ENABLE_SME_FOR_NS=0 ENABLE_SME_FOR_SWD=0
@@ -198,7 +223,7 @@
 TF_A_FLAGS += CTX_INCLUDE_MTE_REGS=1
 endif
 
-arm-tf: optee-os $(BL33_DEPS)
+arm-tf: $(BL32_DEPS) $(BL33_DEPS)
 	$(TF_A_EXPORTS) $(MAKE) -C $(TF_A_PATH) $(TF_A_FLAGS) all fip
 	mkdir -p $(BINARIES_PATH)
 	ln -sf $(TF_A_OUT)/bl1.bin $(BINARIES_PATH)
@@ -218,12 +243,20 @@
 	rm -f $(BINARIES_PATH)/bl32_extra1.bin
 	rm -f $(BINARIES_PATH)/bl32_extra2.bin
 	rm -f $(BINARIES_PATH)/tos_fw_config.dtb
+	rm -f $(BINARIES_PATH)/op-tee.pkg
 ifeq ($(SPMC_AT_EL),1)
 	ln -sf $(TF_A_OUT)/fdts/spmc_el1_manifest.dtb \
 		$(BINARIES_PATH)/tos_fw_config.dtb
 	ln -sf $(OPTEE_OS_HEADER_V2_BIN) $(BINARIES_PATH)/bl32.bin
 	ln -sf $(OPTEE_OS_PAGER_V2_BIN) $(BINARIES_PATH)/bl32_extra1.bin
 	ln -sf $(OPTEE_OS_PAGEABLE_V2_BIN) $(BINARIES_PATH)/bl32_extra2.bin
+else ifeq ($(SPMC_AT_EL),2)
+	ln -sf $(TF_A_OUT)/fdts/spmc_el2_manifest.dtb \
+		$(BINARIES_PATH)/tos_fw_config.dtb
+	ln -sf $(TF_A_OUT)/fdts/tb_fw_config.dtb \
+		$(BINARIES_PATH)/tb_fw_config.dtb
+	ln -sf $(HAFNIUM_BIN) $(BINARIES_PATH)/bl32.bin
+	ln -sf $(TF_A_OUT)/op-tee.pkg $(BINARIES_PATH)/op-tee.pkg
 else ifeq ($(SPMC_AT_EL),3)
 	ln -sf $(TF_A_OUT)/fdts/spmc_el3_manifest.dtb \
 		$(BINARIES_PATH)/tos_fw_config.dtb
@@ -334,6 +367,13 @@
 ################################################################################
 OPTEE_OS_COMMON_FLAGS += DEBUG=$(DEBUG) CFG_ARM_GICV3=$(GICV3)
 OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_1 = CFG_CORE_SEL1_SPMC=y
+OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_2 = CFG_CORE_SEL2_SPMC=y
+OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_2 += CFG_ARM_GICV3=n CFG_CORE_HAFNIUM_INTC=y
+# [0e00.0000 0e2f.ffff] is reserved to early boot and SPMC
+# [0e30.0000 0e33.ffff] is reserved manifest etc (op-tee.pkg)
+OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_2 += CFG_TZDRAM_START=0x0e304000
+OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_2 += CFG_TZDRAM_SIZE=0x00cfc000
+OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_2 += CFG_CORE_WORKAROUND_NSITR_CACHE_PRIME=n
 OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_3 = CFG_CORE_EL3_SPMC=y
 OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_3 += CFG_DT_ADDR=0x40000000
 OPTEE_OS_COMMON_FLAGS_SPMC_AT_EL_3 += CFG_CORE_RESERVED_SHM=n
@@ -357,6 +397,22 @@
 optee-os-clean: optee-os-clean-common
 
 ################################################################################
+# Hafnium
+################################################################################
+
+HAFNIUM_EXPORTS = PATH=$(HAFNIUM_PATH)/prebuilts/linux-x64/clang/bin:$(HAFNIUM_PATH)/prebuilts/linux-x64/dtc:$(PATH)
+
+.hafnium_checkout:
+	git -C $(HAFNIUM_PATH) submodule init --update
+	touch $@
+
+hafnium: $(HAFNIUM_BIN)
+
+$(HAFNIUM_BIN): .hafnium_checkout | $(OUT_PATH)
+	$(HAFNIUM_EXPORTS) $(MAKE) -C $(HAFNIUM_PATH) $(HAFNIUM_FLAGS) all
+
+
+################################################################################
 # mkimage - create images to be loaded by U-Boot
 ################################################################################
 # Without the objcopy, the uImage will be 10x bigger.
@@ -420,7 +476,11 @@
 QEMU_XEN	?= -drive if=none,file=$(XEN_EXT4),format=raw,id=hd1 \
 		   -device virtio-blk-device,drive=hd1
 else
+ifeq ($(SPMC_AT_EL),2)
+QEMU_VIRT	= true
+else
 QEMU_VIRT	= false
+endif
 ifeq ($(SPMC_AT_EL),n)
 QEMU_SME	= on
 else
@@ -433,6 +493,8 @@
 
 ifeq ($(MEMTAG),y)
 QEMU_MTE	= on
+else ifeq ($(SPMC_AT_EL),2)
+QEMU_MTE	= on
 else
 QEMU_MTE	= off
 endif
diff --git a/qemu_v8/optee_sp_manifest.dts b/qemu_v8/optee_sp_manifest.dts
new file mode 100644
index 0000000..024efe7
--- /dev/null
+++ b/qemu_v8/optee_sp_manifest.dts
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * that has additional optional properties defined.
+ *
+ */
+
+/dts-v1/;
+
+/ {
+	compatible = "arm,ffa-manifest-1.0";
+
+	/* Properties */
+	description = "op-tee";
+	ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+	uuid = <0xe0786148 0xe311f8e7 0x02005ebc 0x1bc5d5a5>;
+	id = <1>;
+	execution-ctx-count = <8>;
+	exception-level = <2>; /* S-EL1 */
+	execution-state = <0>; /* AARCH64 */
+	load-address = <0xe300000>;
+	mem-size = <0xd00000>;	/* OP-TEE specific extension */
+	entrypoint-offset = <0x4000>;
+	xlat-granule = <0>; /* 4KiB */
+	boot-order = <0>;
+	messaging-method = <0x3>; /* Direct messaging only */
+	ns-interrupts-action = <1>; /* NS_ACTION_ME */
+
+	/* Boot protocol */
+	gp-register-num = <0x0>;
+
+	/* Boot Info */
+	boot-info {
+		compatible = "arm,ffa-manifest-boot-info";
+		ffa_manifest;
+	};
+
+	device-regions {
+		compatible = "arm,ffa-manifest-device-regions";
+
+		uart1 {
+			base-address = <0x00000000 0x09040000>;
+			pages-count = <1>;
+			attributes = <0x3>; /* read-write */
+			/* SPI, level-triggered, secure, priority=1 */
+			interrupts = <0x28 0xb01>;
+		};
+	};
+};
diff --git a/qemu_v8/sp_layout.json b/qemu_v8/sp_layout.json
new file mode 100644
index 0000000..c6a02a9
--- /dev/null
+++ b/qemu_v8/sp_layout.json
@@ -0,0 +1,6 @@
+{
+	"op-tee" : {
+		"image": "../../optee_os/out/arm/core/tee-pager_v2.bin",
+		"pm": "optee_sp_manifest.dts"
+	}
+}
diff --git a/qemu_v8/spmc_el2_manifest.dts b/qemu_v8/spmc_el2_manifest.dts
new file mode 100644
index 0000000..7acaa38
--- /dev/null
+++ b/qemu_v8/spmc_el2_manifest.dts
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+/dts-v1/;
+
+/ {
+	compatible = "arm,ffa-core-manifest-1.0";
+	#address-cells = <2>;
+	#size-cells = <1>;
+
+	attribute {
+		spmc_id = <0x8000>;
+		maj_ver = <0x1>;
+		min_ver = <0x1>;
+		exec_state = <0x0>;
+		load_address = <0x0 0xe100000>;
+		entrypoint = <0x0 0xe100000>;
+		binary_size = <0x80000>;
+	};
+
+	hypervisor {
+		compatible = "hafnium,hafnium";
+		vm1 {
+			is_ffa_partition;
+			load_address = <0xe300000>;
+			debug_name = "op-tee";
+			vcpu_count = <4>;
+			mem_size = <0xd00000>;
+		};
+	};
+
+	cpus {
+		#address-cells = <0x02>;
+		#size-cells = <0x00>;
+
+		cpu@0 {
+			device_type = "cpu";
+			reg = <0x0 0x0>;
+		};
+
+		cpu@3 {
+			device_type = "cpu";
+			reg = <0x0 0x3>;
+		};
+
+		cpu@2 {
+			device_type = "cpu";
+			reg = <0x0 0x2>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			reg = <0x0 0x1>;
+		};
+	};
+
+	/* VIRT_SECURE_MEM */
+	memory@e000000 {
+		device_type = "memory";
+		reg = <0x0 0xe000000 0x1000000>;
+	};
+};
diff --git a/qemu_v8/tb_fw_config.dts b/qemu_v8/tb_fw_config.dts
new file mode 100644
index 0000000..68f7b3b
--- /dev/null
+++ b/qemu_v8/tb_fw_config.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2022, Linaro Limited.
+ */
+
+#include <lib/libc/cdefs.h>
+
+/dts-v1/;
+
+/ {
+	secure-partitions {
+		compatible = "arm,sp";
+		op-tee {
+		       uuid = "486178e0-e7f8-11e3-bc5e-0002a5d5c51b";
+		       load-address = <0xe300000>;
+		};
+	};
+};