mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-24 05:54:08 +00:00
feat(cpus): add a way to automatically report errata
Using the errata framework per-cpu data structure, errata can all be reported automatically through a single standard errata reporter which can replace the cpu-specific ones. This reporter can also enforce the ordering requirement of errata. Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com> Change-Id: I7d2d5ac5bcb9d21aed0d560d7d23919a323ffdab
This commit is contained in:
parent
3f4c1e1e7b
commit
4f748cc44c
3 changed files with 122 additions and 8 deletions
|
@ -552,4 +552,24 @@
|
||||||
ret x15
|
ret x15
|
||||||
endfunc \_cpu\()_reset_func
|
endfunc \_cpu\()_reset_func
|
||||||
.endm
|
.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 */
|
||||||
|
|
|
@ -26,10 +26,29 @@
|
||||||
#define ERRATUM_ENTRY_SIZE ERRATUM_MITIGATED + ERRATUM_MITIGATED_SIZE
|
#define ERRATUM_ENTRY_SIZE ERRATUM_MITIGATED + ERRATUM_MITIGATED_SIZE
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
#include <lib/cassert.h>
|
||||||
|
|
||||||
void print_errata_status(void);
|
void print_errata_status(void);
|
||||||
void errata_print_msg(unsigned int status, const char *cpu, const char *id);
|
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
|
#else
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -31,9 +31,88 @@
|
||||||
/* 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
|
#if !REPORT_ERRATA
|
||||||
void print_errata_status(void) {}
|
void print_errata_status(void) {}
|
||||||
#else /* !REPORT_ERRATA */
|
#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.
|
||||||
|
@ -94,14 +173,10 @@ void print_errata_status(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print errata status message.
|
* Old errata status message printer
|
||||||
*
|
* TODO: remove once all cpus have been converted to the new printing method
|
||||||
* Unknown: WARN
|
|
||||||
* Missing: WARN
|
|
||||||
* Applied: INFO
|
|
||||||
* Not applied: VERBOSE
|
|
||||||
*/
|
*/
|
||||||
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 */
|
/* Errata status strings */
|
||||||
static const char *const errata_status_str[] = {
|
static const char *const errata_status_str[] = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue