xref: /rk3399_ARM-atf/lib/cpus/errata_report.c (revision 9b5c0fcdbac088eaf564e1ceca7ef686668bc25b)
1 /*
2  * Copyright (c) 2017-2023, 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 #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 
54 #if !REPORT_ERRATA
55 void print_errata_status(void) {}
56 #else /* !REPORT_ERRATA */
57 /* New errata status message printer */
58 void __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 
116 /*
117  * Returns whether errata needs to be reported. Passed arguments are private to
118  * a CPU type.
119  */
120 static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
121 {
122 	bool report_now;
123 
124 	/* If already reported, return false. */
125 	if (*reported != 0U)
126 		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);
133 	report_now = (*reported == 0U);
134 	if (report_now)
135 		*reported = 1;
136 	spin_unlock(lock);
137 
138 	return report_now;
139 }
140 
141 /*
142  * 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  */
147 void 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 /*
176  * Old errata status message printer
177  * TODO: remove once all cpus have been converted to the new printing method
178  */
179 void __unused errata_print_msg(unsigned int status, const char *cpu, const char *id)
180 {
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 
191 	assert(status < ARRAY_SIZE(errata_status_str));
192 	assert(cpu != NULL);
193 	assert(id != NULL);
194 
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 }
215 #endif /* !REPORT_ERRATA */
216