Xen Security Advisory 436 v1 (CVE-2023-34320) - arm: Guests can trigger a deadlock on Cortex-A77

Xen.org security team posted 1 patch 9 months ago
Failed in applying to current master (apply log)
SUPPORT.md                            |  2 ++
docs/misc/arm/silicon-errata.txt      |  1 +
xen/arch/arm/Kconfig                  | 21 +++++++++++++++++++++
xen/arch/arm/arm64/entry.S            | 19 +++++++++++++++++++
xen/arch/arm/cpuerrata.c              | 16 ++++++++++++----
xen/arch/arm/domain.c                 |  2 +-
xen/arch/arm/include/asm/arm64/page.h | 12 ++++++------
xen/arch/arm/include/asm/cpufeature.h |  3 ++-
xen/arch/arm/include/asm/sysregs.h    | 24 ++++++++++++++++++++++++
9 files changed, 88 insertions(+), 12 deletions(-)
Xen Security Advisory 436 v1 (CVE-2023-34320) - arm: Guests can trigger a deadlock on Cortex-A77
Posted by Xen.org security team 9 months ago
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

            Xen Security Advisory CVE-2023-34320 / XSA-436

           arm: Guests can trigger a deadlock on Cortex-A77

ISSUE DESCRIPTION
=================

Cortex-A77 cores (r0p0 and r1p0) are affected by erratum 1508412
where software, under certain circumstances, could deadlock a core
due to the execution of either a load to device or non-cacheable memory,
and either a store exclusive or register read of the Physical
Address Register (PAR_EL1) in close proximity.

IMPACT
======

A (malicious) guest that doesn't include the workaround for erratum
1508412 could deadlock the core.  This will ultimately result to
a deadlock of the system.

VULNERABLE SYSTEMS
==================

Systems running all version of Xen are affected.

This bug is specific to Arm Cortex-A77 cores r0p0 and r1p0.

MITIGATION
==========

There are no known mitigations.

NOTE REGARDING LACK OF EMBARGO
==============================

This issue has been publicly documented.

RESOLUTION
==========

To handle properly the erratum, it is necessary to have an updated
firmware and that both the hypervisor and guest OSes have the workaround.
This means it is not possible to security support Xen on the Cortex-A77,
even on systems which have the workaround enabled.

Applying the attached patches will document the situation and also
add the workaround in Xen if someone wish to run on Cortex-A77 with
only trusted guests.

Note that patches for released versions are generally prepared to
apply to the stable branches, and may not apply cleanly to the most
recent release tarball.  Downstreams are encouraged to update to the
tip of the stable branch before applying these patches.

xsa436/xsa436.patch           xen-unstable - Xen 4.17.x
xsa436/xsa436-4.16.patch      Xen 4.16.x
xsa436/xsa436-4.15.patch      Xen 4.15.x

$ sha256sum xsa436* xsa436*/*
64d34753cdbbcfec2c80db2daad98529bf900935419d0214057e962098b38160  xsa436.meta
cc0f1303d4ad4c4750bd555622b87a9721e0253759b07915e6ba5216c24e8f8d  xsa436/xsa436.patch
97d1bd7716637efce1fa5d7f608d7f26b2b396fa20b966c8c0cd22ef61dc07d4  xsa436/xsa436-4.15.patch
e1264a44df39d56a2c6246d8f9f511d0371a5f416c364ef766ea5a59e7b46f92  xsa436/xsa436-4.16.patch
$
-----BEGIN PGP SIGNATURE-----

iQFABAEBCAAqFiEEI+MiLBRfRHX6gGCng/4UyVfoK9kFAmTJGVoMHHBncEB4ZW4u
b3JnAAoJEIP+FMlX6CvZIpMIAJJ/58V/2+aEQfc0Fd+UDegr+69PsgRVRKofbX5o
M8r0hCLoowsEvI8vxloaOCTtgEwzFq2zCYsUED1nn0iLk0MqK6t9njkuVD3cmuqt
WaVXiW7uJU8ph2pwscv2tVPBBYblT7+Y3fuHsbXEjEW40yQkStkD5NMgwH5Z0bhq
61zCZm+/xK66VBKnrWFdlTaueOLT11/lGPskISquWrYjz7Vr873k89fXdGURn6+9
N7gdl3eIDqkpGTXvUPFdPwwE+z1ESxGig24RYNQmt3UpLbIQO2wGp0HXbsJ8e1cj
r4KNhSFm/h6tsjOYxm5Jmi4an4gAOlVxCSNds2/+oZQVHpQ=
=GNOw
-----END PGP SIGNATURE-----
{
  "XSA": 436,
  "SupportedVersions": [
    "master",
    "4.17",
    "4.16",
    "4.15"
  ],
  "Trees": [
    "xen"
  ],
  "Recipes": {
    "4.15": {
      "Recipes": {
        "xen": {
          "StableRef": "df3395f6b2d759aba39fb67a7bc0fe49147c8b39",
          "Prereqs": [],
          "Patches": [
            "xsa436/xsa436-4.15.patch"
          ]
        }
      }
    },
    "4.16": {
      "Recipes": {
        "xen": {
          "StableRef": "89fe6d0edea841d1d2690cf3f5173e334c687823",
          "Prereqs": [],
          "Patches": [
            "xsa436/xsa436-4.16.patch"
          ]
        }
      }
    },
    "4.17": {
      "Recipes": {
        "xen": {
          "StableRef": "3141a0b85c37b76e069ec7dcb906ff202f5c4075",
          "Prereqs": [],
          "Patches": [
            "xsa436/xsa436.patch"
          ]
        }
      }
    },
    "master": {
      "Recipes": {
        "xen": {
          "StableRef": "01ca29f0b17a50a94b0e232ba276c32e95d80ae3",
          "Prereqs": [],
          "Patches": [
            "xsa436/xsa436.patch"
          ]
        }
      }
    }
  }
}From b6c28b0a7fa91e9c92caf388ac875639c424abce Mon Sep 17 00:00:00 2001
From: Luca Fancellu <luca.fancellu@arm.com>
Date: Mon, 17 Jul 2023 13:25:46 +0100
Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling

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.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 SUPPORT.md                            |  2 ++
 docs/misc/arm/silicon-errata.txt      |  1 +
 xen/arch/arm/Kconfig                  | 21 +++++++++++++++++++++
 xen/arch/arm/arm64/entry.S            | 19 +++++++++++++++++++
 xen/arch/arm/cpuerrata.c              | 16 ++++++++++++----
 xen/arch/arm/domain.c                 |  2 +-
 xen/arch/arm/include/asm/arm64/page.h | 12 ++++++------
 xen/arch/arm/include/asm/cpufeature.h |  3 ++-
 xen/arch/arm/include/asm/sysregs.h    | 24 ++++++++++++++++++++++++
 9 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 8e040d1c1ef5..b63376f4d8d2 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -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
 
diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt
index 1925d8fd4ee0..c4e82df53566 100644
--- a/docs/misc/arm/silicon-errata.txt
+++ b/docs/misc/arm/silicon-errata.txt
@@ -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                     |
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 33e004d702bf..6ed1d51791e1 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -312,6 +312,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
diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S
index 95f1a9268419..95ff4e3e0517 100644
--- a/xen/arch/arm/arm64/entry.S
+++ b/xen/arch/arm/arm64/entry.S
@@ -134,6 +134,16 @@
  * 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 */
 
         .if \hyp == 0         /* Guest mode */
@@ -492,6 +502,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
 
diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c
index ae649d16ef02..ea680fac2e44 100644
--- a/xen/arch/arm/cpuerrata.c
+++ b/xen/arch/arm/cpuerrata.c
@@ -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 */
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 2cd481979cf1..3e372fb70b99 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -137,7 +137,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);
diff --git a/xen/arch/arm/include/asm/arm64/page.h b/xen/arch/arm/include/asm/arm64/page.h
index 0cba2663733b..fbfe67bf8951 100644
--- a/xen/arch/arm/include/asm/arm64/page.h
+++ b/xen/arch/arm/include/asm/arm64/page.h
@@ -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;
 }
diff --git a/xen/arch/arm/include/asm/cpufeature.h b/xen/arch/arm/include/asm/cpufeature.h
index c86a2e7f291c..3a39fe4b5afe 100644
--- a/xen/arch/arm/include/asm/cpufeature.h
+++ b/xen/arch/arm/include/asm/cpufeature.h
@@ -68,8 +68,9 @@
 #define ARM_WORKAROUND_BHB_LOOP_32 14
 #define ARM_WORKAROUND_BHB_SMCC_3 15
 #define ARM_HAS_SB 16
+#define ARM64_WORKAROUND_1508412 17
 
-#define ARM_NCAPS           17
+#define ARM_NCAPS           18
 
 #ifndef __ASSEMBLY__
 
diff --git a/xen/arch/arm/include/asm/sysregs.h b/xen/arch/arm/include/asm/sysregs.h
index 5c5c51bbcdbf..61e30c9e517c 100644
--- a/xen/arch/arm/include/asm/sysregs.h
+++ b/xen/arch/arm/include/asm/sysregs.h
@@ -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:
-- 
2.40.1

From bcb0777692eecb6037f6c13240df591fa70e75ee Mon Sep 17 00:00:00 2001
From: Luca Fancellu <luca.fancellu@arm.com>
Date: Mon, 17 Jul 2023 13:25:46 +0100
Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling

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.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 SUPPORT.md                       |  2 ++
 docs/misc/arm/silicon-errata.txt |  1 +
 xen/arch/arm/Kconfig             | 21 +++++++++++++++++++++
 xen/arch/arm/arm64/entry.S       | 19 +++++++++++++++++++
 xen/arch/arm/cpuerrata.c         | 16 ++++++++++++----
 xen/arch/arm/domain.c            |  2 +-
 xen/include/asm-arm/arm64/page.h | 12 ++++++------
 xen/include/asm-arm/cpufeature.h |  3 ++-
 xen/include/asm-arm/sysregs.h    | 24 ++++++++++++++++++++++++
 9 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 0fb262f81f40..d5719f005ba9 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -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
 
diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt
index 1925d8fd4ee0..c4e82df53566 100644
--- a/docs/misc/arm/silicon-errata.txt
+++ b/docs/misc/arm/silicon-errata.txt
@@ -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                     |
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 330bbf6232d4..e3c8b895943e 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -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
diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S
index a8c214506786..4f33cef0b3cd 100644
--- a/xen/arch/arm/arm64/entry.S
+++ b/xen/arch/arm/arm64/entry.S
@@ -112,6 +112,16 @@
  * 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
 
diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c
index ae649d16ef02..ea680fac2e44 100644
--- a/xen/arch/arm/cpuerrata.c
+++ b/xen/arch/arm/cpuerrata.c
@@ -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 */
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 5eaf4c718ec3..961b6dc82a56 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -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);
diff --git a/xen/include/asm-arm/arm64/page.h b/xen/include/asm-arm/arm64/page.h
index 0cba2663733b..fbfe67bf8951 100644
--- a/xen/include/asm-arm/arm64/page.h
+++ b/xen/include/asm-arm/arm64/page.h
@@ -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;
 }
diff --git a/xen/include/asm-arm/cpufeature.h b/xen/include/asm-arm/cpufeature.h
index d4e7cde675e5..41aca9c58c6d 100644
--- a/xen/include/asm-arm/cpufeature.h
+++ b/xen/include/asm-arm/cpufeature.h
@@ -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__
 
diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
index 5c5c51bbcdbf..61e30c9e517c 100644
--- a/xen/include/asm-arm/sysregs.h
+++ b/xen/include/asm-arm/sysregs.h
@@ -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:
-- 
2.40.1

From 5083b8b4a425c64820ac106ce0f79cc5af195b5b Mon Sep 17 00:00:00 2001
From: Luca Fancellu <luca.fancellu@arm.com>
Date: Mon, 17 Jul 2023 13:25:46 +0100
Subject: [PATCH] xen/arm: Add Cortex-A77 erratum 1508412 handling

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.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
---
 SUPPORT.md                       |  2 ++
 docs/misc/arm/silicon-errata.txt |  1 +
 xen/arch/arm/Kconfig             | 21 +++++++++++++++++++++
 xen/arch/arm/arm64/entry.S       | 19 +++++++++++++++++++
 xen/arch/arm/cpuerrata.c         | 16 ++++++++++++----
 xen/arch/arm/domain.c            |  2 +-
 xen/include/asm-arm/arm64/page.h | 12 ++++++------
 xen/include/asm-arm/cpufeature.h |  3 ++-
 xen/include/asm-arm/sysregs.h    | 24 ++++++++++++++++++++++++
 9 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/SUPPORT.md b/SUPPORT.md
index 85726102eab8..78a93159e3da 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -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
 
diff --git a/docs/misc/arm/silicon-errata.txt b/docs/misc/arm/silicon-errata.txt
index 1925d8fd4ee0..c4e82df53566 100644
--- a/docs/misc/arm/silicon-errata.txt
+++ b/docs/misc/arm/silicon-errata.txt
@@ -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                     |
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ecfa6822e4d3..c787a042a0a2 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -278,6 +278,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
diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S
index 95f1a9268419..95ff4e3e0517 100644
--- a/xen/arch/arm/arm64/entry.S
+++ b/xen/arch/arm/arm64/entry.S
@@ -134,6 +134,16 @@
  * 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 */
 
         .if \hyp == 0         /* Guest mode */
@@ -492,6 +502,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
 
diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c
index ae649d16ef02..ea680fac2e44 100644
--- a/xen/arch/arm/cpuerrata.c
+++ b/xen/arch/arm/cpuerrata.c
@@ -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 */
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 96e1b235501d..cb1d54ba8549 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -137,7 +137,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);
diff --git a/xen/include/asm-arm/arm64/page.h b/xen/include/asm-arm/arm64/page.h
index 0cba2663733b..fbfe67bf8951 100644
--- a/xen/include/asm-arm/arm64/page.h
+++ b/xen/include/asm-arm/arm64/page.h
@@ -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;
 }
diff --git a/xen/include/asm-arm/cpufeature.h b/xen/include/asm-arm/cpufeature.h
index f7368766c07c..2f38137f39d5 100644
--- a/xen/include/asm-arm/cpufeature.h
+++ b/xen/include/asm-arm/cpufeature.h
@@ -67,8 +67,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__
 
diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
index 5c5c51bbcdbf..61e30c9e517c 100644
--- a/xen/include/asm-arm/sysregs.h
+++ b/xen/include/asm-arm/sysregs.h
@@ -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:
-- 
2.40.1