110bcd761SJeenu Viswambharan /* 24f748cc4SBoyan Karatotev * Copyright (c) 2017-2023, 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 344f748cc4SBoyan Karatotev #define CVE_FORMAT "%s: %s: CPU workaround for CVE %u_%u was %s\n" 354f748cc4SBoyan Karatotev #define ERRATUM_FORMAT "%s: %s: CPU workaround for erratum %u was %s\n" 364f748cc4SBoyan Karatotev 374f748cc4SBoyan Karatotev 38*f43e09a1SBoyan Karatotev static __unused void print_status(int status, char *cpu_str, uint16_t cve, uint32_t id) 39*f43e09a1SBoyan Karatotev { 40*f43e09a1SBoyan Karatotev if (status == ERRATA_MISSING) { 41*f43e09a1SBoyan Karatotev if (cve) { 42*f43e09a1SBoyan Karatotev WARN(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "missing!"); 43*f43e09a1SBoyan Karatotev } else { 44*f43e09a1SBoyan Karatotev WARN(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "missing!"); 45*f43e09a1SBoyan Karatotev } 46*f43e09a1SBoyan Karatotev } else if (status == ERRATA_APPLIES) { 47*f43e09a1SBoyan Karatotev if (cve) { 48*f43e09a1SBoyan Karatotev INFO(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "applied"); 49*f43e09a1SBoyan Karatotev } else { 50*f43e09a1SBoyan Karatotev INFO(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "applied"); 51*f43e09a1SBoyan Karatotev } 52*f43e09a1SBoyan Karatotev } else { 53*f43e09a1SBoyan Karatotev if (cve) { 54*f43e09a1SBoyan Karatotev VERBOSE(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "not applied"); 55*f43e09a1SBoyan Karatotev } else { 56*f43e09a1SBoyan Karatotev VERBOSE(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "not applied"); 57*f43e09a1SBoyan Karatotev } 58*f43e09a1SBoyan Karatotev } 59*f43e09a1SBoyan Karatotev } 604f748cc4SBoyan Karatotev 61dd9fae1cSBoyan Karatotev #if !REPORT_ERRATA 62dd9fae1cSBoyan Karatotev void print_errata_status(void) {} 63dd9fae1cSBoyan Karatotev #else /* !REPORT_ERRATA */ 64*f43e09a1SBoyan Karatotev /* 65*f43e09a1SBoyan Karatotev * New errata status message printer 66*f43e09a1SBoyan Karatotev * The order checking function is hidden behind the FEATURE_DETECTION flag to 67*f43e09a1SBoyan Karatotev * save space. This functionality is only useful on development and platform 68*f43e09a1SBoyan Karatotev * bringup builds, when FEATURE_DETECTION should be used anyway 69*f43e09a1SBoyan Karatotev */ 704f748cc4SBoyan Karatotev void __unused generic_errata_report(void) 714f748cc4SBoyan Karatotev { 724f748cc4SBoyan Karatotev struct cpu_ops *cpu_ops = get_cpu_ops_ptr(); 734f748cc4SBoyan Karatotev struct erratum_entry *entry = cpu_ops->errata_list_start; 744f748cc4SBoyan Karatotev struct erratum_entry *end = cpu_ops->errata_list_end; 754f748cc4SBoyan Karatotev long rev_var = cpu_get_rev_var(); 76*f43e09a1SBoyan Karatotev #if FEATURE_DETECTION 774f748cc4SBoyan Karatotev uint32_t last_erratum_id = 0; 784f748cc4SBoyan Karatotev uint16_t last_cve_yr = 0; 794f748cc4SBoyan Karatotev bool check_cve = false; 80*f43e09a1SBoyan Karatotev bool failed = false; 81*f43e09a1SBoyan Karatotev #endif /* FEATURE_DETECTION */ 824f748cc4SBoyan Karatotev 834f748cc4SBoyan Karatotev for (; entry != end; entry += 1) { 844f748cc4SBoyan Karatotev uint64_t status = entry->check_func(rev_var); 854f748cc4SBoyan Karatotev 864f748cc4SBoyan Karatotev assert(entry->id != 0); 874f748cc4SBoyan Karatotev 884f748cc4SBoyan Karatotev /* 894f748cc4SBoyan Karatotev * Errata workaround has not been compiled in. If the errata 904f748cc4SBoyan Karatotev * would have applied had it been compiled in, print its status 914f748cc4SBoyan Karatotev * as missing. 924f748cc4SBoyan Karatotev */ 934f748cc4SBoyan Karatotev if (status == ERRATA_APPLIES && entry->chosen == 0) { 944f748cc4SBoyan Karatotev status = ERRATA_MISSING; 954f748cc4SBoyan Karatotev } 964f748cc4SBoyan Karatotev 97*f43e09a1SBoyan Karatotev print_status(status, cpu_ops->cpu_str, entry->cve, entry->id); 984f748cc4SBoyan Karatotev 99*f43e09a1SBoyan Karatotev #if FEATURE_DETECTION 100*f43e09a1SBoyan Karatotev if (entry->cve) { 1014f748cc4SBoyan Karatotev if (last_cve_yr > entry->cve || 1024f748cc4SBoyan Karatotev (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) { 1034f748cc4SBoyan Karatotev ERROR("CVE %u_%u was out of order!\n", 1044f748cc4SBoyan Karatotev entry->cve, entry->id); 1054f748cc4SBoyan Karatotev failed = true; 1064f748cc4SBoyan Karatotev } 1074f748cc4SBoyan Karatotev check_cve = true; 1084f748cc4SBoyan Karatotev last_cve_yr = entry->cve; 1094f748cc4SBoyan Karatotev } else { 1104f748cc4SBoyan Karatotev if (last_erratum_id >= entry->id || check_cve) { 1114f748cc4SBoyan Karatotev ERROR("Erratum %u was out of order!\n", 1124f748cc4SBoyan Karatotev entry->id); 1134f748cc4SBoyan Karatotev failed = true; 1144f748cc4SBoyan Karatotev } 1154f748cc4SBoyan Karatotev } 1164f748cc4SBoyan Karatotev last_erratum_id = entry->id; 117*f43e09a1SBoyan Karatotev #endif /* FEATURE_DETECTION */ 1184f748cc4SBoyan Karatotev } 1194f748cc4SBoyan Karatotev 120*f43e09a1SBoyan Karatotev #if FEATURE_DETECTION 1214f748cc4SBoyan Karatotev /* 1224f748cc4SBoyan Karatotev * enforce errata and CVEs are in ascending order and that CVEs are 1234f748cc4SBoyan Karatotev * after errata 1244f748cc4SBoyan Karatotev */ 1254f748cc4SBoyan Karatotev assert(!failed); 126*f43e09a1SBoyan Karatotev #endif /* FEATURE_DETECTION */ 1274f748cc4SBoyan Karatotev } 1284f748cc4SBoyan Karatotev 12910bcd761SJeenu Viswambharan /* 13010bcd761SJeenu Viswambharan * Returns whether errata needs to be reported. Passed arguments are private to 13110bcd761SJeenu Viswambharan * a CPU type. 13210bcd761SJeenu Viswambharan */ 133dd9fae1cSBoyan Karatotev static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported) 13410bcd761SJeenu Viswambharan { 13543534997SAntonio Nino Diaz bool report_now; 13610bcd761SJeenu Viswambharan 13710bcd761SJeenu Viswambharan /* If already reported, return false. */ 13843534997SAntonio Nino Diaz if (*reported != 0U) 13910bcd761SJeenu Viswambharan return 0; 14010bcd761SJeenu Viswambharan 14110bcd761SJeenu Viswambharan /* 14210bcd761SJeenu Viswambharan * Acquire lock. Determine whether status needs reporting, and then mark 14310bcd761SJeenu Viswambharan * report status to true. 14410bcd761SJeenu Viswambharan */ 14510bcd761SJeenu Viswambharan spin_lock(lock); 14643534997SAntonio Nino Diaz report_now = (*reported == 0U); 14710bcd761SJeenu Viswambharan if (report_now) 14810bcd761SJeenu Viswambharan *reported = 1; 14910bcd761SJeenu Viswambharan spin_unlock(lock); 15010bcd761SJeenu Viswambharan 15110bcd761SJeenu Viswambharan return report_now; 15210bcd761SJeenu Viswambharan } 15310bcd761SJeenu Viswambharan 15410bcd761SJeenu Viswambharan /* 155dd9fae1cSBoyan Karatotev * Function to print errata status for the calling CPU (and others of the same 156dd9fae1cSBoyan Karatotev * type). Must be called only: 157dd9fae1cSBoyan Karatotev * - when MMU and data caches are enabled; 158dd9fae1cSBoyan Karatotev * - after cpu_ops have been initialized in per-CPU data. 159dd9fae1cSBoyan Karatotev */ 160dd9fae1cSBoyan Karatotev void print_errata_status(void) 161dd9fae1cSBoyan Karatotev { 162dd9fae1cSBoyan Karatotev struct cpu_ops *cpu_ops; 163dd9fae1cSBoyan Karatotev #ifdef IMAGE_BL1 164dd9fae1cSBoyan Karatotev /* 165dd9fae1cSBoyan Karatotev * BL1 doesn't have per-CPU data. So retrieve the CPU operations 166dd9fae1cSBoyan Karatotev * directly. 167dd9fae1cSBoyan Karatotev */ 168dd9fae1cSBoyan Karatotev cpu_ops = get_cpu_ops_ptr(); 169dd9fae1cSBoyan Karatotev 170dd9fae1cSBoyan Karatotev if (cpu_ops->errata_func != NULL) { 171dd9fae1cSBoyan Karatotev cpu_ops->errata_func(); 172dd9fae1cSBoyan Karatotev } 173dd9fae1cSBoyan Karatotev #else /* IMAGE_BL1 */ 174dd9fae1cSBoyan Karatotev cpu_ops = (void *) get_cpu_data(cpu_ops_ptr); 175dd9fae1cSBoyan Karatotev 176dd9fae1cSBoyan Karatotev assert(cpu_ops != NULL); 177dd9fae1cSBoyan Karatotev 178dd9fae1cSBoyan Karatotev if (cpu_ops->errata_func == NULL) { 179dd9fae1cSBoyan Karatotev return; 180dd9fae1cSBoyan Karatotev } 181dd9fae1cSBoyan Karatotev 182dd9fae1cSBoyan Karatotev if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) { 183dd9fae1cSBoyan Karatotev cpu_ops->errata_func(); 184dd9fae1cSBoyan Karatotev } 185dd9fae1cSBoyan Karatotev #endif /* IMAGE_BL1 */ 186dd9fae1cSBoyan Karatotev } 187dd9fae1cSBoyan Karatotev 188dd9fae1cSBoyan Karatotev /* 1894f748cc4SBoyan Karatotev * Old errata status message printer 1904f748cc4SBoyan Karatotev * TODO: remove once all cpus have been converted to the new printing method 19110bcd761SJeenu Viswambharan */ 1924f748cc4SBoyan Karatotev void __unused errata_print_msg(unsigned int status, const char *cpu, const char *id) 19310bcd761SJeenu Viswambharan { 19410bcd761SJeenu Viswambharan /* Errata status strings */ 19510bcd761SJeenu Viswambharan static const char *const errata_status_str[] = { 19610bcd761SJeenu Viswambharan [ERRATA_NOT_APPLIES] = "not applied", 19710bcd761SJeenu Viswambharan [ERRATA_APPLIES] = "applied", 19810bcd761SJeenu Viswambharan [ERRATA_MISSING] = "missing!" 19910bcd761SJeenu Viswambharan }; 20010bcd761SJeenu Viswambharan static const char *const __unused bl_str = BL_STRING; 20110bcd761SJeenu Viswambharan const char *msg __unused; 20210bcd761SJeenu Viswambharan 20310bcd761SJeenu Viswambharan 2040dd41951SDavid Cunado assert(status < ARRAY_SIZE(errata_status_str)); 20543534997SAntonio Nino Diaz assert(cpu != NULL); 20643534997SAntonio Nino Diaz assert(id != NULL); 20710bcd761SJeenu Viswambharan 20810bcd761SJeenu Viswambharan msg = errata_status_str[status]; 20910bcd761SJeenu Viswambharan 21010bcd761SJeenu Viswambharan switch (status) { 21110bcd761SJeenu Viswambharan case ERRATA_NOT_APPLIES: 21210bcd761SJeenu Viswambharan VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg); 21310bcd761SJeenu Viswambharan break; 21410bcd761SJeenu Viswambharan 21510bcd761SJeenu Viswambharan case ERRATA_APPLIES: 21610bcd761SJeenu Viswambharan INFO(ERRATA_FORMAT, bl_str, cpu, id, msg); 21710bcd761SJeenu Viswambharan break; 21810bcd761SJeenu Viswambharan 21910bcd761SJeenu Viswambharan case ERRATA_MISSING: 22010bcd761SJeenu Viswambharan WARN(ERRATA_FORMAT, bl_str, cpu, id, msg); 22110bcd761SJeenu Viswambharan break; 22210bcd761SJeenu Viswambharan 22310bcd761SJeenu Viswambharan default: 22410bcd761SJeenu Viswambharan WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown"); 22510bcd761SJeenu Viswambharan break; 22610bcd761SJeenu Viswambharan } 22710bcd761SJeenu Viswambharan } 228dd9fae1cSBoyan Karatotev #endif /* !REPORT_ERRATA */ 229