xref: /rk3399_ARM-atf/lib/cpus/errata_report.c (revision 2d3b44e3073e8d6ec49dde45ec353d6f41290917)
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 #endif /* FEATURE_DETECTION */
81 
82 	for (; entry != end; entry += 1) {
83 		uint64_t status = entry->check_func(rev_var);
84 
85 		assert(entry->id != 0);
86 
87 		/*
88 		 * Errata workaround has not been compiled in. If the errata
89 		 * would have applied had it been compiled in, print its status
90 		 * as missing.
91 		 */
92 		if (status == ERRATA_APPLIES && entry->chosen == 0) {
93 			status = ERRATA_MISSING;
94 		}
95 
96 		print_status(status, cpu_ops->cpu_str, entry->cve, entry->id);
97 
98 #if FEATURE_DETECTION
99 		if (entry->cve) {
100 			if (last_cve_yr > entry->cve ||
101 			   (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
102 				WARN("CVE %u_%u was out of order!\n",
103 				      entry->cve, entry->id);
104 			}
105 			check_cve = true;
106 			last_cve_yr = entry->cve;
107 		} else {
108 			if (last_erratum_id >= entry->id || check_cve) {
109 				WARN("Erratum %u was out of order!\n",
110 				      entry->id);
111 			}
112 		}
113 		last_erratum_id = entry->id;
114 #endif /* FEATURE_DETECTION */
115 	}
116 }
117 
118 /*
119  * Returns whether errata needs to be reported. Passed arguments are private to
120  * a CPU type.
121  */
122 static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
123 {
124 	bool report_now;
125 
126 	/* If already reported, return false. */
127 	if (*reported != 0U)
128 		return 0;
129 
130 	/*
131 	 * Acquire lock. Determine whether status needs reporting, and then mark
132 	 * report status to true.
133 	 */
134 	spin_lock(lock);
135 	report_now = (*reported == 0U);
136 	if (report_now)
137 		*reported = 1;
138 	spin_unlock(lock);
139 
140 	return report_now;
141 }
142 
143 /*
144  * Function to print errata status for the calling CPU (and others of the same
145  * type). Must be called only:
146  *   - when MMU and data caches are enabled;
147  *   - after cpu_ops have been initialized in per-CPU data.
148  */
149 void print_errata_status(void)
150 {
151 #ifdef IMAGE_BL1
152 	generic_errata_report();
153 #else /* IMAGE_BL1 */
154 	struct cpu_ops *cpu_ops = (void *) get_cpu_data(cpu_ops_ptr);
155 
156 	assert(cpu_ops != NULL);
157 
158 	if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) {
159 		generic_errata_report();
160 	}
161 #endif /* IMAGE_BL1 */
162 }
163 #endif /* !REPORT_ERRATA */
164