blob: a37ba819a3fbabddf82b0474c08aaceb6ba009ce [file] [log] [blame]
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +00001/*
Boyan Karatotev29fa56d2023-01-27 09:38:15 +00002 * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +00003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +00005 */
6
7/* Runtime firmware routines to report errata status for the current CPU. */
8
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +00009#include <assert.h>
Antonio Nino Diaz9fe40fd2018-10-25 17:11:02 +010010#include <stdbool.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011
12#include <arch_helpers.h>
13#include <common/debug.h>
Boyan Karatotev06236c92023-01-25 18:50:10 +000014#include <lib/cpus/cpu_ops.h>
Boyan Karatotev5d38cb32023-01-27 09:37:07 +000015#include <lib/cpus/errata.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000016#include <lib/el3_runtime/cpu_data.h>
17#include <lib/spinlock.h>
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +000018
19#ifdef IMAGE_BL1
20# define BL_STRING "BL1"
Julius Werner8e0ef0f2019-07-09 14:02:43 -070021#elif defined(__aarch64__) && defined(IMAGE_BL31)
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +000022# define BL_STRING "BL31"
Yann Gautier9335ff52021-10-06 17:34:12 +020023#elif !defined(__aarch64__) && defined(IMAGE_BL32)
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +000024# define BL_STRING "BL32"
Arvind Ram Prakash11b9b492022-11-22 14:41:00 -060025#elif defined(IMAGE_BL2) && RESET_TO_BL2
Roberto Vargase0e99462017-10-30 14:43:43 +000026# define BL_STRING "BL2"
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +000027#else
28# error This image should not be printing errata status
29#endif
30
31/* Errata format: BL stage, CPU, errata ID, message */
Dimitris Papastamos84e02dc2018-01-16 10:42:20 +000032#define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n"
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +000033
Boyan Karatotev29fa56d2023-01-27 09:38:15 +000034#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#define PRINT_STATUS_DISPATCH(status, ...) \
38 do { \
39 assert(status <= ERRATA_MISSING); \
40 switch (status) { \
41 case ERRATA_NOT_APPLIES: \
42 VERBOSE(__VA_ARGS__, "not applied"); \
43 break; \
44 case ERRATA_APPLIES: \
45 INFO(__VA_ARGS__, "applied"); \
46 break; \
47 case ERRATA_MISSING: \
48 WARN(__VA_ARGS__, "missing!"); \
49 break; \
50 } \
51 } while (0)
52
53
Boyan Karatotev06236c92023-01-25 18:50:10 +000054#if !REPORT_ERRATA
55void print_errata_status(void) {}
56#else /* !REPORT_ERRATA */
Boyan Karatotev29fa56d2023-01-27 09:38:15 +000057/* New errata status message printer */
58void __unused generic_errata_report(void)
59{
60 struct cpu_ops *cpu_ops = get_cpu_ops_ptr();
61 struct erratum_entry *entry = cpu_ops->errata_list_start;
62 struct erratum_entry *end = cpu_ops->errata_list_end;
63 long rev_var = cpu_get_rev_var();
64 uint32_t last_erratum_id = 0;
65 uint16_t last_cve_yr = 0;
66 bool check_cve = false;
67 /* unused because assert goes away on release */
68 bool failed __unused = false;
69
70 for (; entry != end; entry += 1) {
71 uint64_t status = entry->check_func(rev_var);
72
73 assert(entry->id != 0);
74
75 /*
76 * Errata workaround has not been compiled in. If the errata
77 * would have applied had it been compiled in, print its status
78 * as missing.
79 */
80 if (status == ERRATA_APPLIES && entry->chosen == 0) {
81 status = ERRATA_MISSING;
82 }
83
84 if (entry->cve) {
85 PRINT_STATUS_DISPATCH(status, CVE_FORMAT, BL_STRING,
86 cpu_ops->cpu_str, entry->cve, entry->id);
87
88 if (last_cve_yr > entry->cve ||
89 (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
90 ERROR("CVE %u_%u was out of order!\n",
91 entry->cve, entry->id);
92 failed = true;
93 }
94 check_cve = true;
95 last_cve_yr = entry->cve;
96 } else {
97 PRINT_STATUS_DISPATCH(status, ERRATUM_FORMAT, BL_STRING,
98 cpu_ops->cpu_str, entry->id);
99
100 if (last_erratum_id >= entry->id || check_cve) {
101 ERROR("Erratum %u was out of order!\n",
102 entry->id);
103 failed = true;
104 }
105 }
106 last_erratum_id = entry->id;
107 }
108
109 /*
110 * enforce errata and CVEs are in ascending order and that CVEs are
111 * after errata
112 */
113 assert(!failed);
114}
115
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000116/*
117 * Returns whether errata needs to be reported. Passed arguments are private to
118 * a CPU type.
119 */
Boyan Karatotev06236c92023-01-25 18:50:10 +0000120static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000121{
Antonio Nino Diaz9fe40fd2018-10-25 17:11:02 +0100122 bool report_now;
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000123
124 /* If already reported, return false. */
Antonio Nino Diaz9fe40fd2018-10-25 17:11:02 +0100125 if (*reported != 0U)
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000126 return 0;
127
128 /*
129 * Acquire lock. Determine whether status needs reporting, and then mark
130 * report status to true.
131 */
132 spin_lock(lock);
Antonio Nino Diaz9fe40fd2018-10-25 17:11:02 +0100133 report_now = (*reported == 0U);
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000134 if (report_now)
135 *reported = 1;
136 spin_unlock(lock);
137
138 return report_now;
139}
140
141/*
Boyan Karatotev06236c92023-01-25 18:50:10 +0000142 * Function to print errata status for the calling CPU (and others of the same
143 * type). Must be called only:
144 * - when MMU and data caches are enabled;
145 * - after cpu_ops have been initialized in per-CPU data.
146 */
147void print_errata_status(void)
148{
149 struct cpu_ops *cpu_ops;
150#ifdef IMAGE_BL1
151 /*
152 * BL1 doesn't have per-CPU data. So retrieve the CPU operations
153 * directly.
154 */
155 cpu_ops = get_cpu_ops_ptr();
156
157 if (cpu_ops->errata_func != NULL) {
158 cpu_ops->errata_func();
159 }
160#else /* IMAGE_BL1 */
161 cpu_ops = (void *) get_cpu_data(cpu_ops_ptr);
162
163 assert(cpu_ops != NULL);
164
165 if (cpu_ops->errata_func == NULL) {
166 return;
167 }
168
169 if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) {
170 cpu_ops->errata_func();
171 }
172#endif /* IMAGE_BL1 */
173}
174
175/*
Boyan Karatotev29fa56d2023-01-27 09:38:15 +0000176 * Old errata status message printer
177 * TODO: remove once all cpus have been converted to the new printing method
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000178 */
Boyan Karatotev29fa56d2023-01-27 09:38:15 +0000179void __unused errata_print_msg(unsigned int status, const char *cpu, const char *id)
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000180{
181 /* Errata status strings */
182 static const char *const errata_status_str[] = {
183 [ERRATA_NOT_APPLIES] = "not applied",
184 [ERRATA_APPLIES] = "applied",
185 [ERRATA_MISSING] = "missing!"
186 };
187 static const char *const __unused bl_str = BL_STRING;
188 const char *msg __unused;
189
190
David Cunado8a354f12017-06-21 16:52:45 +0100191 assert(status < ARRAY_SIZE(errata_status_str));
Antonio Nino Diaz9fe40fd2018-10-25 17:11:02 +0100192 assert(cpu != NULL);
193 assert(id != NULL);
Jeenu Viswambharand5ec3672017-01-03 11:01:51 +0000194
195 msg = errata_status_str[status];
196
197 switch (status) {
198 case ERRATA_NOT_APPLIES:
199 VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg);
200 break;
201
202 case ERRATA_APPLIES:
203 INFO(ERRATA_FORMAT, bl_str, cpu, id, msg);
204 break;
205
206 case ERRATA_MISSING:
207 WARN(ERRATA_FORMAT, bl_str, cpu, id, msg);
208 break;
209
210 default:
211 WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown");
212 break;
213 }
214}
Boyan Karatotev06236c92023-01-25 18:50:10 +0000215#endif /* !REPORT_ERRATA */