File armstub8-Add-PSCI-monitor-support-for-DBCM2711.patch of Package raspberrypi-tools

From af9c7ef93efca0efa4f0a2da153ae1ec4ca9db4c Mon Sep 17 00:00:00 2001
From: "Ivan T. Ivanov" <iivanov@suse.de>
Date: Thu, 4 Feb 2021 22:58:03 +0200
Subject: [PATCH] armstub8: Add PSCI monitor support for BCM2711

This monitor is used to workaround few issues in
Cortex-A72 CPU used in BCM2711:

* CVE-2017-5715 aka Spectre-v2. Invalidate the Branch Target
  Buffer (BTB) on entry to EL3 by disabling and enabling the MMU.
* CVE-2018-3639 aka Spectre-v4. Set or clean bit 55
  (Disable load pass store) of CPUACTLR_EL1, when requested
  by SMCCC_ARCH_WORKAROUND_2.
* Prevent speculative execution past ERET.
* Implement workaround for AT speculative behaviour

This work is based on Oleksandr RPi3 psci-monitor [1] and
Arm Trusted Firmware [2].

Mitigation's are implemented according "ARM DEN 0070A" [3].

CVE workarounds could be controlled via Linux command line
options [4]: nospectre_v2 and ssbd=

Validation was done using Ghostbusters [5] and Google's Safeside
project [6].

Supported functions include:
 PSCI_VERSION
 PSCI_CPU_OFF
 PSCI_CPU_ON
 PSCI_AFFINITY_INFO
 PSCI_MIGRATE_INFO_TYPE
 PSCI_MIGRATE_INFO_UP_CPU
 PSCI_SYSTEM_OFF
 PSCI_SYSTEM_RESET
 PSCI_FEATURES
 SMCCC_VERSION
 SMCCC_ARCH_WORKAROUND_1
 SMCCC_ARCH_WORKAROUND_2

As side effect of this now Linux kexec is working.

Performance degradation was evaluated using Phoronix hackbench
and it is around 6% in combined case, I would say.

"Hackbench - Count: 4 - Type: Process"

00 = spectre_v2: Vulnerable, spec_store_bypass: Vulnerable
01 = spectre_v2: Mitigated, spec_store_bypass: Vulnerable
02 = spectre_v2: Vulnerable, spec_store_bypass: Mitigated
03 = spectre_v2: Mitigated, spec_store_bypass: Mitigated
04 = no PSCI monitor at all
05 = no PSCI monitor at all

     Run-1   | Run-2   | Run-3, seconds
----------------------------------------
00 | 100.689 | 100.215 | 100.749
01 | 103.386 | 104.627 | 104.387
02 | 104.519 | 105.383 | 104.611
03 | 107.084 | 106.081 | 107.269
04 | 101.301 | 101.894 | 102.564
05 | 100.302 | 101.85  | 99.912

[1] https://github.com/gonzoua/rpi3-psci-monitor
[2] https://github.com/Arm-Software/arm-trusted-firmware
[3] "Firmware interfaces for mitigating cache speculation vulnerabilities"
[4] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
[5] https://github.com/Sultanic/Ghostbusters.git
[6] https://github.com/google/safeside.git

Signed-off-by: Ivan T. Ivanov <iivanov@suse.de>
---
 armstubs/Makefile   |  33 +++-
 armstubs/armstub8.S |   5 +
 armstubs/fdtpatch.c | 279 +++++++++++++++++++++++++++
 armstubs/pscimon8.S | 459 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 773 insertions(+), 3 deletions(-)
 create mode 100644 armstubs/fdtpatch.c
 create mode 100644 armstubs/pscimon8.S

diff --git a/armstubs/Makefile b/armstubs/Makefile
index e6035719..f9b087aa 100644
--- a/armstubs/Makefile
+++ b/armstubs/Makefile
@@ -1,4 +1,4 @@
-BINS=armstub.bin armstub7.bin armstub8-32.bin armstub8-32-gic.bin armstub8.bin armstub8-gic.bin armstub8-gic-highperi.bin
+BINS+=armstub8-gic-highperi-psci.bin armstub8-gic-psci.bin

 CC8?=aarch64-linux-gnu-gcc
 LD8?=aarch64-linux-gnu-ld
@@ -17,6 +17,9 @@ all : $(BINS)
 clean :
 	rm -f *.o *.out *.tmp *.bin *.elf *.ds *.C armstubs.h bin2c *~

+fdtpatch.o: fdtpatch.c
+	$(CC8) -Os -fomit-frame-pointer -fno-builtin -c $< -o $@
+
 %8.o: %8.S
 	$(CC8) -c $< -o $@

@@ -26,6 +29,12 @@ clean :
 %8-gic-highperi.o: %8.S
 	$(CC8) -DGIC=1 -DHIGH_PERI=1 -DBCM2711=1 -c $< -o $@

+%8-gic-psci.o: %8.S
+	$(CC8) -DGIC=1 -DBCM2711=1 -DPSCIMON8=1 -c $< -o $@
+
+%8-gic-highperi-psci.o: %8.S
+	$(CC8) -DGIC=1 -DBCM2711=1 -DPSCIMON8=1 -DHIGH_PERI=1 -c $< -o $@
+
 %8-32.o: %7.S
 	$(CC7) -DBCM2710=1 -c $< -o $@

@@ -41,6 +50,12 @@ clean :
 %8-gic-highperi.elf: %8-gic-highperi.o
 	$(LD8) --section-start=.text=0 $< -o $@

+%8-gic-psci.elf: %8-gic-psci.o fdtpatch.o pscimon8.o
+	$(LD8) --section-start=.text=0 $^ -o $@
+
+%8-gic-highperi-psci.elf: %8-gic-highperi-psci.o fdtpatch.o pscimon8.o
+	$(LD8) --section-start=.text=0 $^ -o $@
+
 %8.elf: %8.o
 	$(LD8) --section-start=.text=0 $< -o $@

@@ -53,6 +68,12 @@ clean :
 %8-gic-highperi.tmp: %8-gic-highperi.elf
 	$(OBJCOPY8) $< -O binary $@

+%8-gic-psci.tmp: %8-gic-psci.elf
+	$(OBJCOPY8) $< -O binary $@
+
+%8-gic-highperi-psci.tmp: %8-gic-highperi-psci.elf
+	$(OBJCOPY8) $< -O binary $@
+
 %8.tmp: %8.elf
 	$(OBJCOPY8) $< -O binary $@

@@ -75,7 +96,8 @@ clean :
 $(BIN2C): bin2c.c
 	gcc $< -o $@

-armstubs.h: armstub.C armstub7.C armstub8-32.C armstub8-32-gic.C armstub8.C armstub8-gic.C armstub8-gic-highperi.C
+armstubs.h: armstub.C armstub7.C armstub8-32.C armstub8-32-gic.C armstub8.C armstub8-gic.C armstub8-gic-highperi.C \
+	armstub8-gic-highperi-psci.C armstub8-gic-psci.C
 	echo 'static const unsigned armstub[] = {' > $@
 	cat armstub.C >> $@
 	echo '};' >> $@
@@ -97,4 +119,9 @@ armstubs.h: armstub.C armstub7.C armstub8-32.C armstub8-32-gic.C armstub8.C arms
 	echo 'static const unsigned armstub8_gic_highperi[] = {' >> $@
 	cat armstub8-gic-highperi.C >> $@
 	echo '};' >> $@
-
+	echo 'static const unsigned armstub8_gic_psci[] = {' >> $@
+	cat armstub8-gic-psci.C >> $@
+	echo '};' >> $@
+	echo 'static const unsigned armstub8_gic_highperi_psci[] = {' >> $@
+	cat armstub8-gic-highperi-psci.C >> $@
+	echo '};' >> $@
diff --git a/armstubs/armstub8.S b/armstubs/armstub8.S
index c675e3e9..af323398 100644
--- a/armstubs/armstub8.S
+++ b/armstubs/armstub8.S
@@ -133,6 +133,11 @@ _start:

 #ifdef GIC
         bl      setup_gic
+#endif
+#ifdef PSCIMON8
+.globl in_el3
+	bl setup_psci_monitor
+in_el3:
 #endif
 	/*
 	 * Set up SCTLR_EL2
diff --git a/armstubs/fdtpatch.c b/armstubs/fdtpatch.c
new file mode 100644
index 00000000..3a9e5fc2
--- /dev/null
+++ b/armstubs/fdtpatch.c
@@ -0,0 +1,279 @@
+/*-
+ * Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (c) 2021 Ivan T. Ivanov <iivanov@suse.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* FDT bits */
+#define	FDT_MAGIC       0xd00dfeed      /* 4: version, 4: total size */
+#define	FDT_TAGSIZE     sizeof(uint32_t)
+
+#define	FDT_BEGIN_NODE	0x1             /* Start node: full name */
+#define	FDT_END_NODE	0x2             /* End node */
+#define	FDT_PROP	0x3             /* Property: name off,
+                                           size, content */
+#define	FDT_NOP		0x4             /* nop */
+#define	FDT_END		0x9
+
+/*
+ * Data below when applied to main blob produces following device tree node
+ *   psci {
+ *       compatible      = "arm,psci-1.0";
+ *       method          = "smc";
+ *   };
+ */
+
+#define	PSCI_NODE_LEN			0x3C
+#define	PSCI_NODE_COMAPTIBLE_OFF	0x14
+#define	PSCI_NODE_METHOD_OFF		0x30
+const unsigned char psci_node[] = {
+	/* FDT_BEGIN_NODE, "psci", FDT_PROP */
+	0, 0, 0, 1, 'p', 's', 'c', 'i', 0, 0, 0, 0, 0, 0, 0, 3,
+	/* len, @"compatible", "arm,psci-1.0 */
+	0, 0, 0, 13, 0, 0, 0, 0, 'a', 'r', 'm', ',', 'p', 's', 'c', 'i',
+	                                /* FDT_PROP, len */
+	'-', '1', '.', '0', 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4,
+        /* @"method", "smc", FDT_END_NODE */
+        0, 0, 0, 0, 's', 'm', 'c', 0, 0, 0, 0, 2
+};
+
+#define	STRINGS_SIZE			0x12
+#define	STRINGS_COMPATIBLE_OFF		0
+#define	STRINGS_METHOD_OFF		11
+const unsigned char strings[] = {
+	'c', 'o', 'm', 'p', 'a', 't', 'i', 'b',
+	'l', 'e',   0, 'm', 'e', 't', 'h', 'o',
+	'd', 0
+};
+
+typedef	unsigned int uint32_t;
+typedef	unsigned long long uint64_t;
+
+struct fdt_reserve_entry {
+	uint64_t address;
+	uint64_t size;
+};
+
+__attribute__((always_inline))
+static inline uint32_t
+bswap32(uint32_t v)
+{
+	uint32_t ret;
+
+	__asm __volatile("rev32 %x0, %x1\n"
+                         : "=&r" (ret), "+r" (v));
+
+	return (ret);
+}
+
+__attribute__((always_inline))
+static inline uint64_t
+bswap64(uint64_t v)
+{
+	uint64_t ret;
+
+	__asm __volatile("rev %x0, %x1\n"
+                         : "=&r" (ret), "+r" (v));
+
+	return (ret);
+}
+
+/*
+ * We always assume that dst is la
+ */
+static void memmove(const void *src, void *dst, int len)
+{
+	const char *s;
+	char *d;
+
+	s = src;
+	d = dst;
+	for (int i = len - 1; i >= 0; i--)
+		d[i] = s[i];
+}
+
+static int is_enable_method(const char *s1)
+{
+	const char *s2 = "enable-method";
+	unsigned n = 13;
+
+	while(n--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+
+	return 1;
+}
+
+void fixup_dt_blob(void *dtb)
+{
+	uint32_t magic;
+	uint32_t total_size;
+	uint32_t off_memrsrv;
+	uint32_t off_struct;
+	uint32_t off_strings;
+	uint32_t size_struct;
+	uint32_t size_strings;
+	uint32_t *dtb_hdr;
+	uint32_t *dtb_struct;
+	struct fdt_reserve_entry *reserve;
+	int tag_ptr, tag, done, len, level, node_ptr;
+	int psci_node_ptr;
+	int strings_end;
+	char *dtb_strings;
+	char *s;
+
+	dtb_hdr = dtb;
+
+	magic = bswap32(dtb_hdr[0]);
+	if (magic != FDT_MAGIC) {
+		return;
+	}
+	total_size = bswap32(dtb_hdr[1]);
+	off_struct = bswap32(dtb_hdr[2]);
+	off_strings = bswap32(dtb_hdr[3]);
+	off_memrsrv = bswap32(dtb_hdr[4]);
+	size_strings = bswap32(dtb_hdr[8]);
+	size_struct = bswap32(dtb_hdr[9]);
+
+	/* Get one more page */
+	reserve = (struct fdt_reserve_entry *)((char*)dtb + off_memrsrv);
+	reserve->size = bswap64(bswap64(reserve->size) + 0x1000);
+
+	dtb_struct = dtb_hdr + off_struct/sizeof(uint32_t);
+	dtb_strings = (char*)dtb + off_strings;
+
+	/*
+	 * Find end first non-root node
+	 */
+	done = 0;
+	tag_ptr = 0;
+	level = 0;
+	node_ptr = -1;
+	/* Find first sub-node of root node */
+	while (!done) {
+		tag = bswap32(dtb_struct[tag_ptr]);
+		switch (tag) {
+		case FDT_BEGIN_NODE:
+			level++;
+			if (level == 2) {
+				node_ptr = tag_ptr;
+				break;
+			}
+			tag_ptr++;
+			s = (char *)(dtb_struct + tag_ptr);
+			len = 0;
+			while (s[len] != 0)
+				len++;
+			len++; /* include zero byte */
+			len = (len + 3) & ~0x3;
+			tag_ptr += len/sizeof(uint32_t);
+			break;
+
+		case FDT_END_NODE:
+			tag_ptr++;
+			break;
+
+		case FDT_NOP:
+			tag_ptr++;
+			break;
+		case FDT_PROP:
+			tag_ptr++; /* skip tag */
+			len = bswap32(dtb_struct[tag_ptr]);
+			/* Goto 'nameoff'  */
+			tag_ptr += 1;
+			s = (char *)(dtb_strings + bswap32(dtb_struct[tag_ptr]));
+			/* Align up to the next 32 bit */
+			len = (len + 3) & ~0x3;
+			/* Goto property value  */
+			tag_ptr += 1;
+			if (is_enable_method(s)) {
+				s = (char *)&dtb_struct[tag_ptr];
+				memmove("psci\0", s, 5);
+			}
+			tag_ptr += len/sizeof(uint32_t);
+			break;
+		case FDT_END:
+			done = 1;
+			break;
+		default:
+			done = 1;
+			break;
+		}
+	}
+
+	tag_ptr = node_ptr;
+
+	/* Either invalid tag or reached end */
+	if (tag_ptr < 0)
+		return;
+
+	/*
+	 * Insert free space for psci node before
+	 * first non-root node
+	 */
+	psci_node_ptr = off_struct + tag_ptr * sizeof(uint32_t);
+	memmove((char *)dtb + psci_node_ptr,
+		(char *)dtb + psci_node_ptr + PSCI_NODE_LEN,
+		total_size - psci_node_ptr);
+	memmove(psci_node, (char *)dtb + psci_node_ptr, PSCI_NODE_LEN);
+
+	/* Fixup lengths/offsets */
+	total_size += PSCI_NODE_LEN;
+	size_struct += PSCI_NODE_LEN;
+	if (off_strings > psci_node_ptr)
+		off_strings += PSCI_NODE_LEN;
+	if (off_memrsrv > psci_node_ptr)
+		off_memrsrv += PSCI_NODE_LEN;
+
+	/*
+	 * Append some free space at the end of strings section
+	 */
+	strings_end = off_strings + size_strings;
+	memmove((char *)dtb + strings_end,
+		(char *)dtb + strings_end + STRINGS_SIZE,
+		total_size - strings_end);
+	memmove(strings, (char *)dtb + strings_end, STRINGS_SIZE);
+
+	/* set property names offsets in psci node */
+	dtb_struct[tag_ptr + PSCI_NODE_COMAPTIBLE_OFF/sizeof(uint32_t)] =
+		bswap32(size_strings + STRINGS_COMPATIBLE_OFF);
+	dtb_struct[tag_ptr + PSCI_NODE_METHOD_OFF/sizeof(uint32_t)] =
+		bswap32(size_strings + STRINGS_METHOD_OFF);
+
+	/* Fixup lengths/offsets */
+	total_size += STRINGS_SIZE;
+	size_strings += STRINGS_SIZE;
+	if (off_struct > strings_end)
+		off_struct += STRINGS_SIZE;
+	if (off_memrsrv > psci_node_ptr)
+		off_memrsrv += STRINGS_SIZE;
+
+	/* Update header */
+	dtb_hdr[1] = bswap32(total_size);
+	dtb_hdr[2] = bswap32(off_struct);
+	dtb_hdr[3] = bswap32(off_strings);
+	dtb_hdr[4] = bswap32(off_memrsrv);
+	dtb_hdr[8] = bswap32(size_strings);
+	dtb_hdr[9] = bswap32(size_struct);
+}
diff --git a/armstubs/pscimon8.S b/armstubs/pscimon8.S
new file mode 100644
index 00000000..fcdabd26
--- /dev/null
+++ b/armstubs/pscimon8.S
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2016 Stephen Warren <swarren@wwwdotorg.org>
+ * Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (c) 2021 Ivan T. Ivanov <iivanov@suse.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the copyright holder nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define BIT(x) 					(1 << (x))
+
+/* Secure Configuration Register */
+#define SCR_SMD					BIT(7)
+
+/* CPU Auxiliary Control Register */
+#define CPUACTLR_EL1				S3_1_C15_C2_0
+#define CPUACTLR_EL1_DIS_LOAD_PASS_STORE	BIT(55)
+
+/* System Control Register */
+#define SCTLR_M_BIT				BIT(0)
+
+/* Translation Control Register */
+#define TCR_EPD0_BIT				BIT(7)
+#define TCR_EPD1_BIT				BIT(23)
+
+/* Function ID's */
+#define SMCCC_VERSION				0x80000000
+#define SMCCC_ARCH_FEATURES			0x80000001
+#define SMCCC_ARCH_WORKAROUND_1			0x80008000
+#define SMCCC_ARCH_WORKAROUND_2			0x80007fff
+
+#define PSCI_VERSION				0x84000000
+#define PSCI_CPU_OFF				0x84000002
+#define PSCI_CPU_ON				0xC4000003
+#define PSCI_AFFINITY_INFO			0xC4000004
+#define PSCI_MIGRATE_INFO_TYPE			0x84000006
+#define PSCI_MIGRATE_INFO_UP_CPU		0xC4000007
+#define PSCI_SYSTEM_OFF				0x84000008
+#define PSCI_SYSTEM_RESET			0x84000009
+#define PSCI_FEATURES				0x8400000a
+
+#define WDOG_ADDRESS				0xfe100000
+#define WDOG_RSTC				0x1c
+#define WDOG_RSTS				0x20
+#define WDOG_WDOG				0x24
+
+#define WDOG_PASSWORD				0x5a000000
+#define WDOG_WDOG_TIMEOUT			(WDOG_PASSWORD | 10)  /* ~150ms */
+#define WDOG_RSTC_CLR				0xffffffcf
+#define WDOG_RSTC_FULL_RESET			(WDOG_PASSWORD | 0x00000020)
+#define WDOG_RSTS_CLR				0xfffffaaa
+#define WDOG_RSTS_FULL_HALT			(WDOG_PASSWORD | 0x0000003f)
+
+#define CPU_COUNT				4
+#define CPU_STACK_SIZE				0x100
+
+.extern in_el3
+.globl setup_psci_monitor
+
+
+	.macro	save_registers
+	stp	x29, x30, [sp, -16]!
+	.endm
+
+	.macro	restore_registers
+	ldp	x29, x30, [sp], 16
+	.endm
+
+	/* Macro for mitigating against speculative execution beyond ERET */
+	.macro	exception_return
+	eret
+	dsb	nsh
+	isb
+	.endm
+
+	/*
+	 * Enables/disables page table walk as speculative AT instructions
+	 * using an out-of-context translation regime could cause subsequent
+	 * requests to generate an incorrect translation.
+	 */
+	.macro	wa_speculative_at
+	mrs	x30, tcr_el1
+	mrs	x29, sctlr_el1
+	stp	x29, x30, [sp, -16]!
+
+	/* ------------------------------------------------------------
+	 * Must follow below order in order to disable page table
+	 * walk for lower ELs (EL1 and EL0). First step ensures that
+	 * page table walk is disabled for stage1 and second step
+	 * ensures that page table walker should use TCR_EL1.EPDx
+	 * bits to perform address translation. ISB ensures that CPU
+	 * does these 2 steps in order.
+	 *
+	 * 1. Update TCR_EL1.EPDx bits to disable page table walk by
+	 *    stage1.
+	 * 2. Enable MMU bit to avoid identity mapping via stage2
+	 *    and force TCR_EL1.EPDx to be used by the page table
+	 *    walker.
+	 * ------------------------------------------------------------
+	 */
+	orr	x30, x30, TCR_EPD0_BIT
+	orr	x30, x30, TCR_EPD1_BIT
+	msr	tcr_el1, x30
+	isb
+	orr	x29, x29, SCTLR_M_BIT
+	msr	sctlr_el1, x29
+
+	/* -----------------------------------------------------------
+	 * Must follow below order to ensure that page table walk is
+	 * not enabled until restoration of all EL1 system registers.
+	 * TCR_EL1 register
+	 * should be updated at the end which restores previous page
+	 * table walk setting of stage1 i.e.(TCR_EL1.EPDx) bits. ISB
+	 * ensures that CPU does below steps in order.
+	 *
+	 * 1. Ensure all other system registers are written before
+	 *    updating SCTLR_EL1 using ISB.
+	 * 2. Restore SCTLR_EL1 register.
+	 * 3. Ensure SCTLR_EL1 written successfully using ISB.
+	 * 4. Restore TCR_EL1 register.
+	 * -----------------------------------------------------------
+	 */
+	isb
+	ldp	x29, x30, [sp], 16
+	msr	sctlr_el1, x29
+	isb
+	msr	tcr_el1, x30
+	.endm
+
+	/*
+	 * Mitigations for CVE-2017-5715 on Arm Cortex CPUs involves
+	 * invalidation of the branch predictor.
+	 */
+	.macro	wa_cve_2017_5715
+	mrs	x29, sctlr_el3
+	/* Disable MMU */
+	bic	x30, x29, SCTLR_M_BIT
+	msr	sctlr_el3, x30
+	isb
+
+	/* Restore MMU */
+	msr	sctlr_el3, x29
+	isb
+	.endm
+
+	.macro	harden_exception
+	save_registers
+	wa_cve_2017_5715
+	wa_speculative_at
+	restore_registers
+	exception_return
+	.endm
+
+.ltorg
+
+.align 11
+el3_vectors:
+	/* Sync, Current EL using SP0 */
+	exception_return
+	.align  7
+	/* IRQ, Current EL using SP0 */
+	exception_return
+	.align  7
+	 /* FIQ, Current EL using SP0 */
+	exception_return
+	.align  7
+	/* SError, Current EL using SP0 */
+	exception_return
+	.align  7
+	/* Sync, Current EL using SPx */
+	exception_return
+	.align  7
+	/* IRQ, Current EL using SPx */
+	exception_return
+	.align  7
+	/* FIQ, Current EL using SPx */
+	exception_return
+	.align  7
+	/* SError, Current EL using SPx */
+	exception_return
+	.align  7
+	/* Sync, Lower EL using AArch64 */
+	save_registers
+	wa_cve_2017_5715
+	wa_speculative_at
+	bl	handle_sync
+	restore_registers
+	exception_return
+	.align  7
+	/* IRQ, Lower EL using AArch64 */
+	harden_exception
+	.align  7
+	/* FIQ, Lower EL using AArch64 */
+	harden_exception
+	.align  7
+	/* SError, Lower EL using AArch64 */
+	harden_exception
+	.align  7
+	/* Sync, Lower EL using AArch32 */
+	harden_exception
+	.align  7
+	/* IRQ, Lower EL using AArch32 */
+	harden_exception
+	.align  7
+	/* FIQ, Lower EL using AArch32 */
+	harden_exception
+	.align  7
+	/* SError, Lower EL using AArch32 */
+	harden_exception
+
+handle_sync:
+	ldr	w29, =SMCCC_ARCH_WORKAROUND_1
+	cmp	w0, w29
+	b.eq	smccc_arch_wa_1_done
+	ldr	w29, =SMCCC_ARCH_WORKAROUND_2
+	cmp	w0, w29
+	b.eq	smccc_arch_wa_2_enable_disable
+	ldr	w29, =PSCI_VERSION
+	cmp	w0, w29
+	b.eq	psci_version
+	ldr	w29, =PSCI_CPU_ON
+	cmp	w0, w29
+	b.eq	psci_cpu_on
+	ldr	w29, =PSCI_FEATURES
+	cmp	w0, w29
+	b.eq	psci_features_query
+	ldr	w29, =SMCCC_ARCH_FEATURES
+	cmp	w0, w29
+	b.eq	smccc_arch_features_query
+	ldr	w29, =SMCCC_VERSION
+	cmp	w0, w29
+	b.eq	smccc_version
+	ldr	w29, =PSCI_MIGRATE_INFO_TYPE
+	cmp	w0, w29
+	b.eq	psci_migrate_info_type
+	ldr	w29, =PSCI_MIGRATE_INFO_UP_CPU
+	cmp	w0, w29
+	b.eq	psci_migrate_info_up_cpu
+	ldr	w29, =PSCI_CPU_OFF
+	cmp	w0, w29
+	b.eq	psci_cpu_off
+	ldr	w29, =PSCI_AFFINITY_INFO
+	cmp	w0, w29
+	b.eq	psci_affinity_info
+	ldr	w29, =PSCI_SYSTEM_OFF
+	cmp	w0, w29
+	b.eq	psci_system_off
+	ldr	w29, =PSCI_SYSTEM_RESET
+	cmp	w0, w29
+	b.eq	psci_system_reset
+	/* fall through to invalid ID case */
+	ldr	w0, =0xFFFFFFFF
+smccc_arch_wa_1_done:
+	ret
+
+smccc_arch_wa_2_enable_disable:
+	/*
+	 * Mitigations for CVE-2018-3639 on Arm Cortex CPUs involve disabling
+	 * the bypassing of writes by reads (including speculative reads).
+	 *
+	 * Cortex-A57, Cortex-A72 - Permanently set bit 55
+	 * (Disable load pass store) of CPUACTLR_EL1 (S3_1_C15_C2_0)
+	 */
+	mrs	x0, CPUACTLR_EL1
+	orr	x0, x0, CPUACTLR_EL1_DIS_LOAD_PASS_STORE
+	/*
+	 * A non-zero value indicates that the mitigation
+	 * for CVE-2018-3639 must be enabled.
+	 */
+	cbnz	w1, 1f
+	bic	x0, x0, CPUACTLR_EL1_DIS_LOAD_PASS_STORE
+1:
+	msr	CPUACTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+
+psci_migrate_info_type:
+	/*
+	 * The Trusted OS will only run one core.
+	 * The Trusted OS does not support the MIGRATE function
+	 */
+	mov	w0, 1
+	ret
+
+smccc_version:
+	/*
+	 * Version v1.1 is required for SMCCC_ARCH_WORKAROUND_1
+	 * and SMCCC_ARCH_WORKAROUND_2 support
+	 */
+	ldr	w0, =0x10001
+	ret
+
+psci_cpu_off:
+	mrs	x6, MPIDR_EL1
+	and	x6, x6, #0x3
+	adr 	x5, spin_cpu0
+	mov	x4, 0
+	str	x4, [x5, x6, lsl #3]
+	dmb	sy
+
+	/* Go to secondary CPUs WFE boot loop */
+	restore_registers
+	adr	x30, in_el3
+	ret
+
+psci_cpu_on:
+	/* x1 - target CPU, x2 - Entrypoint */
+	adr	x29, spin_cpu0
+	and	x1, x1, 3
+	str 	x2, [x29, x1, lsl 3]
+	dsb	sy
+	sev
+	mov	w0, 0
+	ret
+
+psci_migrate_info_up_cpu:
+	mov	w0, 0	/* Pretend that monitor is resiendt on CPU0 */
+	ret
+
+psci_version:
+	/* Return v1.0 */
+	mov	w0, 0x00010000
+	ret
+
+psci_system_off:
+	ldr	x0, =WDOG_ADDRESS
+	ldr	w1, [x0, WDOG_RSTS]
+	ldr	w2, =WDOG_RSTS_CLR
+	and	w1, w1, w2
+	ldr	w2, =WDOG_RSTS_FULL_HALT
+	orr 	w1, w1, w2
+	str	w1, [x0, WDOG_RSTS]
+	/* fall through */
+psci_system_reset:
+	ldr	x0, =WDOG_ADDRESS
+	ldr	w1, =WDOG_WDOG_TIMEOUT
+	str	w1, [x0, WDOG_WDOG]
+	ldr	w1, [x0, WDOG_RSTC]
+	ldr	w2, =WDOG_RSTC_CLR
+	and	w1, w1, w2
+	ldr	w2, =WDOG_RSTC_FULL_RESET
+	orr	w1, w1, w2
+	str	w1, [x0, WDOG_RSTC]
+loop:
+	wfe
+	b	loop
+
+psci_features_query:
+	ldr	w29, =SMCCC_VERSION
+	cmp	w1, w29
+	/* Version read is supported */
+	b.eq	return_success
+	ldr	w29, =SMCCC_ARCH_WORKAROUND_1
+	cmp	w1, w29
+	/* Check for workaround is supported */
+	b.eq	return_success
+	ldr	w29, =SMCCC_ARCH_WORKAROUND_2
+	cmp	w1, w29
+	/* Check for workaround is supported */
+	b.eq	return_success
+	ldr	w0, =0xFFFFFFFF /* not supported */
+	ret
+
+smccc_arch_features_query:
+	ldr	w29, =SMCCC_ARCH_WORKAROUND_1
+	cmp	w1, w29
+	/*
+	 * Return 0 - SMCCC_ARCH_WORKAROUND_1 can be invoked safely on all
+	 * PEs in the system. The PE on which SMCCC_ARCH_FEATURES is called
+	 * requires firmware mitigation for CVE-2017-5715.
+	 */
+	b.eq	return_success
+	ldr	w29, =SMCCC_ARCH_WORKAROUND_2
+	cmp	w1, w29
+	/*
+	 * Return 0 - SMCCC_ARCH_WORKAROUND_2 can be invoked safely on all
+	 * PEs in the system. The PE on which SMCCC_ARCH_FEATURES is called
+	 * requires dynamic firmware mitigation for CVE-2018- 3639 using
+	 * SMCCC_ARCH_WORKAROUND_2.
+	 */
+	b.eq	return_success
+	ldr	w0, =0xFFFFFFFF		/* not supported */
+	ret
+
+return_success:
+	mov	w0, 0
+	ret
+
+psci_affinity_info:
+	and	x1, x1, 3
+	adr	x29, spin_cpu0
+	dsb	sy
+	ldr	x0, [x29, x1, lsl 3]
+	/* If no address assume that CPU is in WFE loop */
+	cmp	w0, 0
+	cset	w0, eq		/* CPU is ON(0) or OFF(1) */
+	ret
+
+setup_psci_monitor:
+	adr	x0, el3_vectors
+	msr	vbar_el3, x0
+
+	/* Get CPU number */
+	mrs	x6, MPIDR_EL1
+	and	x6, x6, 0x3
+
+	/* Setup per CPU stack */
+	msr     SPsel, 1
+	adrp	x1, stack_top
+	add	x1, x1, :lo12: stack_top
+	mov	x3, CPU_STACK_SIZE
+	mul	x3, x6, x3
+	sub	x1, x1, x3
+	mov	sp, x1
+
+	cbnz	x6, 1f
+
+	stp	x29, x30, [sp, -16]!
+	ldr	w0, dtb_ptr32
+	/*
+	 * Insert psci device tree node and increase reserved
+	 * memory with one 4K page
+	 */
+	bl	fixup_dt_blob
+	ldp	x29, x30, [sp], 16
+1:
+	/* Enable SMC */
+	mrs	x0, SCR_EL3
+	bic	x0, x0, SCR_SMD
+	msr	SCR_EL3, x0
+	ret
+
+	.align 5
+stack_bottom:
+	.space (CPU_COUNT * CPU_STACK_SIZE), 0
+stack_top:
--
2.30.1

openSUSE Build Service is sponsored by