110bcd761SJeenu Viswambharan /*
2106ca0cbSGovindraj Raja * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
310bcd761SJeenu Viswambharan *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
510bcd761SJeenu Viswambharan */
610bcd761SJeenu Viswambharan
710bcd761SJeenu Viswambharan /* Runtime firmware routines to report errata status for the current CPU. */
810bcd761SJeenu Viswambharan
910bcd761SJeenu Viswambharan #include <assert.h>
1043534997SAntonio Nino Diaz #include <stdbool.h>
1109d40e0eSAntonio Nino Diaz
1209d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
14dd9fae1cSBoyan Karatotev #include <lib/cpus/cpu_ops.h>
156bb96fa6SBoyan Karatotev #include <lib/cpus/errata.h>
1609d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/cpu_data.h>
1709d40e0eSAntonio Nino Diaz #include <lib/spinlock.h>
1810bcd761SJeenu Viswambharan
1910bcd761SJeenu Viswambharan #ifdef IMAGE_BL1
2010bcd761SJeenu Viswambharan # define BL_STRING "BL1"
21402b3cf8SJulius Werner #elif defined(__aarch64__) && defined(IMAGE_BL31)
2210bcd761SJeenu Viswambharan # define BL_STRING "BL31"
23322e60a6SYann Gautier #elif !defined(__aarch64__) && defined(IMAGE_BL32)
2410bcd761SJeenu Viswambharan # define BL_STRING "BL32"
2542d4d3baSArvind Ram Prakash #elif defined(IMAGE_BL2) && RESET_TO_BL2
26b1d27b48SRoberto Vargas # define BL_STRING "BL2"
2710bcd761SJeenu Viswambharan #else
2810bcd761SJeenu Viswambharan # error This image should not be printing errata status
2910bcd761SJeenu Viswambharan #endif
3010bcd761SJeenu Viswambharan
3110bcd761SJeenu Viswambharan /* Errata format: BL stage, CPU, errata ID, message */
32c0ca14d6SDimitris Papastamos #define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n"
3310bcd761SJeenu Viswambharan
34*d1ed0c3dSJohn Powell #define CVE_FORMAT "%s: %s: CPU workaround for CVE %u_%04u was %s\n"
354f748cc4SBoyan Karatotev #define ERRATUM_FORMAT "%s: %s: CPU workaround for erratum %u was %s\n"
364f748cc4SBoyan Karatotev
374f748cc4SBoyan Karatotev
print_status(int status,char * cpu_str,uint16_t cve,uint32_t id)38f43e09a1SBoyan Karatotev static __unused void print_status(int status, char *cpu_str, uint16_t cve, uint32_t id)
39f43e09a1SBoyan Karatotev {
40f43e09a1SBoyan Karatotev if (status == ERRATA_MISSING) {
41f43e09a1SBoyan Karatotev if (cve) {
42f43e09a1SBoyan Karatotev WARN(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "missing!");
43f43e09a1SBoyan Karatotev } else {
44f43e09a1SBoyan Karatotev WARN(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "missing!");
45f43e09a1SBoyan Karatotev }
46f43e09a1SBoyan Karatotev } else if (status == ERRATA_APPLIES) {
47f43e09a1SBoyan Karatotev if (cve) {
48f43e09a1SBoyan Karatotev INFO(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "applied");
49f43e09a1SBoyan Karatotev } else {
50f43e09a1SBoyan Karatotev INFO(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "applied");
51f43e09a1SBoyan Karatotev }
52f43e09a1SBoyan Karatotev } else {
53f43e09a1SBoyan Karatotev if (cve) {
54becc97efSSona Mathew VERBOSE(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "not applicable");
55f43e09a1SBoyan Karatotev } else {
56becc97efSSona Mathew VERBOSE(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "not applicable");
57f43e09a1SBoyan Karatotev }
58f43e09a1SBoyan Karatotev }
59f43e09a1SBoyan Karatotev }
604f748cc4SBoyan Karatotev
61dd9fae1cSBoyan Karatotev #if !REPORT_ERRATA
print_errata_status(void)62dd9fae1cSBoyan Karatotev void print_errata_status(void) {}
63dd9fae1cSBoyan Karatotev #else /* !REPORT_ERRATA */
64f43e09a1SBoyan Karatotev /*
65f43e09a1SBoyan Karatotev * New errata status message printer
66f43e09a1SBoyan Karatotev */
generic_errata_report(void)671c20f05cSRyan Everett void generic_errata_report(void)
684f748cc4SBoyan Karatotev {
694f748cc4SBoyan Karatotev struct cpu_ops *cpu_ops = get_cpu_ops_ptr();
704f748cc4SBoyan Karatotev struct erratum_entry *entry = cpu_ops->errata_list_start;
714f748cc4SBoyan Karatotev struct erratum_entry *end = cpu_ops->errata_list_end;
724f748cc4SBoyan Karatotev long rev_var = cpu_get_rev_var();
734f748cc4SBoyan Karatotev
744f748cc4SBoyan Karatotev for (; entry != end; entry += 1) {
754f748cc4SBoyan Karatotev uint64_t status = entry->check_func(rev_var);
764f748cc4SBoyan Karatotev
774f748cc4SBoyan Karatotev assert(entry->id != 0);
784f748cc4SBoyan Karatotev
794f748cc4SBoyan Karatotev /*
804f748cc4SBoyan Karatotev * Errata workaround has not been compiled in. If the errata
814f748cc4SBoyan Karatotev * would have applied had it been compiled in, print its status
824f748cc4SBoyan Karatotev * as missing.
834f748cc4SBoyan Karatotev */
844f748cc4SBoyan Karatotev if (status == ERRATA_APPLIES && entry->chosen == 0) {
854f748cc4SBoyan Karatotev status = ERRATA_MISSING;
864f748cc4SBoyan Karatotev }
874f748cc4SBoyan Karatotev
88f43e09a1SBoyan Karatotev print_status(status, cpu_ops->cpu_str, entry->cve, entry->id);
894f748cc4SBoyan Karatotev }
904f748cc4SBoyan Karatotev }
914f748cc4SBoyan Karatotev
9210bcd761SJeenu Viswambharan /*
9310bcd761SJeenu Viswambharan * Returns whether errata needs to be reported. Passed arguments are private to
9410bcd761SJeenu Viswambharan * a CPU type.
9510bcd761SJeenu Viswambharan */
errata_needs_reporting(spinlock_t * lock,uint32_t * reported)96dd9fae1cSBoyan Karatotev static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
9710bcd761SJeenu Viswambharan {
9843534997SAntonio Nino Diaz bool report_now;
9910bcd761SJeenu Viswambharan
10010bcd761SJeenu Viswambharan /* If already reported, return false. */
10143534997SAntonio Nino Diaz if (*reported != 0U)
10210bcd761SJeenu Viswambharan return 0;
10310bcd761SJeenu Viswambharan
10410bcd761SJeenu Viswambharan /*
10510bcd761SJeenu Viswambharan * Acquire lock. Determine whether status needs reporting, and then mark
10610bcd761SJeenu Viswambharan * report status to true.
10710bcd761SJeenu Viswambharan */
10810bcd761SJeenu Viswambharan spin_lock(lock);
10943534997SAntonio Nino Diaz report_now = (*reported == 0U);
11010bcd761SJeenu Viswambharan if (report_now)
11110bcd761SJeenu Viswambharan *reported = 1;
11210bcd761SJeenu Viswambharan spin_unlock(lock);
11310bcd761SJeenu Viswambharan
11410bcd761SJeenu Viswambharan return report_now;
11510bcd761SJeenu Viswambharan }
11610bcd761SJeenu Viswambharan
11710bcd761SJeenu Viswambharan /*
118dd9fae1cSBoyan Karatotev * Function to print errata status for the calling CPU (and others of the same
119dd9fae1cSBoyan Karatotev * type). Must be called only:
120dd9fae1cSBoyan Karatotev * - when MMU and data caches are enabled;
121dd9fae1cSBoyan Karatotev * - after cpu_ops have been initialized in per-CPU data.
122dd9fae1cSBoyan Karatotev */
print_errata_status(void)123dd9fae1cSBoyan Karatotev void print_errata_status(void)
124dd9fae1cSBoyan Karatotev {
125dd9fae1cSBoyan Karatotev #ifdef IMAGE_BL1
1261c20f05cSRyan Everett generic_errata_report();
127dd9fae1cSBoyan Karatotev #else /* IMAGE_BL1 */
1281c20f05cSRyan Everett struct cpu_ops *cpu_ops = (void *) get_cpu_data(cpu_ops_ptr);
129dd9fae1cSBoyan Karatotev
130dd9fae1cSBoyan Karatotev assert(cpu_ops != NULL);
131dd9fae1cSBoyan Karatotev
132dd9fae1cSBoyan Karatotev if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) {
1331c20f05cSRyan Everett generic_errata_report();
134dd9fae1cSBoyan Karatotev }
135dd9fae1cSBoyan Karatotev #endif /* IMAGE_BL1 */
136dd9fae1cSBoyan Karatotev }
137dd9fae1cSBoyan Karatotev #endif /* !REPORT_ERRATA */
138