1ffea3844SSona Mathew /*
250de8867SArvind Ram Prakash * Copyright (c) 2023-2025, Arm Limited and Contributors. All rights reserved.
3ffea3844SSona Mathew *
4ffea3844SSona Mathew * SPDX-License-Identifier: BSD-3-Clause
5ffea3844SSona Mathew */
6ffea3844SSona Mathew
7ffea3844SSona Mathew #include <assert.h>
8ffea3844SSona Mathew #include "cpu_errata_info.h"
9c9f26343SSona Mathew #include <lib/cpus/cpu_ops.h>
10c9f26343SSona Mathew #include <lib/cpus/errata.h>
11ffea3844SSona Mathew #include <lib/smccc.h>
12ffea3844SSona Mathew #include <lib/utils_def.h>
13ffea3844SSona Mathew #include <services/errata_abi_svc.h>
14ffea3844SSona Mathew #include <smccc_helpers.h>
15ffea3844SSona Mathew
16ffea3844SSona Mathew /*
17ffea3844SSona Mathew * Global pointer that points to the specific
18ffea3844SSona Mathew * structure based on the MIDR part number
19ffea3844SSona Mathew */
20ffea3844SSona Mathew struct em_cpu_list *cpu_ptr;
21ffea3844SSona Mathew
22ffea3844SSona Mathew /* Structure array that holds CPU specific errata information */
23ffea3844SSona Mathew struct em_cpu_list cpu_list[] = {
24ffea3844SSona Mathew #if CORTEX_A78_H_INC
25ffea3844SSona Mathew {
265dd90688SGovindraj Raja .cpu_midr = CORTEX_A78_MIDR,
27ffea3844SSona Mathew .cpu_errata_list = {
28aceb9c9eSSona Mathew [0] = {2712571, 0x00, 0x12},
29c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
30ffea3844SSona Mathew }
31ffea3844SSona Mathew },
32ffea3844SSona Mathew #endif /* CORTEX_A78_H_INC */
33ffea3844SSona Mathew
34ffea3844SSona Mathew #if CORTEX_A78_AE_H_INC
35ffea3844SSona Mathew {
365dd90688SGovindraj Raja .cpu_midr = CORTEX_A78_AE_MIDR,
37ffea3844SSona Mathew .cpu_errata_list = {
38aceb9c9eSSona Mathew [0] = {2712574, 0x00, 0x02},
39c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
40ffea3844SSona Mathew }
41ffea3844SSona Mathew },
42ffea3844SSona Mathew #endif /* CORTEX_A78_AE_H_INC */
43ffea3844SSona Mathew
44ffea3844SSona Mathew #if CORTEX_A78C_H_INC
45ffea3844SSona Mathew {
465dd90688SGovindraj Raja .cpu_midr = CORTEX_A78C_MIDR,
47ffea3844SSona Mathew .cpu_errata_list = {
48aceb9c9eSSona Mathew [0] = {2712575, 0x01, 0x02},
49c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
50ffea3844SSona Mathew }
51ffea3844SSona Mathew },
52ffea3844SSona Mathew #endif /* CORTEX_A78C_H_INC */
53ffea3844SSona Mathew
54ffea3844SSona Mathew #if NEOVERSE_V1_H_INC
55ffea3844SSona Mathew {
565dd90688SGovindraj Raja .cpu_midr = NEOVERSE_V1_MIDR,
57ffea3844SSona Mathew .cpu_errata_list = {
58aceb9c9eSSona Mathew [0] = {2701953, 0x00, 0x11},
59c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
60ffea3844SSona Mathew }
61ffea3844SSona Mathew },
62ffea3844SSona Mathew #endif /* NEOVERSE_V1_H_INC */
63ffea3844SSona Mathew
64ffea3844SSona Mathew #if CORTEX_A710_H_INC
65ffea3844SSona Mathew {
665dd90688SGovindraj Raja .cpu_midr = CORTEX_A710_MIDR,
67ffea3844SSona Mathew .cpu_errata_list = {
68aceb9c9eSSona Mathew [0] = {2701952, 0x00, 0x21},
69c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
70ffea3844SSona Mathew }
71ffea3844SSona Mathew },
72ffea3844SSona Mathew #endif /* CORTEX_A710_H_INC */
73ffea3844SSona Mathew
74ffea3844SSona Mathew #if NEOVERSE_N2_H_INC
75ffea3844SSona Mathew {
765dd90688SGovindraj Raja .cpu_midr = NEOVERSE_N2_MIDR,
77ffea3844SSona Mathew .cpu_errata_list = {
78aceb9c9eSSona Mathew [0] = {2728475, 0x00, 0x02},
79c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
80ffea3844SSona Mathew }
81ffea3844SSona Mathew },
82ffea3844SSona Mathew #endif /* NEOVERSE_N2_H_INC */
83ffea3844SSona Mathew
84ffea3844SSona Mathew #if CORTEX_X2_H_INC
85ffea3844SSona Mathew {
865dd90688SGovindraj Raja .cpu_midr = CORTEX_X2_MIDR,
87ffea3844SSona Mathew .cpu_errata_list = {
88aceb9c9eSSona Mathew [0] = {2701952, 0x00, 0x21},
89c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
90ffea3844SSona Mathew }
91ffea3844SSona Mathew },
92ffea3844SSona Mathew #endif /* CORTEX_X2_H_INC */
93ffea3844SSona Mathew
94ab062f05SSona Mathew #if NEOVERSE_V2_H_INC
95ab062f05SSona Mathew {
965dd90688SGovindraj Raja .cpu_midr = NEOVERSE_V2_MIDR,
97ab062f05SSona Mathew .cpu_errata_list = {
98aceb9c9eSSona Mathew [0] = {2719103, 0x00, 0x01},
99c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
100ab062f05SSona Mathew }
101ab062f05SSona Mathew },
102ab062f05SSona Mathew #endif /* NEOVERSE_V2_H_INC */
103ab062f05SSona Mathew
104106c4283SSona Mathew #if CORTEX_X3_H_INC
105ab062f05SSona Mathew {
1065dd90688SGovindraj Raja .cpu_midr = CORTEX_X3_MIDR,
107ab062f05SSona Mathew .cpu_errata_list = {
108aceb9c9eSSona Mathew [0] = {2701951, 0x00, 0x11},
109c9f26343SSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
110ab062f05SSona Mathew }
111ab062f05SSona Mathew },
112106c4283SSona Mathew #endif /* CORTEX_X3_H_INC */
1139c165216SSona Mathew
114cc41b56fSSona Mathew #if CORTEX_X4_H_INC
115cc41b56fSSona Mathew {
1165dd90688SGovindraj Raja .cpu_midr = CORTEX_X4_MIDR,
117cc41b56fSSona Mathew .cpu_errata_list = {
118cc41b56fSSona Mathew [0] = {2701112, 0x00, 0x00},
119cc41b56fSSona Mathew [1 ... ERRATA_LIST_END] = UNDEF_ERRATA,
120cc41b56fSSona Mathew }
121cc41b56fSSona Mathew },
122cc41b56fSSona Mathew #endif /* CORTEX_X4_H_INC */
123cc41b56fSSona Mathew
124ffea3844SSona Mathew };
125ffea3844SSona Mathew
126aceb9c9eSSona Mathew #if ERRATA_NON_ARM_INTERCONNECT
127aceb9c9eSSona Mathew
128aceb9c9eSSona Mathew /* Check if the errata is enabled for non-arm interconnect */
non_arm_interconnect_errata(uint32_t errata_id,long rev_var)129aceb9c9eSSona Mathew static int32_t non_arm_interconnect_errata(uint32_t errata_id, long rev_var)
130aceb9c9eSSona Mathew {
131aceb9c9eSSona Mathew int32_t ret_val = EM_UNKNOWN_ERRATUM;
132aceb9c9eSSona Mathew
133aceb9c9eSSona Mathew /* Determine the number of cpu listed in the cpu list */
134aceb9c9eSSona Mathew uint8_t size_cpulist = ARRAY_SIZE(cpu_list);
135aceb9c9eSSona Mathew
136aceb9c9eSSona Mathew /* Read the midr reg to extract cpu, revision and variant info */
137aceb9c9eSSona Mathew uint32_t midr_val = read_midr();
138aceb9c9eSSona Mathew
139aceb9c9eSSona Mathew for (uint8_t i = 0U; i < size_cpulist; i++) {
140aceb9c9eSSona Mathew cpu_ptr = &cpu_list[i];
141aceb9c9eSSona Mathew /*
142aceb9c9eSSona Mathew * If the cpu partnumber in the cpu list, matches the midr
143aceb9c9eSSona Mathew * part number, check to see if the errata ID matches
144aceb9c9eSSona Mathew */
1455dd90688SGovindraj Raja if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(cpu_ptr->cpu_midr)) {
146aceb9c9eSSona Mathew
147aceb9c9eSSona Mathew struct em_cpu *ptr = NULL;
148aceb9c9eSSona Mathew
149aceb9c9eSSona Mathew for (int j = 0; j < MAX_PLAT_CPU_ERRATA_ENTRIES; j++) {
150aceb9c9eSSona Mathew ptr = &cpu_ptr->cpu_errata_list[j];
151aceb9c9eSSona Mathew assert(ptr != NULL);
152aceb9c9eSSona Mathew if (errata_id == ptr->em_errata_id) {
153aceb9c9eSSona Mathew if (RXPX_RANGE(rev_var, ptr->em_rxpx_lo, ptr->em_rxpx_hi)) {
154aceb9c9eSSona Mathew ret_val = EM_AFFECTED;
155aceb9c9eSSona Mathew break;
156aceb9c9eSSona Mathew }
157aceb9c9eSSona Mathew ret_val = EM_NOT_AFFECTED;
158aceb9c9eSSona Mathew break;
159aceb9c9eSSona Mathew }
160aceb9c9eSSona Mathew }
161aceb9c9eSSona Mathew break;
162aceb9c9eSSona Mathew }
163aceb9c9eSSona Mathew }
164aceb9c9eSSona Mathew return ret_val;
165aceb9c9eSSona Mathew }
166aceb9c9eSSona Mathew #endif
167aceb9c9eSSona Mathew
168ffea3844SSona Mathew /* Function to check if the errata exists for the specific CPU and rxpx */
verify_errata_implemented(uint32_t errata_id)16950de8867SArvind Ram Prakash int32_t verify_errata_implemented(uint32_t errata_id)
170ffea3844SSona Mathew {
171*5a1b666dSArvind Ram Prakash struct erratum_entry *entry;
172c9f26343SSona Mathew long rev_var;
173ffea3844SSona Mathew
174aceb9c9eSSona Mathew rev_var = cpu_get_rev_var();
175aceb9c9eSSona Mathew
176aceb9c9eSSona Mathew #if ERRATA_NON_ARM_INTERCONNECT
177*5a1b666dSArvind Ram Prakash int32_t ret_val = non_arm_interconnect_errata(errata_id, rev_var);
178aceb9c9eSSona Mathew if (ret_val != EM_UNKNOWN_ERRATUM) {
179aceb9c9eSSona Mathew return ret_val;
180aceb9c9eSSona Mathew }
181aceb9c9eSSona Mathew #endif
182*5a1b666dSArvind Ram Prakash entry = find_erratum_entry(errata_id);
183*5a1b666dSArvind Ram Prakash if (entry == NULL)
184*5a1b666dSArvind Ram Prakash return EM_UNKNOWN_ERRATUM;
185ffea3844SSona Mathew
186c9f26343SSona Mathew if (entry->check_func(rev_var)) {
187bbff267bSArvind Ram Prakash if (entry->chosen & WA_ENABLED_MASK)
188bbff267bSArvind Ram Prakash if (entry->chosen & SPLIT_WA_MASK)
189bbff267bSArvind Ram Prakash return EM_AFFECTED;
190bbff267bSArvind Ram Prakash else
191c9f26343SSona Mathew return EM_HIGHER_EL_MITIGATION;
192c9f26343SSona Mathew else
193c9f26343SSona Mathew return EM_AFFECTED;
194ffea3844SSona Mathew }
195c9f26343SSona Mathew return EM_NOT_AFFECTED;
196c9f26343SSona Mathew }
197ffea3844SSona Mathew
198ffea3844SSona Mathew /* Predicate indicating that a function id is part of EM_ABI */
is_errata_fid(uint32_t smc_fid)199ffea3844SSona Mathew bool is_errata_fid(uint32_t smc_fid)
200ffea3844SSona Mathew {
201ffea3844SSona Mathew return ((smc_fid == ARM_EM_VERSION) ||
202ffea3844SSona Mathew (smc_fid == ARM_EM_FEATURES) ||
203ffea3844SSona Mathew (smc_fid == ARM_EM_CPU_ERRATUM_FEATURES));
204ffea3844SSona Mathew
205ffea3844SSona Mathew }
206ffea3844SSona Mathew
validate_spsr_mode(void)207ffea3844SSona Mathew bool validate_spsr_mode(void)
208ffea3844SSona Mathew {
209ffea3844SSona Mathew /* In AArch64, if the caller is EL1, return true */
210ffea3844SSona Mathew
211ffea3844SSona Mathew #if __aarch64__
212ffea3844SSona Mathew if (GET_EL(read_spsr_el3()) == MODE_EL1) {
213ffea3844SSona Mathew return true;
214ffea3844SSona Mathew }
215ffea3844SSona Mathew return false;
216ffea3844SSona Mathew #else
217ffea3844SSona Mathew
218ffea3844SSona Mathew /* In AArch32, if in system/svc mode, return true */
219ffea3844SSona Mathew uint8_t read_el_state = GET_M32(read_spsr());
220ffea3844SSona Mathew
221ffea3844SSona Mathew if ((read_el_state == (MODE32_svc)) || (read_el_state == MODE32_sys)) {
222ffea3844SSona Mathew return true;
223ffea3844SSona Mathew }
224ffea3844SSona Mathew return false;
225ffea3844SSona Mathew #endif /* __aarch64__ */
226ffea3844SSona Mathew }
227ffea3844SSona Mathew
errata_abi_smc_handler(uint32_t smc_fid,u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)228ffea3844SSona Mathew uintptr_t errata_abi_smc_handler(uint32_t smc_fid, u_register_t x1,
229ffea3844SSona Mathew u_register_t x2, u_register_t x3, u_register_t x4,
230ffea3844SSona Mathew void *cookie, void *handle, u_register_t flags)
231ffea3844SSona Mathew {
232ffea3844SSona Mathew int32_t ret_id = EM_UNKNOWN_ERRATUM;
233ffea3844SSona Mathew
234ffea3844SSona Mathew switch (smc_fid) {
235ffea3844SSona Mathew case ARM_EM_VERSION:
236ffea3844SSona Mathew SMC_RET1(handle, MAKE_SMCCC_VERSION(
237ffea3844SSona Mathew EM_VERSION_MAJOR, EM_VERSION_MINOR
238ffea3844SSona Mathew ));
239ffea3844SSona Mathew break; /* unreachable */
240ffea3844SSona Mathew case ARM_EM_FEATURES:
241ffea3844SSona Mathew if (is_errata_fid((uint32_t)x1)) {
242ffea3844SSona Mathew SMC_RET1(handle, EM_SUCCESS);
243ffea3844SSona Mathew }
244ffea3844SSona Mathew
245ffea3844SSona Mathew SMC_RET1(handle, EM_NOT_SUPPORTED);
246ffea3844SSona Mathew break; /* unreachable */
247ffea3844SSona Mathew case ARM_EM_CPU_ERRATUM_FEATURES:
248ffea3844SSona Mathew
249ffea3844SSona Mathew /*
250ffea3844SSona Mathew * If the forward flag is greater than zero and the calling EL
251ffea3844SSona Mathew * is EL1 in AArch64 or in system mode or svc mode in case of AArch32,
252ffea3844SSona Mathew * return Invalid Parameters.
253ffea3844SSona Mathew */
254ffea3844SSona Mathew if (((uint32_t)x2 != 0) && (validate_spsr_mode())) {
255ffea3844SSona Mathew SMC_RET1(handle, EM_INVALID_PARAMETERS);
256ffea3844SSona Mathew }
25750de8867SArvind Ram Prakash ret_id = verify_errata_implemented((uint32_t)x1);
258ffea3844SSona Mathew SMC_RET1(handle, ret_id);
259ffea3844SSona Mathew break; /* unreachable */
260ffea3844SSona Mathew default:
261ffea3844SSona Mathew {
262ffea3844SSona Mathew WARN("Unimplemented Errata ABI Service Call: 0x%x\n", smc_fid);
263ffea3844SSona Mathew SMC_RET1(handle, EM_UNKNOWN_ERRATUM);
264ffea3844SSona Mathew break; /* unreachable */
265ffea3844SSona Mathew }
266ffea3844SSona Mathew }
267ffea3844SSona Mathew }
268