1 /* 2 * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* Runtime firmware routines to report errata status for the current CPU. */ 8 9 #include <assert.h> 10 #include <stdbool.h> 11 12 #include <arch_helpers.h> 13 #include <common/debug.h> 14 #include <lib/cpus/cpu_ops.h> 15 #include <lib/cpus/errata.h> 16 #include <lib/el3_runtime/cpu_data.h> 17 #include <lib/spinlock.h> 18 19 #ifdef IMAGE_BL1 20 # define BL_STRING "BL1" 21 #elif defined(__aarch64__) && defined(IMAGE_BL31) 22 # define BL_STRING "BL31" 23 #elif !defined(__aarch64__) && defined(IMAGE_BL32) 24 # define BL_STRING "BL32" 25 #elif defined(IMAGE_BL2) && RESET_TO_BL2 26 # define BL_STRING "BL2" 27 #else 28 # error This image should not be printing errata status 29 #endif 30 31 /* Errata format: BL stage, CPU, errata ID, message */ 32 #define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n" 33 34 #define CVE_FORMAT "%s: %s: CPU workaround for CVE %u_%u was %s\n" 35 #define ERRATUM_FORMAT "%s: %s: CPU workaround for erratum %u was %s\n" 36 37 38 static __unused void print_status(int status, char *cpu_str, uint16_t cve, uint32_t id) 39 { 40 if (status == ERRATA_MISSING) { 41 if (cve) { 42 WARN(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "missing!"); 43 } else { 44 WARN(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "missing!"); 45 } 46 } else if (status == ERRATA_APPLIES) { 47 if (cve) { 48 INFO(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "applied"); 49 } else { 50 INFO(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "applied"); 51 } 52 } else { 53 if (cve) { 54 VERBOSE(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "not applicable"); 55 } else { 56 VERBOSE(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "not applicable"); 57 } 58 } 59 } 60 61 #if !REPORT_ERRATA 62 void print_errata_status(void) {} 63 #else /* !REPORT_ERRATA */ 64 /* 65 * New errata status message printer 66 * The order checking function is hidden behind the FEATURE_DETECTION flag to 67 * save space. This functionality is only useful on development and platform 68 * bringup builds, when FEATURE_DETECTION should be used anyway 69 */ 70 void generic_errata_report(void) 71 { 72 struct cpu_ops *cpu_ops = get_cpu_ops_ptr(); 73 struct erratum_entry *entry = cpu_ops->errata_list_start; 74 struct erratum_entry *end = cpu_ops->errata_list_end; 75 long rev_var = cpu_get_rev_var(); 76 #if FEATURE_DETECTION 77 uint32_t last_erratum_id = 0; 78 uint16_t last_cve_yr = 0; 79 bool check_cve = false; 80 bool failed = false; 81 #endif /* FEATURE_DETECTION */ 82 83 for (; entry != end; entry += 1) { 84 uint64_t status = entry->check_func(rev_var); 85 86 assert(entry->id != 0); 87 88 /* 89 * Errata workaround has not been compiled in. If the errata 90 * would have applied had it been compiled in, print its status 91 * as missing. 92 */ 93 if (status == ERRATA_APPLIES && entry->chosen == 0) { 94 status = ERRATA_MISSING; 95 } 96 97 print_status(status, cpu_ops->cpu_str, entry->cve, entry->id); 98 99 #if FEATURE_DETECTION 100 if (entry->cve) { 101 if (last_cve_yr > entry->cve || 102 (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) { 103 ERROR("CVE %u_%u was out of order!\n", 104 entry->cve, entry->id); 105 failed = true; 106 } 107 check_cve = true; 108 last_cve_yr = entry->cve; 109 } else { 110 if (last_erratum_id >= entry->id || check_cve) { 111 ERROR("Erratum %u was out of order!\n", 112 entry->id); 113 failed = true; 114 } 115 } 116 last_erratum_id = entry->id; 117 #endif /* FEATURE_DETECTION */ 118 } 119 120 #if FEATURE_DETECTION 121 /* 122 * enforce errata and CVEs are in ascending order and that CVEs are 123 * after errata 124 */ 125 assert(!failed); 126 #endif /* FEATURE_DETECTION */ 127 } 128 129 /* 130 * Returns whether errata needs to be reported. Passed arguments are private to 131 * a CPU type. 132 */ 133 static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported) 134 { 135 bool report_now; 136 137 /* If already reported, return false. */ 138 if (*reported != 0U) 139 return 0; 140 141 /* 142 * Acquire lock. Determine whether status needs reporting, and then mark 143 * report status to true. 144 */ 145 spin_lock(lock); 146 report_now = (*reported == 0U); 147 if (report_now) 148 *reported = 1; 149 spin_unlock(lock); 150 151 return report_now; 152 } 153 154 /* 155 * Function to print errata status for the calling CPU (and others of the same 156 * type). Must be called only: 157 * - when MMU and data caches are enabled; 158 * - after cpu_ops have been initialized in per-CPU data. 159 */ 160 void print_errata_status(void) 161 { 162 #ifdef IMAGE_BL1 163 generic_errata_report(); 164 #else /* IMAGE_BL1 */ 165 struct cpu_ops *cpu_ops = (void *) get_cpu_data(cpu_ops_ptr); 166 167 assert(cpu_ops != NULL); 168 169 if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) { 170 generic_errata_report(); 171 } 172 #endif /* IMAGE_BL1 */ 173 } 174 #endif /* !REPORT_ERRATA */ 175