mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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. This is XSA-436 / CVE-2023-34320. Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com> Reviewed-by: Julien Grall <jgrall@amazon.com>
This commit is contained in:
1 parent
cb827e7a19
commit
bd3ddaf6ee
9 files changed
+88
-12
No files matched your search
@@ -39,8 +39,10 @@ supported in this document.
|
|||||||
|
|
||||||
Status: Supported
|
Status: Supported
|
||||||
Status, Cortex A57 r0p0-r1p1: Supported, not security 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 A57 r0p0 - r1p1, see Errata 832075.
|
||||||
|
For the Cortex A77 r0p0 - r1p0, see Errata 1508412.
|
||||||
|
|
||||||
## Host hardware support
|
## Host hardware support
|
||||||
|
|
||||||
|
|||||||
@@ -58,4 +58,5 @@ stable hypervisors.
|
|||||||
| ARM | Cortex-A76 | #1286807 | ARM64_ERRATUM_1286807 |
|
| ARM | Cortex-A76 | #1286807 | ARM64_ERRATUM_1286807 |
|
||||||
| ARM | Neoverse-N1 | #1165522 | N/A |
|
| ARM | Neoverse-N1 | #1165522 | N/A |
|
||||||
| ARM | Neoverse-N1 | #1286807 | ARM64_ERRATUM_1286807 |
|
| ARM | Neoverse-N1 | #1286807 | ARM64_ERRATUM_1286807 |
|
||||||
|
| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 |
|
||||||
| ARM | MMU-500 | #842869 | N/A |
|
| ARM | MMU-500 | #842869 | N/A |
|
||||||
@@ -355,6 +355,27 @@ config ARM64_ERRATUM_1286807
|
|||||||
|
|
||||||
If unsure, say Y.
|
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
|
endmenu
|
||||||
|
|
||||||
config ARM64_HARDEN_BRANCH_PREDICTOR
|
config ARM64_HARDEN_BRANCH_PREDICTOR
|
||||||
|
|||||||
@@ -134,6 +134,16 @@
|
|||||||
* position on the stack before.
|
* position on the stack before.
|
||||||
*/
|
*/
|
||||||
.macro entry, hyp, compat, save_x0_x1=1
|
.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 */
|
sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */
|
||||||
|
|
||||||
.if \hyp == 0 /* Guest mode */
|
.if \hyp == 0 /* Guest mode */
|
||||||
@@ -503,6 +513,15 @@ return_from_trap:
|
|||||||
|
|
||||||
ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */
|
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
|
eret
|
||||||
sb
|
sb
|
||||||
|
|
||||||
|
|||||||
@@ -669,6 +669,14 @@ static const struct arm_cpu_capabilities arm_errata[] = {
|
|||||||
.capability = ARM64_WORKAROUND_AT_SPECULATE,
|
.capability = ARM64_WORKAROUND_AT_SPECULATE,
|
||||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
|
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) */
|
/* Cortex-A55 (All versions as erratum is open in SDEN v14) */
|
||||||
.desc = "ARM erratum 1530923",
|
.desc = "ARM erratum 1530923",
|
||||||
@@ -687,11 +695,11 @@ void __init enable_errata_workarounds(void)
|
|||||||
{
|
{
|
||||||
enable_cpu_capabilities(arm_errata);
|
enable_cpu_capabilities(arm_errata);
|
||||||
|
|
||||||
#ifdef CONFIG_ARM64_ERRATUM_832075
|
#if defined(CONFIG_ARM64_ERRATUM_832075) || defined(CONFIG_ARM64_ERRATUM_1508412)
|
||||||
if ( cpus_have_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) )
|
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"
|
printk_once("**** Guests without CPU erratum workarounds can deadlock the system! ****\n"
|
||||||
"**** Guests without CPU erratum workarounds can deadlock the system! ****\n"
|
|
||||||
"**** Only trusted guests should be used. ****\n");
|
"**** Only trusted guests should be used. ****\n");
|
||||||
|
|
||||||
/* Taint the machine has being insecure */
|
/* Taint the machine has being insecure */
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ static void ctxt_switch_from(struct vcpu *p)
|
|||||||
p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1);
|
p->arch.ttbr1 = READ_SYSREG64(TTBR1_EL1);
|
||||||
if ( is_32bit_domain(p->domain) )
|
if ( is_32bit_domain(p->domain) )
|
||||||
p->arch.dacr = READ_SYSREG(DACR32_EL2);
|
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)
|
#if defined(CONFIG_ARM_32)
|
||||||
p->arch.mair0 = READ_CP32(MAIR0);
|
p->arch.mair0 = READ_CP32(MAIR0);
|
||||||
p->arch.mair1 = READ_CP32(MAIR1);
|
p->arch.mair1 = READ_CP32(MAIR1);
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ static inline void invalidate_icache_local(void)
|
|||||||
/* Ask the MMU to translate a VA for us */
|
/* Ask the MMU to translate a VA for us */
|
||||||
static inline uint64_t __va_to_par(vaddr_t va)
|
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));
|
asm volatile ("at s1e2r, %0;" : : "r" (va));
|
||||||
isb();
|
isb();
|
||||||
par = READ_SYSREG64(PAR_EL1);
|
par = read_sysreg_par();
|
||||||
WRITE_SYSREG64(tmp, PAR_EL1);
|
WRITE_SYSREG64(tmp, PAR_EL1);
|
||||||
return par;
|
return par;
|
||||||
}
|
}
|
||||||
@@ -49,28 +49,28 @@ static inline uint64_t __va_to_par(vaddr_t va)
|
|||||||
/* Ask the MMU to translate a Guest VA for us */
|
/* Ask the MMU to translate a Guest VA for us */
|
||||||
static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags)
|
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 )
|
if ( (flags & GV2M_WRITE) == GV2M_WRITE )
|
||||||
asm volatile ("at s12e1w, %0;" : : "r" (va));
|
asm volatile ("at s12e1w, %0;" : : "r" (va));
|
||||||
else
|
else
|
||||||
asm volatile ("at s12e1r, %0;" : : "r" (va));
|
asm volatile ("at s12e1r, %0;" : : "r" (va));
|
||||||
isb();
|
isb();
|
||||||
par = READ_SYSREG64(PAR_EL1);
|
par = read_sysreg_par();
|
||||||
WRITE_SYSREG64(tmp, PAR_EL1);
|
WRITE_SYSREG64(tmp, PAR_EL1);
|
||||||
return par;
|
return par;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t gva_to_ipa_par(vaddr_t va, unsigned int flags)
|
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 )
|
if ( (flags & GV2M_WRITE) == GV2M_WRITE )
|
||||||
asm volatile ("at s1e1w, %0;" : : "r" (va));
|
asm volatile ("at s1e1w, %0;" : : "r" (va));
|
||||||
else
|
else
|
||||||
asm volatile ("at s1e1r, %0;" : : "r" (va));
|
asm volatile ("at s1e1r, %0;" : : "r" (va));
|
||||||
isb();
|
isb();
|
||||||
par = READ_SYSREG64(PAR_EL1);
|
par = read_sysreg_par();
|
||||||
WRITE_SYSREG64(tmp, PAR_EL1);
|
WRITE_SYSREG64(tmp, PAR_EL1);
|
||||||
return par;
|
return par;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,8 +75,9 @@
|
|||||||
#define ARM_WORKAROUND_BHB_LOOP_32 14
|
#define ARM_WORKAROUND_BHB_LOOP_32 14
|
||||||
#define ARM_WORKAROUND_BHB_SMCC_3 15
|
#define ARM_WORKAROUND_BHB_SMCC_3 15
|
||||||
#define ARM_HAS_SB 16
|
#define ARM_HAS_SB 16
|
||||||
|
#define ARM64_WORKAROUND_1508412 17
|
||||||
|
|
||||||
#define ARM_NCAPS 17
|
#define ARM_NCAPS 18
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,30 @@
|
|||||||
# error "unknown ARM variant"
|
# error "unknown ARM variant"
|
||||||
#endif
|
#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 */
|
#endif /* __ASM_ARM_SYSREGS_H */
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
|
|||||||