mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-24 13:55:56 +00:00
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:
commit
0cfa06b22b
19 changed files with 826 additions and 346 deletions
9
Makefile
9
Makefile
|
@ -710,16 +710,23 @@ endif
|
|||
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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -41,8 +41,7 @@ else
|
|||
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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
152
include/lib/cpus/cpu_ops.h
Normal file
152
include/lib/cpus/cpu_ops.h
Normal 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
78
include/lib/cpus/errata.h
Normal 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 */
|
|
@ -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 */
|
|
@ -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 @@ func cpu_rev_var_hs
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ func cpu_rev_var_range
|
|||
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);
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
|
|||
}
|
||||
|
||||
/*
|
||||
* 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 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 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif /* !REPORT_ERRATA */
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -83,6 +83,7 @@ override BL1_SOURCES := drivers/arm/sp805/sp805.c \
|
|||
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 \
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue