Merge changes from topic "bk/errata_refactor" into integration
* changes:
feat(cpus): wrappers to propagate AArch32 errata info
feat(cpus): add a way to automatically report errata
feat(cpus): add a concise way to implement AArch64 errata
refactor(cpus): convert print_errata_status to C
refactor(cpus): rename errata_report.h to errata.h
refactor(cpus): move cpu_ops field defines to a header
diff --git a/Makefile b/Makefile
index 98f47a7..3ec4151 100644
--- a/Makefile
+++ b/Makefile
@@ -710,16 +710,23 @@
BL32_LDFLAGS += $(PIE_LDFLAGS)
endif
-ifeq (${ARCH},aarch64)
+BL1_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
+BL31_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
+BL32_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
+
BL1_CPPFLAGS += -DIMAGE_AT_EL3
ifeq ($(RESET_TO_BL2),1)
BL2_CPPFLAGS += -DIMAGE_AT_EL3
else
BL2_CPPFLAGS += -DIMAGE_AT_EL1
endif
+
+ifeq (${ARCH},aarch64)
BL2U_CPPFLAGS += -DIMAGE_AT_EL1
BL31_CPPFLAGS += -DIMAGE_AT_EL3
BL32_CPPFLAGS += -DIMAGE_AT_EL1
+else
+BL32_CPPFLAGS += -DIMAGE_AT_EL3
endif
# Include the CPU specific operations makefile, which provides default
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index 7399bc8..3f64e27 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -17,7 +17,7 @@
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/crypto_mod.h>
#include <drivers/console.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <smccc_helpers.h>
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
index 41bcd12..19b955f 100644
--- a/bl2/bl2.mk
+++ b/bl2/bl2.mk
@@ -41,8 +41,7 @@
BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \
bl2/${ARCH}/bl2_el3_exceptions.S \
bl2/${ARCH}/bl2_run_next_image.S \
- lib/cpus/${ARCH}/cpu_helpers.S \
- lib/cpus/errata_report.c
+ lib/cpus/${ARCH}/cpu_helpers.S
ifeq (${DISABLE_MTPMU},1)
BL2_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S
diff --git a/drivers/st/crypto/stm32_pka.c b/drivers/st/crypto/stm32_pka.c
index 1e7c42c..9124cf2 100644
--- a/drivers/st/crypto/stm32_pka.c
+++ b/drivers/st/crypto/stm32_pka.c
@@ -33,10 +33,10 @@
#define UINT8_LEN 8U
#define UINT64_LEN (UINT8_LEN * sizeof(uint64_t))
-#define WORD_SIZE (sizeof(uint64_t))
+#define PKA_WORD_SIZE (sizeof(uint64_t))
#define OP_NBW_FROM_LEN(len) (DIV_ROUND_UP_2EVAL((len), UINT64_LEN) + 1)
#define OP_NBW_FROM_SIZE(s) OP_NBW_FROM_LEN((s) * UINT8_LEN)
-#define OP_SIZE_FROM_SIZE(s) (OP_NBW_FROM_SIZE(s) * WORD_SIZE)
+#define OP_SIZE_FROM_SIZE(s) (OP_NBW_FROM_SIZE(s) * PKA_WORD_SIZE)
#define DT_PKA_COMPAT "st,stm32-pka64"
diff --git a/include/arch/aarch32/asm_macros.S b/include/arch/aarch32/asm_macros.S
index 483f9fe..83e94ca 100644
--- a/include/arch/aarch32/asm_macros.S
+++ b/include/arch/aarch32/asm_macros.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,6 +8,7 @@
#include <arch.h>
#include <common/asm_macros_common.S>
+#include <lib/cpus/cpu_ops.h>
#include <lib/spinlock.h>
/*
@@ -24,8 +25,6 @@
stcopr _reg, _coproc
#endif
-#define WORD_SIZE 4
-
/*
* Co processor register accessors
*/
@@ -49,14 +48,14 @@
.macro dcache_line_size reg, tmp
ldcopr \tmp, CTR
ubfx \tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH
- mov \reg, #WORD_SIZE
+ mov \reg, #CPU_WORD_SIZE
lsl \reg, \reg, \tmp
.endm
.macro icache_line_size reg, tmp
ldcopr \tmp, CTR
and \tmp, \tmp, #CTR_IMINLINE_MASK
- mov \reg, #WORD_SIZE
+ mov \reg, #CPU_WORD_SIZE
lsl \reg, \reg, \tmp
.endm
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S
index ab2f2c6..096e0b1 100644
--- a/include/lib/cpus/aarch32/cpu_macros.S
+++ b/include/lib/cpus/aarch32/cpu_macros.S
@@ -1,82 +1,13 @@
/*
- * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CPU_MACROS_S
#define CPU_MACROS_S
-#include <arch.h>
-#include <lib/cpus/errata_report.h>
-
-#if defined(IMAGE_BL1) || defined(IMAGE_BL32) \
- || (defined(IMAGE_BL2) && RESET_TO_BL2)
-#define IMAGE_AT_EL3
-#endif
-
-#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
- (MIDR_PN_MASK << MIDR_PN_SHIFT)
-
-/* The number of CPU operations allowed */
-#define CPU_MAX_PWR_DWN_OPS 2
-
-/* Special constant to specify that CPU has no reset function */
-#define CPU_NO_RESET_FUNC 0
-
-/* Word size for 32-bit CPUs */
-#define CPU_WORD_SIZE 4
-
-/*
- * Whether errata status needs reporting. Errata status is printed in debug
- * builds for both BL1 and BL32 images.
- */
-#if (defined(IMAGE_BL1) || defined(IMAGE_BL32)) && DEBUG
-# define REPORT_ERRATA 1
-#else
-# define REPORT_ERRATA 0
-#endif
-
-
- .equ CPU_MIDR_SIZE, CPU_WORD_SIZE
- .equ CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
- .equ CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE
-
-#ifndef IMAGE_AT_EL3
- .equ CPU_RESET_FUNC_SIZE, 0
-#endif
-
-/* The power down core and cluster is needed only in BL32 */
-#ifndef IMAGE_BL32
- .equ CPU_PWR_DWN_OPS_SIZE, 0
-#endif
-
-/* Fields required to print errata status */
-#if !REPORT_ERRATA
- .equ CPU_ERRATA_FUNC_SIZE, 0
-#endif
-
-/* Only BL32 requires mutual exclusion and printed flag. */
-#if !(REPORT_ERRATA && defined(IMAGE_BL32))
- .equ CPU_ERRATA_LOCK_SIZE, 0
- .equ CPU_ERRATA_PRINTED_SIZE, 0
-#endif
-
-
-/*
- * Define the offsets to the fields in cpu_ops structure.
- * Every offset is defined based on the offset and size of the previous
- * field.
- */
- .equ CPU_MIDR, 0
- .equ CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE
- .equ CPU_PWR_DWN_OPS, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
- .equ CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
- .equ CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
- .equ CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
- .equ CPU_OPS_SIZE, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
/*
* Write given expressions as words
@@ -142,6 +73,29 @@
fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
#endif
+ /*
+ * It is possible (although unlikely) that a cpu may have no errata in
+ * code. In that case the start label will not be defined. The list is
+ * inteded to be used in a loop, so define it as zero-length for
+ * predictable behaviour. Since this macro is always called at the end
+ * of the cpu file (after all errata have been parsed) we can be sure
+ * that we are at the end of the list. Some cpus call the macro twice,
+ * so only do this once.
+ */
+ .pushsection .rodata.errata_entries
+ .ifndef \_name\()_errata_list_start
+ \_name\()_errata_list_start:
+ .endif
+ /* some call this multiple times, so only do this once */
+ .ifndef \_name\()_errata_list_end
+ \_name\()_errata_list_end:
+ .endif
+ .popsection
+
+ /* and now put them in cpu_ops */
+ .word \_name\()_errata_list_start
+ .word \_name\()_errata_list_end
+
#if REPORT_ERRATA
.ifndef \_name\()_cpu_str
/*
@@ -166,6 +120,7 @@
* this class.
*/
.word \_name\()_errata_report
+ .word \_name\()_cpu_str
#ifdef IMAGE_BL32
/* Pointers to errata lock and reported flag */
@@ -228,4 +183,77 @@
beq \_label
.endm
+/*
+ * NOTE an erratum and CVE id could clash. However, both numbers are very large
+ * and the probablity is minuscule. Working around this makes code very
+ * complicated and extremely difficult to read so it is not considered. In the
+ * unlikely event that this does happen, prepending the CVE id with a 0 should
+ * resolve the conflict
+ */
+
+/*
+ * Add an entry for this erratum to the errata framework
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with the previous field with the
+ * ERRATUM or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * _special:
+ * The special non-standard name of an erratum
+ */
+.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _special
+ .pushsection .rodata.errata_entries
+ .align 2
+ .ifndef \_cpu\()_errata_list_start
+ \_cpu\()_errata_list_start:
+ .endif
+
+ /* unused on AArch32, maintain for portability */
+ .word 0
+ /* TODO(errata ABI): this prevents all checker functions from
+ * being optimised away. Can be done away with unless the ABI
+ * needs them */
+ .ifnb \_special
+ .word check_errata_\_special
+ .elseif \_cve
+ .word check_errata_cve_\_cve\()_\_id
+ .else
+ .word check_errata_\_id
+ .endif
+ /* Will fit CVEs with up to 10 character in the ID field */
+ .word \_id
+ .hword \_cve
+ .byte \_chosen
+ /* TODO(errata ABI): mitigated field for known but unmitigated
+ * errata*/
+ .byte 0x1
+ .popsection
+.endm
+
+/*
+ * Maintain compatibility with the old scheme of "each cpu has its own reporter".
+ * TODO remove entirely once all cpus have been converted. This includes the
+ * cpu_ops entry, as print_errata_status can call this directly for all cpus
+ */
+.macro errata_report_shim _cpu:req
+ #if REPORT_ERRATA
+ func \_cpu\()_errata_report
+ push {r12, lr}
+
+ bl generic_errata_report
+
+ pop {r12, lr}
+ bx lr
+ endfunc \_cpu\()_errata_report
+ #endif
+.endm
#endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
index 041be51..724624c 100644
--- a/include/lib/cpus/aarch64/cpu_macros.S
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -1,95 +1,14 @@
/*
- * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef CPU_MACROS_S
#define CPU_MACROS_S
-#include <arch.h>
#include <assert_macros.S>
-#include <lib/cpus/errata_report.h>
-
-#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
- (MIDR_PN_MASK << MIDR_PN_SHIFT)
-
-/* The number of CPU operations allowed */
-#define CPU_MAX_PWR_DWN_OPS 2
-
-/* Special constant to specify that CPU has no reset function */
-#define CPU_NO_RESET_FUNC 0
-
-#define CPU_NO_EXTRA1_FUNC 0
-#define CPU_NO_EXTRA2_FUNC 0
-#define CPU_NO_EXTRA3_FUNC 0
-
-/* Word size for 64-bit CPUs */
-#define CPU_WORD_SIZE 8
-
-/*
- * Whether errata status needs reporting. Errata status is printed in debug
- * builds for both BL1 and BL31 images.
- */
-#if (defined(IMAGE_BL1) || defined(IMAGE_BL31)) && DEBUG
-# define REPORT_ERRATA 1
-#else
-# define REPORT_ERRATA 0
-#endif
-
-
- .equ CPU_MIDR_SIZE, CPU_WORD_SIZE
- .equ CPU_EXTRA1_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_EXTRA2_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_EXTRA3_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_E_HANDLER_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
- .equ CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE
- .equ CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE
- .equ CPU_REG_DUMP_SIZE, CPU_WORD_SIZE
-
-#ifndef IMAGE_AT_EL3
- .equ CPU_RESET_FUNC_SIZE, 0
-#endif
-
-/* The power down core and cluster is needed only in BL31 */
-#ifndef IMAGE_BL31
- .equ CPU_PWR_DWN_OPS_SIZE, 0
-#endif
-
-/* Fields required to print errata status. */
-#if !REPORT_ERRATA
- .equ CPU_ERRATA_FUNC_SIZE, 0
-#endif
-
-/* Only BL31 requieres mutual exclusion and printed flag. */
-#if !(REPORT_ERRATA && defined(IMAGE_BL31))
- .equ CPU_ERRATA_LOCK_SIZE, 0
- .equ CPU_ERRATA_PRINTED_SIZE, 0
-#endif
-
-#if !defined(IMAGE_BL31) || !CRASH_REPORTING
- .equ CPU_REG_DUMP_SIZE, 0
-#endif
-
-/*
- * Define the offsets to the fields in cpu_ops structure.
- * Every offset is defined based in the offset and size of the previous
- * field.
- */
- .equ CPU_MIDR, 0
- .equ CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE
- .equ CPU_EXTRA1_FUNC, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
- .equ CPU_EXTRA2_FUNC, CPU_EXTRA1_FUNC + CPU_EXTRA1_FUNC_SIZE
- .equ CPU_EXTRA3_FUNC, CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE
- .equ CPU_E_HANDLER_FUNC, CPU_EXTRA3_FUNC + CPU_EXTRA3_FUNC_SIZE
- .equ CPU_PWR_DWN_OPS, CPU_E_HANDLER_FUNC + CPU_E_HANDLER_FUNC_SIZE
- .equ CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
- .equ CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
- .equ CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
- .equ CPU_REG_DUMP, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
- .equ CPU_OPS_SIZE, CPU_REG_DUMP + CPU_REG_DUMP_SIZE
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
/*
* Write given expressions as quad words
@@ -172,6 +91,27 @@
/* Insert list of functions */
fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
#endif
+ /*
+ * It is possible (although unlikely) that a cpu may have no errata in
+ * code. In that case the start label will not be defined. The list is
+ * intended to be used in a loop, so define it as zero-length for
+ * predictable behaviour. Since this macro is always called at the end
+ * of the cpu file (after all errata have been parsed) we can be sure
+ * that we are at the end of the list. Some cpus call declare_cpu_ops
+ * twice, so only do this once.
+ */
+ .pushsection .rodata.errata_entries
+ .ifndef \_name\()_errata_list_start
+ \_name\()_errata_list_start:
+ .endif
+ .ifndef \_name\()_errata_list_end
+ \_name\()_errata_list_end:
+ .endif
+ .popsection
+
+ /* and now put them in cpu_ops */
+ .quad \_name\()_errata_list_start
+ .quad \_name\()_errata_list_end
#if REPORT_ERRATA
.ifndef \_name\()_cpu_str
@@ -192,18 +132,20 @@
.popsection
.endif
+
/*
* Mandatory errata status printing function for CPUs of
* this class.
*/
.quad \_name\()_errata_report
+ .quad \_name\()_cpu_str
#ifdef IMAGE_BL31
/* Pointers to errata lock and reported flag */
.quad \_name\()_errata_lock
.quad \_name\()_errata_reported
-#endif
-#endif
+#endif /* IMAGE_BL31 */
+#endif /* REPORT_ERRATA */
#if defined(IMAGE_BL31) && CRASH_REPORTING
.quad \_name\()_cpu_reg_dump
@@ -229,6 +171,7 @@
\_extra1, \_extra2, \_extra3, 0, \_power_down_ops
.endm
+/* TODO can be deleted once all CPUs have been converted */
#if REPORT_ERRATA
/*
* Print status of a CPU errata
@@ -311,4 +254,322 @@
b.eq \_label
.endm
+
+/*
+ * Workaround wrappers for errata that apply at reset or runtime. Reset errata
+ * will be applied automatically
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * _apply_at_reset:
+ * Whether the erratum should be automatically applied at reset
+ */
+.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
+ .pushsection .rodata.errata_entries
+ .align 3
+ .ifndef \_cpu\()_errata_list_start
+ \_cpu\()_errata_list_start:
+ .endif
+
+ /* check if unused and compile out if no references */
+ .if \_apply_at_reset && \_chosen
+ .quad erratum_\_cpu\()_\_id\()_wa
+ .else
+ .quad 0
+ .endif
+ /* TODO(errata ABI): this prevents all checker functions from
+ * being optimised away. Can be done away with unless the ABI
+ * needs them */
+ .quad check_erratum_\_cpu\()_\_id
+ /* Will fit CVEs with up to 10 character in the ID field */
+ .word \_id
+ .hword \_cve
+ .byte \_chosen
+ /* TODO(errata ABI): mitigated field for known but unmitigated
+ * errata */
+ .byte 0x1
+ .popsection
+.endm
+
+.macro _workaround_start _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
+ add_erratum_entry \_cpu, \_cve, \_id, \_chosen, \_apply_at_reset
+
+ func erratum_\_cpu\()_\_id\()_wa
+ mov x8, x30
+
+ /* save rev_var for workarounds that might need it but don't
+ * restore to x0 because few will care */
+ mov x7, x0
+ bl check_erratum_\_cpu\()_\_id
+ cbz x0, erratum_\_cpu\()_\_id\()_skip
+.endm
+
+.macro _workaround_end _cpu:req, _id:req
+ erratum_\_cpu\()_\_id\()_skip:
+ ret x8
+ endfunc erratum_\_cpu\()_\_id\()_wa
+.endm
+
+/*******************************************************************************
+ * Errata workaround wrappers
+ ******************************************************************************/
+/*
+ * Workaround wrappers for errata that apply at reset or runtime. Reset errata
+ * will be applied automatically
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * in body:
+ * clobber x0 to x7 (please only use those)
+ * argument x7 - cpu_rev_var
+ *
+ * _wa clobbers: x0-x8 (PCS compliant)
+ */
+.macro workaround_reset_start _cpu:req, _cve:req, _id:req, _chosen:req
+ _workaround_start \_cpu, \_cve, \_id, \_chosen, 1
+.endm
+
+/*
+ * See `workaround_reset_start` for usage info. Additional arguments:
+ *
+ * _midr:
+ * Check if CPU's MIDR matches the CPU it's meant for. Must be specified
+ * for errata applied in generic code
+ */
+.macro workaround_runtime_start _cpu:req, _cve:req, _id:req, _chosen:req, _midr
+ /*
+ * Let errata specify if they need MIDR checking. Sadly, storing the
+ * MIDR in an .equ to retrieve automatically blows up as it stores some
+ * brackets in the symbol
+ */
+ .ifnb \_midr
+ jump_if_cpu_midr \_midr, 1f
+ b erratum_\_cpu\()_\_id\()_skip
+
+ 1:
+ .endif
+ _workaround_start \_cpu, \_cve, \_id, \_chosen, 0
+.endm
+
+/*
+ * Usage and arguments identical to `workaround_reset_start`. The _cve argument
+ * is kept here so the same #define can be used as that macro
+ */
+.macro workaround_reset_end _cpu:req, _cve:req, _id:req
+ _workaround_end \_cpu, \_id
+.endm
+
+/*
+ * See `workaround_reset_start` for usage info. The _cve argument is kept here
+ * so the same #define can be used as that macro. Additional arguments:
+ *
+ * _no_isb:
+ * Optionally do not include the trailing isb. Please disable with the
+ * NO_ISB macro
+ */
+.macro workaround_runtime_end _cpu:req, _cve:req, _id:req, _no_isb
+ /*
+ * Runtime errata do not have a reset function to call the isb for them
+ * and missing the isb could be very problematic. It is also likely as
+ * they tend to be scattered in generic code.
+ */
+ .ifb \_no_isb
+ isb
+ .endif
+ _workaround_end \_cpu, \_id
+.endm
+
+/*******************************************************************************
+ * Errata workaround helpers
+ ******************************************************************************/
+/*
+ * Set a bit in a system register. Can set multiple bits but is limited by the
+ * way the ORR instruction encodes them.
+ *
+ * _reg:
+ * Register to write to
+ *
+ * _bit:
+ * Bit to set. Please use a descriptive #define
+ *
+ * _assert:
+ * Optionally whether to read back and assert that the bit has been
+ * written. Please disable with NO_ASSERT macro
+ *
+ * clobbers: x1
+ */
+.macro sysreg_bit_set _reg:req, _bit:req, _assert=1
+ mrs x1, \_reg
+ orr x1, x1, #\_bit
+ msr \_reg, x1
+.endm
+
+/*
+ * Apply erratum
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _chosen:
+ * Compile time flag on whether the erratum is included
+ *
+ * clobbers: x0-x9 (PCS compliant)
+ */
+.macro apply_erratum _cpu:req, _cve:req, _id:req, _chosen:req
+ .if \_chosen
+ mov x9, x30
+ bl cpu_get_rev_var
+ bl erratum_\_cpu\()_\_id\()_wa
+ mov x30, x9
+
+ .endif
+.endm
+
+/*
+ * Helpers to select which revisions errata apply to. Don't leave a link
+ * register as the cpu_rev_var_*** will call the ret and we can save on one.
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * _cve:
+ * Whether erratum is a CVE. CVE year if yes, 0 otherwise
+ *
+ * _id:
+ * Erratum or CVE number. Please combine with previous field with ERRATUM
+ * or CVE macros
+ *
+ * _rev_num:
+ * Revision to apply to
+ *
+ * in body:
+ * clobber: x0 to x4
+ * argument: x0 - cpu_rev_var
+ */
+.macro check_erratum_ls _cpu:req, _cve:req, _id:req, _rev_num:req
+ func check_erratum_\_cpu\()_\_id
+ mov x1, #\_rev_num
+ b cpu_rev_var_ls
+ endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+.macro check_erratum_hs _cpu:req, _cve:req, _id:req, _rev_num:req
+ func check_erratum_\_cpu\()_\_id
+ mov x1, #\_rev_num
+ b cpu_rev_var_hs
+ endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+.macro check_erratum_range _cpu:req, _cve:req, _id:req, _rev_num_lo:req, _rev_num_hi:req
+ func check_erratum_\_cpu\()_\_id
+ mov x1, #\_rev_num_lo
+ mov x2, #\_rev_num_hi
+ b cpu_rev_var_range
+ endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+/*******************************************************************************
+ * CPU reset function wrapper
+ ******************************************************************************/
+
+/*
+ * Wrapper to automatically apply all reset-time errata. Will end with an isb.
+ *
+ * _cpu:
+ * Name of cpu as given to declare_cpu_ops
+ *
+ * in body:
+ * clobber x8 to x14
+ * argument x14 - cpu_rev_var
+ */
+.macro cpu_reset_func_start _cpu:req
+ func \_cpu\()_reset_func
+ mov x15, x30
+ bl cpu_get_rev_var
+ mov x14, x0
+
+ /* short circuit the location to avoid searching the list */
+ adrp x12, \_cpu\()_errata_list_start
+ add x12, x12, :lo12:\_cpu\()_errata_list_start
+ adrp x13, \_cpu\()_errata_list_end
+ add x13, x13, :lo12:\_cpu\()_errata_list_end
+
+ errata_begin:
+ /* if head catches up with end of list, exit */
+ cmp x12, x13
+ b.eq errata_end
+
+ ldr x10, [x12, #ERRATUM_WA_FUNC]
+ /* TODO(errata ABI): check mitigated and checker function fields
+ * for 0 */
+ ldrb w11, [x12, #ERRATUM_CHOSEN]
+
+ /* skip if not chosen */
+ cbz x11, 1f
+ /* skip if runtime erratum */
+ cbz x10, 1f
+
+ /* put cpu revision in x0 and call workaround */
+ mov x0, x14
+ blr x10
+ 1:
+ add x12, x12, #ERRATUM_ENTRY_SIZE
+ b errata_begin
+ errata_end:
+.endm
+
+.macro cpu_reset_func_end _cpu:req
+ isb
+ ret x15
+ endfunc \_cpu\()_reset_func
+.endm
+
+/*
+ * Maintain compatibility with the old scheme of each cpu has its own reporting.
+ * TODO remove entirely once all cpus have been converted. This includes the
+ * cpu_ops entry, as print_errata_status can call this directly for all cpus
+ */
+.macro errata_report_shim _cpu:req
+ #if REPORT_ERRATA
+ func \_cpu\()_errata_report
+ /* normal stack frame for pretty debugging */
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ bl generic_errata_report
+
+ ldp x29, x30, [sp], #16
+ ret
+ endfunc \_cpu\()_errata_report
+ #endif
+.endm
#endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/cpu_ops.h b/include/lib/cpus/cpu_ops.h
new file mode 100644
index 0000000..8b36ff1
--- /dev/null
+++ b/include/lib/cpus/cpu_ops.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CPU_OPS_H
+#define CPU_OPS_H
+
+#include <arch.h>
+
+#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
+ (MIDR_PN_MASK << MIDR_PN_SHIFT)
+
+/* Hardcode to keep compatible with assembly. sizeof(uintptr_t) */
+#if __aarch64__
+#define CPU_WORD_SIZE 8
+#else
+#define CPU_WORD_SIZE 4
+#endif /* __aarch64__ */
+
+/* The number of CPU operations allowed */
+#define CPU_MAX_PWR_DWN_OPS 2
+/* Special constant to specify that CPU has no reset function */
+#define CPU_NO_RESET_FUNC 0
+
+#if __aarch64__
+#define CPU_NO_EXTRA1_FUNC 0
+#define CPU_NO_EXTRA2_FUNC 0
+#define CPU_NO_EXTRA3_FUNC 0
+#endif /* __aarch64__ */
+
+
+/*
+ * Define the sizes of the fields in the cpu_ops structure. Word size is set per
+ * Aarch so keep these definitions the same and each can include whatever it
+ * needs.
+ */
+#define CPU_MIDR_SIZE CPU_WORD_SIZE
+#ifdef IMAGE_AT_EL3
+#define CPU_RESET_FUNC_SIZE CPU_WORD_SIZE
+#else
+#define CPU_RESET_FUNC_SIZE 0
+#endif /* IMAGE_AT_EL3 */
+#define CPU_EXTRA1_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_EXTRA2_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_EXTRA3_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_E_HANDLER_FUNC_SIZE CPU_WORD_SIZE
+/* The power down core and cluster is needed only in BL31 and BL32 */
+#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+#define CPU_PWR_DWN_OPS_SIZE CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
+#else
+#define CPU_PWR_DWN_OPS_SIZE 0
+#endif /* defined(IMAGE_BL31) || defined(IMAGE_BL32) */
+
+#define CPU_ERRATA_LIST_START_SIZE CPU_WORD_SIZE
+#define CPU_ERRATA_LIST_END_SIZE CPU_WORD_SIZE
+/* Fields required to print errata status */
+#if REPORT_ERRATA
+#define CPU_ERRATA_FUNC_SIZE CPU_WORD_SIZE
+#define CPU_CPU_STR_SIZE CPU_WORD_SIZE
+/* BL1 doesn't require mutual exclusion and printed flag. */
+#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+#define CPU_ERRATA_LOCK_SIZE CPU_WORD_SIZE
+#define CPU_ERRATA_PRINTED_SIZE CPU_WORD_SIZE
+#else
+#define CPU_ERRATA_LOCK_SIZE 0
+#define CPU_ERRATA_PRINTED_SIZE 0
+#endif /* defined(IMAGE_BL31) || defined(IMAGE_BL32) */
+#else
+#define CPU_ERRATA_FUNC_SIZE 0
+#define CPU_CPU_STR_SIZE 0
+#define CPU_ERRATA_LOCK_SIZE 0
+#define CPU_ERRATA_PRINTED_SIZE 0
+#endif /* REPORT_ERRATA */
+
+#if defined(IMAGE_BL31) && CRASH_REPORTING
+#define CPU_REG_DUMP_SIZE CPU_WORD_SIZE
+#else
+#define CPU_REG_DUMP_SIZE 0
+#endif /* defined(IMAGE_BL31) && CRASH_REPORTING */
+
+
+/*
+ * Define the offsets to the fields in cpu_ops structure. Every offset is
+ * defined based on the offset and size of the previous field.
+ */
+#define CPU_MIDR 0
+#define CPU_RESET_FUNC CPU_MIDR + CPU_MIDR_SIZE
+#if __aarch64__
+#define CPU_EXTRA1_FUNC CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
+#define CPU_EXTRA2_FUNC CPU_EXTRA1_FUNC + CPU_EXTRA1_FUNC_SIZE
+#define CPU_EXTRA3_FUNC CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE
+#define CPU_E_HANDLER_FUNC CPU_EXTRA3_FUNC + CPU_EXTRA3_FUNC_SIZE
+#define CPU_PWR_DWN_OPS CPU_E_HANDLER_FUNC + CPU_E_HANDLER_FUNC_SIZE
+#else
+#define CPU_PWR_DWN_OPS CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
+#endif /* __aarch64__ */
+#define CPU_ERRATA_LIST_START CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
+#define CPU_ERRATA_LIST_END CPU_ERRATA_LIST_START + CPU_ERRATA_LIST_START_SIZE
+#define CPU_ERRATA_FUNC CPU_ERRATA_LIST_END + CPU_ERRATA_LIST_END_SIZE
+#define CPU_CPU_STR CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
+#define CPU_ERRATA_LOCK CPU_CPU_STR + CPU_CPU_STR_SIZE
+#define CPU_ERRATA_PRINTED CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
+#if __aarch64__
+#define CPU_REG_DUMP CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+#define CPU_OPS_SIZE CPU_REG_DUMP + CPU_REG_DUMP_SIZE
+#else
+#define CPU_OPS_SIZE CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+#endif /* __aarch64__ */
+
+#ifndef __ASSEMBLER__
+#include <lib/cassert.h>
+#include <lib/spinlock.h>
+
+struct cpu_ops {
+ unsigned long midr;
+#ifdef IMAGE_AT_EL3
+ void (*reset_func)(void);
+#endif /* IMAGE_AT_EL3 */
+#if __aarch64__
+ void (*extra1_func)(void);
+ void (*extra2_func)(void);
+ void (*extra3_func)(void);
+ void (*e_handler_func)(long es);
+#endif /* __aarch64__ */
+#if (defined(IMAGE_BL31) || defined(IMAGE_BL32)) && CPU_MAX_PWR_DWN_OPS
+ void (*pwr_dwn_ops[CPU_MAX_PWR_DWN_OPS])(void);
+#endif /* (defined(IMAGE_BL31) || defined(IMAGE_BL32)) && CPU_MAX_PWR_DWN_OPS */
+ void *errata_list_start;
+ void *errata_list_end;
+#if REPORT_ERRATA
+ void (*errata_func)(void);
+ char *cpu_str;
+#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+ spinlock_t *errata_lock;
+ unsigned int *errata_reported;
+#endif /* defined(IMAGE_BL31) || defined(IMAGE_BL32) */
+#endif /* REPORT_ERRATA */
+#if defined(IMAGE_BL31) && CRASH_REPORTING
+ void (*reg_dump)(void);
+#endif /* defined(IMAGE_BL31) && CRASH_REPORTING */
+} __packed;
+
+CASSERT(sizeof(struct cpu_ops) == CPU_OPS_SIZE,
+ assert_cpu_ops_asm_c_different_sizes);
+
+long cpu_get_rev_var(void);
+void *get_cpu_ops_ptr(void);
+
+#endif /* __ASSEMBLER__ */
+#endif /* CPU_OPS_H */
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
new file mode 100644
index 0000000..f8f9555
--- /dev/null
+++ b/include/lib/cpus/errata.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ERRATA_REPORT_H
+#define ERRATA_REPORT_H
+
+#include <lib/cpus/cpu_ops.h>
+
+
+#define ERRATUM_WA_FUNC_SIZE CPU_WORD_SIZE
+#define ERRATUM_CHECK_FUNC_SIZE CPU_WORD_SIZE
+#define ERRATUM_ID_SIZE 4
+#define ERRATUM_CVE_SIZE 2
+#define ERRATUM_CHOSEN_SIZE 1
+#define ERRATUM_MITIGATED_SIZE 1
+
+#define ERRATUM_WA_FUNC 0
+#define ERRATUM_CHECK_FUNC ERRATUM_WA_FUNC + ERRATUM_WA_FUNC_SIZE
+#define ERRATUM_ID ERRATUM_CHECK_FUNC + ERRATUM_CHECK_FUNC_SIZE
+#define ERRATUM_CVE ERRATUM_ID + ERRATUM_ID_SIZE
+#define ERRATUM_CHOSEN ERRATUM_CVE + ERRATUM_CVE_SIZE
+#define ERRATUM_MITIGATED ERRATUM_CHOSEN + ERRATUM_CHOSEN_SIZE
+#define ERRATUM_ENTRY_SIZE ERRATUM_MITIGATED + ERRATUM_MITIGATED_SIZE
+
+#ifndef __ASSEMBLER__
+#include <lib/cassert.h>
+
+void print_errata_status(void);
+void errata_print_msg(unsigned int status, const char *cpu, const char *id);
+
+/*
+ * NOTE that this structure will be different on AArch32 and AArch64. The
+ * uintptr_t will reflect the change and the alignment will be correct in both.
+ */
+struct erratum_entry {
+ uintptr_t (*wa_func)(uint64_t cpu_rev);
+ uintptr_t (*check_func)(uint64_t cpu_rev);
+ /* Will fit CVEs with up to 10 character in the ID field */
+ uint32_t id;
+ /* Denote CVEs with their year or errata with 0 */
+ uint16_t cve;
+ uint8_t chosen;
+ /* TODO(errata ABI): placeholder for the mitigated field */
+ uint8_t _mitigated;
+} __packed;
+
+CASSERT(sizeof(struct erratum_entry) == ERRATUM_ENTRY_SIZE,
+ assert_erratum_entry_asm_c_different_sizes);
+#else
+
+/*
+ * errata framework macro helpers
+ *
+ * NOTE an erratum and CVE id could clash. However, both numbers are very large
+ * and the probablity is minuscule. Working around this makes code very
+ * complicated and extremely difficult to read so it is not considered. In the
+ * unlikely event that this does happen, prepending the CVE id with a 0 should
+ * resolve the conflict
+ */
+#define ERRATUM(id) 0, id
+#define CVE(year, id) year, id
+#define NO_ISB 1
+#define NO_ASSERT 0
+
+#endif /* __ASSEMBLER__ */
+
+/* Errata status */
+#define ERRATA_NOT_APPLIES 0
+#define ERRATA_APPLIES 1
+#define ERRATA_MISSING 2
+
+/* Macro to get CPU revision code for checking errata version compatibility. */
+#define CPU_REV(r, p) ((r << 4) | p)
+
+#endif /* ERRATA_REPORT_H */
diff --git a/include/lib/cpus/errata_report.h b/include/lib/cpus/errata_report.h
deleted file mode 100644
index efdedf0..0000000
--- a/include/lib/cpus/errata_report.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef ERRATA_REPORT_H
-#define ERRATA_REPORT_H
-
-#ifndef __ASSEMBLER__
-
-#include <arch.h>
-#include <arch_helpers.h>
-#include <lib/spinlock.h>
-#include <lib/utils_def.h>
-
-#if DEBUG
-void print_errata_status(void);
-#else
-static inline void print_errata_status(void) {}
-#endif
-
-void errata_print_msg(unsigned int status, const char *cpu, const char *id);
-int errata_needs_reporting(spinlock_t *lock, uint32_t *reported);
-
-#endif /* __ASSEMBLER__ */
-
-/* Errata status */
-#define ERRATA_NOT_APPLIES 0
-#define ERRATA_APPLIES 1
-#define ERRATA_MISSING 2
-
-/* Macro to get CPU revision code for checking errata version compatibility. */
-#define CPU_REV(r, p) ((r << 4) | p)
-
-#endif /* ERRATA_REPORT_H */
diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S
index e25ce2a..05bc5d9 100644
--- a/lib/cpus/aarch32/cpu_helpers.S
+++ b/lib/cpus/aarch32/cpu_helpers.S
@@ -9,6 +9,7 @@
#include <assert_macros.S>
#include <cpu_macros.S>
#include <common/bl_common.h>
+#include <lib/cpus/cpu_ops.h>
#include <lib/el3_runtime/cpu_data.h>
#if defined(IMAGE_BL1) || defined(IMAGE_BL32) || \
@@ -204,62 +205,3 @@
movlt r0, #ERRATA_NOT_APPLIES
bx lr
endfunc cpu_rev_var_hs
-
-#if REPORT_ERRATA
-/*
- * void print_errata_status(void);
- *
- * Function to print errata status for CPUs of its class. Must be called only:
- *
- * - with MMU and data caches are enabled;
- * - after cpu_ops have been initialized in per-CPU data.
- */
- .globl print_errata_status
-func print_errata_status
- /* r12 is pushed only for the sake of 8-byte stack alignment */
- push {r4, r5, r12, lr}
-#ifdef IMAGE_BL1
- /*
- * BL1 doesn't have per-CPU data. So retrieve the CPU operations
- * directly.
- */
- bl get_cpu_ops_ptr
- ldr r0, [r0, #CPU_ERRATA_FUNC]
- cmp r0, #0
- blxne r0
-#else
- /*
- * Retrieve pointer to cpu_ops, and further, the errata printing
- * function. If it's non-NULL, jump to the function in turn.
- */
- bl _cpu_data
-#if ENABLE_ASSERTIONS
- cmp r0, #0
- ASM_ASSERT(ne)
-#endif
- ldr r1, [r0, #CPU_DATA_CPU_OPS_PTR]
-#if ENABLE_ASSERTIONS
- cmp r1, #0
- ASM_ASSERT(ne)
-#endif
- ldr r0, [r1, #CPU_ERRATA_FUNC]
- cmp r0, #0
- beq 1f
-
- mov r4, r0
-
- /*
- * Load pointers to errata lock and printed flag. Call
- * errata_needs_reporting to check whether this CPU needs to report
- * errata status pertaining to its class.
- */
- ldr r0, [r1, #CPU_ERRATA_LOCK]
- ldr r1, [r1, #CPU_ERRATA_PRINTED]
- bl errata_needs_reporting
- cmp r0, #0
- blxne r4
-1:
-#endif
- pop {r4, r5, r12, pc}
-endfunc print_errata_status
-#endif
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
index df11d86..ecaf422 100644
--- a/lib/cpus/aarch64/cortex_a53.S
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -9,8 +9,8 @@
#include <common/debug.h>
#include <cortex_a53.h>
#include <cpu_macros.S>
-#include <lib/cpus/errata_report.h>
#include <plat_macros.S>
+#include <lib/cpus/errata.h>
#if A53_DISABLE_NON_TEMPORAL_HINT
#undef ERRATA_A53_836870
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
index 0a03e38..a4285ed 100644
--- a/lib/cpus/aarch64/cpu_helpers.S
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -10,7 +10,8 @@
#include <common/bl_common.h>
#include <common/debug.h>
#include <cpu_macros.S>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
#include <lib/el3_runtime/cpu_data.h>
/* Reset fn is needed in BL at reset vector */
@@ -279,72 +280,6 @@
ret
endfunc cpu_rev_var_range
-#if REPORT_ERRATA
-/*
- * void print_errata_status(void);
- *
- * Function to print errata status for CPUs of its class. Must be called only:
- *
- * - with MMU and data caches are enabled;
- * - after cpu_ops have been initialized in per-CPU data.
- */
- .globl print_errata_status
-func print_errata_status
-#ifdef IMAGE_BL1
- /*
- * BL1 doesn't have per-CPU data. So retrieve the CPU operations
- * directly.
- */
- stp xzr, x30, [sp, #-16]!
- bl get_cpu_ops_ptr
- ldp xzr, x30, [sp], #16
- ldr x1, [x0, #CPU_ERRATA_FUNC]
- cbnz x1, .Lprint
-#else
- /*
- * Retrieve pointer to cpu_ops from per-CPU data, and further, the
- * errata printing function. If it's non-NULL, jump to the function in
- * turn.
- */
- mrs x0, tpidr_el3
-#if ENABLE_ASSERTIONS
- cmp x0, #0
- ASM_ASSERT(ne)
-#endif
- ldr x1, [x0, #CPU_DATA_CPU_OPS_PTR]
-#if ENABLE_ASSERTIONS
- cmp x1, #0
- ASM_ASSERT(ne)
-#endif
- ldr x0, [x1, #CPU_ERRATA_FUNC]
- cbz x0, .Lnoprint
-
- /*
- * Printing errata status requires atomically testing the printed flag.
- */
- stp x19, x30, [sp, #-16]!
- mov x19, x0
-
- /*
- * Load pointers to errata lock and printed flag. Call
- * errata_needs_reporting to check whether this CPU needs to report
- * errata status pertaining to its class.
- */
- ldr x0, [x1, #CPU_ERRATA_LOCK]
- ldr x1, [x1, #CPU_ERRATA_PRINTED]
- bl errata_needs_reporting
- mov x1, x19
- ldp x19, x30, [sp], #16
- cbnz x0, .Lprint
-#endif
-.Lnoprint:
- ret
-.Lprint:
- /* Jump to errata reporting function for this CPU */
- br x1
-endfunc print_errata_status
-#endif
-
/*
* int check_wa_cve_2017_5715(void);
*
diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
index 419b6ea..b7e028a 100644
--- a/lib/cpus/aarch64/dsu_helpers.S
+++ b/lib/cpus/aarch64/dsu_helpers.S
@@ -6,7 +6,7 @@
#include <asm_macros.S>
#include <dsu_def.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
/* -----------------------------------------------------------------------
* DSU erratum 798953 check function
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index 5f41aee..a37ba81 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,7 +11,8 @@
#include <arch_helpers.h>
#include <common/debug.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/cpus/errata.h>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/spinlock.h>
@@ -30,11 +31,93 @@
/* Errata format: BL stage, CPU, errata ID, message */
#define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n"
+#define CVE_FORMAT "%s: %s: CPU workaround for CVE %u_%u was %s\n"
+#define ERRATUM_FORMAT "%s: %s: CPU workaround for erratum %u was %s\n"
+
+#define PRINT_STATUS_DISPATCH(status, ...) \
+ do { \
+ assert(status <= ERRATA_MISSING); \
+ switch (status) { \
+ case ERRATA_NOT_APPLIES: \
+ VERBOSE(__VA_ARGS__, "not applied"); \
+ break; \
+ case ERRATA_APPLIES: \
+ INFO(__VA_ARGS__, "applied"); \
+ break; \
+ case ERRATA_MISSING: \
+ WARN(__VA_ARGS__, "missing!"); \
+ break; \
+ } \
+ } while (0)
+
+
+#if !REPORT_ERRATA
+void print_errata_status(void) {}
+#else /* !REPORT_ERRATA */
+/* New errata status message printer */
+void __unused generic_errata_report(void)
+{
+ struct cpu_ops *cpu_ops = get_cpu_ops_ptr();
+ struct erratum_entry *entry = cpu_ops->errata_list_start;
+ struct erratum_entry *end = cpu_ops->errata_list_end;
+ long rev_var = cpu_get_rev_var();
+ uint32_t last_erratum_id = 0;
+ uint16_t last_cve_yr = 0;
+ bool check_cve = false;
+ /* unused because assert goes away on release */
+ bool failed __unused = false;
+
+ for (; entry != end; entry += 1) {
+ uint64_t status = entry->check_func(rev_var);
+
+ assert(entry->id != 0);
+
+ /*
+ * Errata workaround has not been compiled in. If the errata
+ * would have applied had it been compiled in, print its status
+ * as missing.
+ */
+ if (status == ERRATA_APPLIES && entry->chosen == 0) {
+ status = ERRATA_MISSING;
+ }
+
+ if (entry->cve) {
+ PRINT_STATUS_DISPATCH(status, CVE_FORMAT, BL_STRING,
+ cpu_ops->cpu_str, entry->cve, entry->id);
+
+ if (last_cve_yr > entry->cve ||
+ (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
+ ERROR("CVE %u_%u was out of order!\n",
+ entry->cve, entry->id);
+ failed = true;
+ }
+ check_cve = true;
+ last_cve_yr = entry->cve;
+ } else {
+ PRINT_STATUS_DISPATCH(status, ERRATUM_FORMAT, BL_STRING,
+ cpu_ops->cpu_str, entry->id);
+
+ if (last_erratum_id >= entry->id || check_cve) {
+ ERROR("Erratum %u was out of order!\n",
+ entry->id);
+ failed = true;
+ }
+ }
+ last_erratum_id = entry->id;
+ }
+
+ /*
+ * enforce errata and CVEs are in ascending order and that CVEs are
+ * after errata
+ */
+ assert(!failed);
+}
+
/*
* Returns whether errata needs to be reported. Passed arguments are private to
* a CPU type.
*/
-int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
+static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
{
bool report_now;
@@ -56,14 +139,44 @@
}
/*
- * Print errata status message.
- *
- * Unknown: WARN
- * Missing: WARN
- * Applied: INFO
- * Not applied: VERBOSE
+ * Function to print errata status for the calling CPU (and others of the same
+ * type). Must be called only:
+ * - when MMU and data caches are enabled;
+ * - after cpu_ops have been initialized in per-CPU data.
+ */
+void print_errata_status(void)
+{
+ struct cpu_ops *cpu_ops;
+#ifdef IMAGE_BL1
+ /*
+ * BL1 doesn't have per-CPU data. So retrieve the CPU operations
+ * directly.
+ */
+ cpu_ops = get_cpu_ops_ptr();
+
+ if (cpu_ops->errata_func != NULL) {
+ cpu_ops->errata_func();
+ }
+#else /* IMAGE_BL1 */
+ cpu_ops = (void *) get_cpu_data(cpu_ops_ptr);
+
+ assert(cpu_ops != NULL);
+
+ if (cpu_ops->errata_func == NULL) {
+ return;
+ }
+
+ if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) {
+ cpu_ops->errata_func();
+ }
+#endif /* IMAGE_BL1 */
+}
+
+/*
+ * Old errata status message printer
+ * TODO: remove once all cpus have been converted to the new printing method
*/
-void errata_print_msg(unsigned int status, const char *cpu, const char *id)
+void __unused errata_print_msg(unsigned int status, const char *cpu, const char *id)
{
/* Errata status strings */
static const char *const errata_status_str[] = {
@@ -99,3 +212,4 @@
break;
}
}
+#endif /* !REPORT_ERRATA */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 16d6e45..1f93cc9 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -11,8 +11,8 @@
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <context.h>
+#include <lib/cpus/errata.h>
#include <lib/el3_runtime/context_mgmt.h>
-#include <lib/cpus/errata_report.h>
#include <plat/common/platform.h>
#include "psci_private.h"
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_main.c b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
index 841a176..252fc31 100644
--- a/plat/arm/board/fvp_r/fvp_r_bl1_main.c
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
@@ -15,7 +15,7 @@
#include <common/debug.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/console.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
#include <lib/utils.h>
#include <smccc_helpers.h>
#include <tools_share/uuid.h>
diff --git a/plat/arm/board/fvp_r/platform.mk b/plat/arm/board/fvp_r/platform.mk
index 5dd28b9..f14ea54 100644
--- a/plat/arm/board/fvp_r/platform.mk
+++ b/plat/arm/board/fvp_r/platform.mk
@@ -83,6 +83,7 @@
drivers/io/io_storage.c \
drivers/io/io_semihosting.c \
lib/cpus/aarch64/cpu_helpers.S \
+ lib/cpus/errata_report.c \
lib/fconf/fconf_dyn_cfg_getter.c \
lib/semihosting/semihosting.c \
lib/semihosting/${ARCH}/semihosting_call.S \
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
index 46ccd9e..bb042c7 100644
--- a/services/arm_arch_svc/arm_arch_svc_setup.c
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -6,7 +6,7 @@
#include <common/debug.h>
#include <common/runtime_svc.h>
-#include <lib/cpus/errata_report.h>
+#include <lib/cpus/errata.h>
#include <lib/cpus/wa_cve_2017_5715.h>
#include <lib/cpus/wa_cve_2018_3639.h>
#include <lib/cpus/wa_cve_2022_23960.h>