xref: /rk3399_ARM-atf/lib/cpus/errata_report.c (revision f43e09a12e4f4f32185d3e2accceb65895d1f16b)
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