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
This commit is contained in:
Lauren Wehrmeister 2023-05-31 23:06:53 +02:00 committed by TrustedFirmware Code Review
commit 0cfa06b22b
19 changed files with 826 additions and 346 deletions

View file

@ -710,16 +710,23 @@ endif
BL32_LDFLAGS += $(PIE_LDFLAGS) BL32_LDFLAGS += $(PIE_LDFLAGS)
endif endif
ifeq (${ARCH},aarch64) BL1_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
BL31_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
BL32_CPPFLAGS += -DREPORT_ERRATA=${DEBUG}
BL1_CPPFLAGS += -DIMAGE_AT_EL3 BL1_CPPFLAGS += -DIMAGE_AT_EL3
ifeq ($(RESET_TO_BL2),1) ifeq ($(RESET_TO_BL2),1)
BL2_CPPFLAGS += -DIMAGE_AT_EL3 BL2_CPPFLAGS += -DIMAGE_AT_EL3
else else
BL2_CPPFLAGS += -DIMAGE_AT_EL1 BL2_CPPFLAGS += -DIMAGE_AT_EL1
endif endif
ifeq (${ARCH},aarch64)
BL2U_CPPFLAGS += -DIMAGE_AT_EL1 BL2U_CPPFLAGS += -DIMAGE_AT_EL1
BL31_CPPFLAGS += -DIMAGE_AT_EL3 BL31_CPPFLAGS += -DIMAGE_AT_EL3
BL32_CPPFLAGS += -DIMAGE_AT_EL1 BL32_CPPFLAGS += -DIMAGE_AT_EL1
else
BL32_CPPFLAGS += -DIMAGE_AT_EL3
endif endif
# Include the CPU specific operations makefile, which provides default # Include the CPU specific operations makefile, which provides default

View file

@ -17,7 +17,7 @@
#include <drivers/auth/auth_mod.h> #include <drivers/auth/auth_mod.h>
#include <drivers/auth/crypto_mod.h> #include <drivers/auth/crypto_mod.h>
#include <drivers/console.h> #include <drivers/console.h>
#include <lib/cpus/errata_report.h> #include <lib/cpus/errata.h>
#include <lib/utils.h> #include <lib/utils.h>
#include <plat/common/platform.h> #include <plat/common/platform.h>
#include <smccc_helpers.h> #include <smccc_helpers.h>

View file

@ -41,8 +41,7 @@ else
BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \ BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \
bl2/${ARCH}/bl2_el3_exceptions.S \ bl2/${ARCH}/bl2_el3_exceptions.S \
bl2/${ARCH}/bl2_run_next_image.S \ bl2/${ARCH}/bl2_run_next_image.S \
lib/cpus/${ARCH}/cpu_helpers.S \ lib/cpus/${ARCH}/cpu_helpers.S
lib/cpus/errata_report.c
ifeq (${DISABLE_MTPMU},1) ifeq (${DISABLE_MTPMU},1)
BL2_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S BL2_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S

View file

@ -33,10 +33,10 @@
#define UINT8_LEN 8U #define UINT8_LEN 8U
#define UINT64_LEN (UINT8_LEN * sizeof(uint64_t)) #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_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_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" #define DT_PKA_COMPAT "st,stm32-pka64"

View file

@ -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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -8,6 +8,7 @@
#include <arch.h> #include <arch.h>
#include <common/asm_macros_common.S> #include <common/asm_macros_common.S>
#include <lib/cpus/cpu_ops.h>
#include <lib/spinlock.h> #include <lib/spinlock.h>
/* /*
@ -24,8 +25,6 @@
stcopr _reg, _coproc stcopr _reg, _coproc
#endif #endif
#define WORD_SIZE 4
/* /*
* Co processor register accessors * Co processor register accessors
*/ */
@ -49,14 +48,14 @@
.macro dcache_line_size reg, tmp .macro dcache_line_size reg, tmp
ldcopr \tmp, CTR ldcopr \tmp, CTR
ubfx \tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH ubfx \tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH
mov \reg, #WORD_SIZE mov \reg, #CPU_WORD_SIZE
lsl \reg, \reg, \tmp lsl \reg, \reg, \tmp
.endm .endm
.macro icache_line_size reg, tmp .macro icache_line_size reg, tmp
ldcopr \tmp, CTR ldcopr \tmp, CTR
and \tmp, \tmp, #CTR_IMINLINE_MASK and \tmp, \tmp, #CTR_IMINLINE_MASK
mov \reg, #WORD_SIZE mov \reg, #CPU_WORD_SIZE
lsl \reg, \reg, \tmp lsl \reg, \reg, \tmp
.endm .endm

View file

@ -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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
#ifndef CPU_MACROS_S #ifndef CPU_MACROS_S
#define CPU_MACROS_S #define CPU_MACROS_S
#include <arch.h> #include <lib/cpus/cpu_ops.h>
#include <lib/cpus/errata_report.h> #include <lib/cpus/errata.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
/* /*
* Write given expressions as words * Write given expressions as words
@ -142,6 +73,29 @@
fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
#endif #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 #if REPORT_ERRATA
.ifndef \_name\()_cpu_str .ifndef \_name\()_cpu_str
/* /*
@ -166,6 +120,7 @@
* this class. * this class.
*/ */
.word \_name\()_errata_report .word \_name\()_errata_report
.word \_name\()_cpu_str
#ifdef IMAGE_BL32 #ifdef IMAGE_BL32
/* Pointers to errata lock and reported flag */ /* Pointers to errata lock and reported flag */
@ -228,4 +183,77 @@
beq \_label beq \_label
.endm .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 */ #endif /* CPU_MACROS_S */

View file

@ -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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
#ifndef CPU_MACROS_S #ifndef CPU_MACROS_S
#define CPU_MACROS_S #define CPU_MACROS_S
#include <arch.h>
#include <assert_macros.S> #include <assert_macros.S>
#include <lib/cpus/errata_report.h> #include <lib/cpus/cpu_ops.h>
#include <lib/cpus/errata.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
/* /*
* Write given expressions as quad words * Write given expressions as quad words
@ -172,6 +91,27 @@
/* Insert list of functions */ /* Insert list of functions */
fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
#endif #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 #if REPORT_ERRATA
.ifndef \_name\()_cpu_str .ifndef \_name\()_cpu_str
@ -192,18 +132,20 @@
.popsection .popsection
.endif .endif
/* /*
* Mandatory errata status printing function for CPUs of * Mandatory errata status printing function for CPUs of
* this class. * this class.
*/ */
.quad \_name\()_errata_report .quad \_name\()_errata_report
.quad \_name\()_cpu_str
#ifdef IMAGE_BL31 #ifdef IMAGE_BL31
/* Pointers to errata lock and reported flag */ /* Pointers to errata lock and reported flag */
.quad \_name\()_errata_lock .quad \_name\()_errata_lock
.quad \_name\()_errata_reported .quad \_name\()_errata_reported
#endif #endif /* IMAGE_BL31 */
#endif #endif /* REPORT_ERRATA */
#if defined(IMAGE_BL31) && CRASH_REPORTING #if defined(IMAGE_BL31) && CRASH_REPORTING
.quad \_name\()_cpu_reg_dump .quad \_name\()_cpu_reg_dump
@ -229,6 +171,7 @@
\_extra1, \_extra2, \_extra3, 0, \_power_down_ops \_extra1, \_extra2, \_extra3, 0, \_power_down_ops
.endm .endm
/* TODO can be deleted once all CPUs have been converted */
#if REPORT_ERRATA #if REPORT_ERRATA
/* /*
* Print status of a CPU errata * Print status of a CPU errata
@ -311,4 +254,322 @@
b.eq \_label b.eq \_label
.endm .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 */ #endif /* CPU_MACROS_S */

152
include/lib/cpus/cpu_ops.h Normal file
View file

@ -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 */

78
include/lib/cpus/errata.h Normal file
View file

@ -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 */

View file

@ -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 */

View file

@ -9,6 +9,7 @@
#include <assert_macros.S> #include <assert_macros.S>
#include <cpu_macros.S> #include <cpu_macros.S>
#include <common/bl_common.h> #include <common/bl_common.h>
#include <lib/cpus/cpu_ops.h>
#include <lib/el3_runtime/cpu_data.h> #include <lib/el3_runtime/cpu_data.h>
#if defined(IMAGE_BL1) || defined(IMAGE_BL32) || \ #if defined(IMAGE_BL1) || defined(IMAGE_BL32) || \
@ -204,62 +205,3 @@ func cpu_rev_var_hs
movlt r0, #ERRATA_NOT_APPLIES movlt r0, #ERRATA_NOT_APPLIES
bx lr bx lr
endfunc cpu_rev_var_hs 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

View file

@ -9,8 +9,8 @@
#include <common/debug.h> #include <common/debug.h>
#include <cortex_a53.h> #include <cortex_a53.h>
#include <cpu_macros.S> #include <cpu_macros.S>
#include <lib/cpus/errata_report.h>
#include <plat_macros.S> #include <plat_macros.S>
#include <lib/cpus/errata.h>
#if A53_DISABLE_NON_TEMPORAL_HINT #if A53_DISABLE_NON_TEMPORAL_HINT
#undef ERRATA_A53_836870 #undef ERRATA_A53_836870

View file

@ -10,7 +10,8 @@
#include <common/bl_common.h> #include <common/bl_common.h>
#include <common/debug.h> #include <common/debug.h>
#include <cpu_macros.S> #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> #include <lib/el3_runtime/cpu_data.h>
/* Reset fn is needed in BL at reset vector */ /* Reset fn is needed in BL at reset vector */
@ -279,72 +280,6 @@ func cpu_rev_var_range
ret ret
endfunc cpu_rev_var_range 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); * int check_wa_cve_2017_5715(void);
* *

View file

@ -6,7 +6,7 @@
#include <asm_macros.S> #include <asm_macros.S>
#include <dsu_def.h> #include <dsu_def.h>
#include <lib/cpus/errata_report.h> #include <lib/cpus/errata.h>
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* DSU erratum 798953 check function * DSU erratum 798953 check function

View file

@ -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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -11,7 +11,8 @@
#include <arch_helpers.h> #include <arch_helpers.h>
#include <common/debug.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/el3_runtime/cpu_data.h>
#include <lib/spinlock.h> #include <lib/spinlock.h>
@ -30,11 +31,93 @@
/* Errata format: BL stage, CPU, errata ID, message */ /* Errata format: BL stage, CPU, errata ID, message */
#define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n" #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 * Returns whether errata needs to be reported. Passed arguments are private to
* a CPU type. * 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; bool report_now;
@ -56,14 +139,44 @@ int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
} }
/* /*
* Print errata status message. * Function to print errata status for the calling CPU (and others of the same
* * type). Must be called only:
* Unknown: WARN * - when MMU and data caches are enabled;
* Missing: WARN * - after cpu_ops have been initialized in per-CPU data.
* Applied: INFO
* Not applied: VERBOSE
*/ */
void errata_print_msg(unsigned int status, const char *cpu, const char *id) 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 __unused errata_print_msg(unsigned int status, const char *cpu, const char *id)
{ {
/* Errata status strings */ /* Errata status strings */
static const char *const errata_status_str[] = { static const char *const errata_status_str[] = {
@ -99,3 +212,4 @@ void errata_print_msg(unsigned int status, const char *cpu, const char *id)
break; break;
} }
} }
#endif /* !REPORT_ERRATA */

View file

@ -11,8 +11,8 @@
#include <arch_helpers.h> #include <arch_helpers.h>
#include <common/bl_common.h> #include <common/bl_common.h>
#include <context.h> #include <context.h>
#include <lib/cpus/errata.h>
#include <lib/el3_runtime/context_mgmt.h> #include <lib/el3_runtime/context_mgmt.h>
#include <lib/cpus/errata_report.h>
#include <plat/common/platform.h> #include <plat/common/platform.h>
#include "psci_private.h" #include "psci_private.h"

View file

@ -15,7 +15,7 @@
#include <common/debug.h> #include <common/debug.h>
#include <drivers/auth/auth_mod.h> #include <drivers/auth/auth_mod.h>
#include <drivers/console.h> #include <drivers/console.h>
#include <lib/cpus/errata_report.h> #include <lib/cpus/errata.h>
#include <lib/utils.h> #include <lib/utils.h>
#include <smccc_helpers.h> #include <smccc_helpers.h>
#include <tools_share/uuid.h> #include <tools_share/uuid.h>

View file

@ -83,6 +83,7 @@ override BL1_SOURCES := drivers/arm/sp805/sp805.c \
drivers/io/io_storage.c \ drivers/io/io_storage.c \
drivers/io/io_semihosting.c \ drivers/io/io_semihosting.c \
lib/cpus/aarch64/cpu_helpers.S \ lib/cpus/aarch64/cpu_helpers.S \
lib/cpus/errata_report.c \
lib/fconf/fconf_dyn_cfg_getter.c \ lib/fconf/fconf_dyn_cfg_getter.c \
lib/semihosting/semihosting.c \ lib/semihosting/semihosting.c \
lib/semihosting/${ARCH}/semihosting_call.S \ lib/semihosting/${ARCH}/semihosting_call.S \

View file

@ -6,7 +6,7 @@
#include <common/debug.h> #include <common/debug.h>
#include <common/runtime_svc.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_2017_5715.h>
#include <lib/cpus/wa_cve_2018_3639.h> #include <lib/cpus/wa_cve_2018_3639.h>
#include <lib/cpus/wa_cve_2022_23960.h> #include <lib/cpus/wa_cve_2022_23960.h>