]> xenbits.xensource.com Git - xen.git/commitdiff
xen/arm: Add Cortex-A77 erratum 1508412 handling
authorLuca Fancellu <luca.fancellu@arm.com>
Mon, 17 Jul 2023 12:25:46 +0000 (13:25 +0100)
committerStefano Stabellini <stefano.stabellini@amd.com>
Tue, 1 Aug 2023 23:10:46 +0000 (16:10 -0700)
Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence of a
store-exclusive or read of PAR_EL1 and a load with device or non-cacheable
memory attributes.
A workaround is available, but it depends on a firmware counterpart.

The proposed workaround from the errata document is to modify the software
running at EL1 and above to include a DMB SY before and after accessing
PAR_EL1.

In conjunction to the above, the firmware needs to use a specific write
sequence to several IMPLEMENTATION DEFINED registers to have the hardware
insert a DMB SY after all load-exclusive and store-exclusive instructions.

Apply the workaround to Xen where PAR_EL1 is read, implementing an helper
function to do that.
Since Xen can be interrupted by irqs in any moment, add a barrier on
entry/exit when we are running on the affected cores.

A guest without the workaround can deadlock the system, so warn the users
of Xen with the above type of cores to use only trusted guests, by
printing a message on Xen startup.

This is XSA-436 / CVE-2023-34320.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
[stefano: add XSA-436 to commit message]
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
SUPPORT.md
docs/misc/arm/silicon-errata.txt
xen/arch/arm/Kconfig
xen/arch/arm/arm64/entry.S
xen/arch/arm/cpuerrata.c
xen/arch/arm/domain.c
xen/include/asm-arm/arm64/page.h
xen/include/asm-arm/cpufeature.h
xen/include/asm-arm/sysregs.h

index 48fb462221cfb32e918123abad967ca543a98a96..b63abbcda5ad9da81180e9c869843a7938bccfaa 100644 (file)
@@ -39,8 +39,10 @@ supported in this document.
 
     Status: Supported
     Status, Cortex A57 r0p0-r1p1: Supported, not security supported
+    Status, Cortex A77 r0p0-r1p0: Supported, not security supported
 
 For the Cortex A57 r0p0 - r1p1, see Errata 832075.
+For the Cortex A77 r0p0 - r1p0, see Errata 1508412.
 
 ## Host hardware support
 
index 1925d8fd4ee012e27b286743ba72d8c5031a17f3..c4e82df53566873e74d96d37239a05d71475e784 100644 (file)
@@ -58,4 +58,5 @@ stable hypervisors.
 | ARM            | Cortex-A76      | #1286807        | ARM64_ERRATUM_1286807   |
 | ARM            | Neoverse-N1     | #1165522        | N/A
 | ARM            | Neoverse-N1     | #1286807        | ARM64_ERRATUM_1286807   |
+| ARM            | Cortex-A77      | #1508412        | ARM64_ERRATUM_1508412   |
 | ARM            | MMU-500         | #842869         | N/A                     |
index 330bbf6232d4b7e5ef511d8783804c3253d08063..e3c8b895943e8f3dd3a0012079df57b10bbf01af 100644 (file)
@@ -284,6 +284,27 @@ config ARM64_ERRATUM_1286807
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_1508412
+       bool "Cortex-A77: 1508412: possible deadlock on sequence of NC/Device load and store exclusive or PAR read"
+       default y
+       depends on ARM_64
+       help
+         This option adds a workaround for Arm Cortex-A77 erratum 1508412.
+
+         Affected Cortex-A77 cores (r0p0, r1p0) could deadlock on a sequence
+         of a store-exclusive or read of PAR_EL1 and a load with device or
+         non-cacheable memory attributes. The workaround depends on a firmware
+         counterpart.
+
+         Xen guests must also have the workaround implemented or they can
+         deadlock the system.
+
+         Work around the issue by inserting DMB SY barriers around PAR_EL1
+         register reads and warning Xen users. The DMB barrier is sufficient
+         to prevent a speculative PAR_EL1 read.
+
+         If unsure, say Y.
+
 endmenu
 
 config ARM64_HARDEN_BRANCH_PREDICTOR
index a8c214506786ac08232eddf8705c2af401f4b4c0..4f33cef0b3cdedf45f85f102184d8dc75432c0c3 100644 (file)
  * position on the stack before.
  */
         .macro  entry, hyp, compat, save_x0_x1=1
+
+        /*
+         * Ensure any PAR_EL1 reads complete, in case we were interrupted
+         * between the PAR_EL1 read and the memory barrier for the erratum
+         * 1508412 workaround.
+         */
+        alternative_if ARM64_WORKAROUND_1508412
+        dmb sy
+        alternative_else_nop_endif
+
         sub     sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */
         push    x28, x29
         push    x26, x27
@@ -465,6 +475,15 @@ return_from_trap:
 
         ldr     lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */
 
+        /*
+         * Ensure any device/NC reads complete, in case we were interrupted
+         * between the memory barrier for the erratum 1508412 workaround and
+         * any PAR_EL1 read.
+         */
+        alternative_if ARM64_WORKAROUND_1508412
+        dmb sy
+        alternative_else_nop_endif
+
         eret
         sb
 
index ae649d16ef022af5774f1aaaa9e43e376e7edb88..ea680fac2e442d8082a9094cc276087b8f583adb 100644 (file)
@@ -668,6 +668,14 @@ static const struct arm_cpu_capabilities arm_errata[] = {
         .capability = ARM64_WORKAROUND_AT_SPECULATE,
         MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
     },
+#ifdef CONFIG_ARM64_ERRATUM_1508412
+    {
+        /* Cortex-A77 r0p0 - r1p0 */
+        .desc = "ARM erratum 1508412 (hypervisor portion)",
+        .capability = ARM64_WORKAROUND_1508412,
+        MIDR_RANGE(MIDR_CORTEX_A77, 0, 1),
+    },
+#endif
     {
         /* Cortex-A55 (All versions as erratum is open in SDEN v14) */
         .desc = "ARM erratum 1530923",
@@ -686,11 +694,11 @@ void __init enable_errata_workarounds(void)
 {
     enable_cpu_capabilities(arm_errata);
 
-#ifdef CONFIG_ARM64_ERRATUM_832075
-    if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) )
+#if defined(CONFIG_ARM64_ERRATUM_832075) || defined(CONFIG_ARM64_ERRATUM_1508412)
+    if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) ||
+         cpus_have_cap(ARM64_WORKAROUND_1508412) )
     {
-        printk_once("**** This CPU is affected by the errata 832075.                      ****\n"
-                    "**** Guests without CPU erratum workarounds can deadlock the system! ****\n"
+        printk_once("**** Guests without CPU erratum workarounds can deadlock the system! ****\n"
                     "**** Only trusted guests should be used.                             ****\n");
 
         /* Taint the machine has being insecure */
index b11359b8cca3e30c4bcceb00a2e44c9484bb0dea..a997e7dc1169866cc3e8b05be7a3c535e5879efa 100644 (file)
@@ -136,7 +136,7 @@ static void ctxt_switch_from(struct vcpu *p)
     p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1);
     if ( is_32bit_domain(p->domain) )
         p->arch.dacr = READ_SYSREG(DACR32_EL2);
-    p->arch.par = READ_SYSREG64(PAR_EL1);
+    p->arch.par = read_sysreg_par();
 #if defined(CONFIG_ARM_32)
     p->arch.mair0 = READ_CP32(MAIR0);
     p->arch.mair1 = READ_CP32(MAIR1);
index 0cba2663733b1d549f0fe7bf28c11b1cef47915c..fbfe67bf89517b69b88357800b4b9f4add34d189 100644 (file)
@@ -48,11 +48,11 @@ static inline void invalidate_icache_local(void)
 /* Ask the MMU to translate a VA for us */
 static inline uint64_t __va_to_par(vaddr_t va)
 {
-    uint64_t par, tmp = READ_SYSREG64(PAR_EL1);
+    uint64_t par, tmp = read_sysreg_par();
 
     asm volatile ("at s1e2r, %0;" : : "r" (va));
     isb();
-    par = READ_SYSREG64(PAR_EL1);
+    par = read_sysreg_par();
     WRITE_SYSREG64(tmp, PAR_EL1);
     return par;
 }
@@ -60,28 +60,28 @@ static inline uint64_t __va_to_par(vaddr_t va)
 /* Ask the MMU to translate a Guest VA for us */
 static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags)
 {
-    uint64_t par, tmp = READ_SYSREG64(PAR_EL1);
+    uint64_t par, tmp = read_sysreg_par();
 
     if ( (flags & GV2M_WRITE) == GV2M_WRITE )
         asm volatile ("at s12e1w, %0;" : : "r" (va));
     else
         asm volatile ("at s12e1r, %0;" : : "r" (va));
     isb();
-    par = READ_SYSREG64(PAR_EL1);
+    par = read_sysreg_par();
     WRITE_SYSREG64(tmp, PAR_EL1);
     return par;
 }
 
 static inline uint64_t gva_to_ipa_par(vaddr_t va, unsigned int flags)
 {
-    uint64_t par, tmp = READ_SYSREG64(PAR_EL1);
+    uint64_t par, tmp = read_sysreg_par();
 
     if ( (flags & GV2M_WRITE) == GV2M_WRITE )
         asm volatile ("at s1e1w, %0;" : : "r" (va));
     else
         asm volatile ("at s1e1r, %0;" : : "r" (va));
     isb();
-    par = READ_SYSREG64(PAR_EL1);
+    par = read_sysreg_par();
     WRITE_SYSREG64(tmp, PAR_EL1);
     return par;
 }
index d4e7cde675e57b8108130ad4ff521b9acbce3126..41aca9c58c6db73dd31761dfd66ea4bd55988f55 100644 (file)
@@ -53,8 +53,9 @@
 #define ARM_WORKAROUND_BHB_LOOP_24 13
 #define ARM_WORKAROUND_BHB_LOOP_32 14
 #define ARM_WORKAROUND_BHB_SMCC_3 15
+#define ARM64_WORKAROUND_1508412 16
 
-#define ARM_NCAPS           16
+#define ARM_NCAPS           17
 
 #ifndef __ASSEMBLY__
 
index 5c5c51bbcdbf0cbf5774d3e1a5875606dec6f528..61e30c9e517c8c37a9a0f61734c23bb8dac616ed 100644 (file)
@@ -9,6 +9,30 @@
 # error "unknown ARM variant"
 #endif
 
+#ifndef __ASSEMBLY__
+
+#include <asm/alternative.h>
+
+static inline register_t read_sysreg_par(void)
+{
+    register_t par_el1;
+
+    /*
+     * On Cortex-A77 r0p0 and r1p0, read access to PAR_EL1 shall include a
+     * DMB SY before and after accessing it, as part of the workaround for the
+     * errata 1508412.
+     */
+    asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412,
+                 CONFIG_ARM64_ERRATUM_1508412));
+    par_el1 = READ_SYSREG64(PAR_EL1);
+    asm volatile(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412,
+                 CONFIG_ARM64_ERRATUM_1508412));
+
+    return par_el1;
+}
+
+#endif /*  !__ASSEMBLY__  */
+
 #endif /* __ASM_ARM_SYSREGS_H */
 /*
  * Local variables: