1 /* 2 * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include "cpu_errata_info.h" 9 #include <lib/cpus/cpu_ops.h> 10 #include <lib/cpus/errata.h> 11 #include <lib/smccc.h> 12 #include <lib/utils_def.h> 13 #include <services/errata_abi_svc.h> 14 #include <smccc_helpers.h> 15 16 17 /* 18 * Global pointer that points to the specific 19 * structure based on the MIDR part number 20 */ 21 struct em_cpu_list *cpu_ptr; 22 23 /* Structure array that holds CPU specific errata information */ 24 struct em_cpu_list cpu_list[] = { 25 #if CORTEX_A78_H_INC 26 { 27 .cpu_partnumber = CORTEX_A78_MIDR, 28 .cpu_errata_list = { 29 [0] = {2712571, 0x00, 0x12, ERRATA_A78_2712571, ERRATA_NON_ARM_INTERCONNECT}, 30 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 31 } 32 }, 33 #endif /* CORTEX_A78_H_INC */ 34 35 #if CORTEX_A78_AE_H_INC 36 { 37 .cpu_partnumber = CORTEX_A78_AE_MIDR, 38 .cpu_errata_list = { 39 [0] = {2712574, 0x00, 0x02, ERRATA_A78_AE_2712574, ERRATA_NON_ARM_INTERCONNECT}, 40 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 41 } 42 }, 43 #endif /* CORTEX_A78_AE_H_INC */ 44 45 #if CORTEX_A78C_H_INC 46 { 47 .cpu_partnumber = CORTEX_A78C_MIDR, 48 .cpu_errata_list = { 49 [0] = {2712575, 0x01, 0x02, ERRATA_A78C_2712575, ERRATA_NON_ARM_INTERCONNECT}, 50 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 51 } 52 }, 53 #endif /* CORTEX_A78C_H_INC */ 54 55 #if NEOVERSE_V1_H_INC 56 { 57 .cpu_partnumber = NEOVERSE_V1_MIDR, 58 .cpu_errata_list = { 59 [0] = {2701953, 0x00, 0x11, ERRATA_V1_2701953, ERRATA_NON_ARM_INTERCONNECT}, 60 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 61 } 62 }, 63 #endif /* NEOVERSE_V1_H_INC */ 64 65 #if CORTEX_A710_H_INC 66 { 67 .cpu_partnumber = CORTEX_A710_MIDR, 68 .cpu_errata_list = { 69 [0] = {2701952, 0x00, 0x21, ERRATA_A710_2701952, ERRATA_NON_ARM_INTERCONNECT}, 70 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 71 } 72 }, 73 #endif /* CORTEX_A710_H_INC */ 74 75 #if NEOVERSE_N2_H_INC 76 { 77 .cpu_partnumber = NEOVERSE_N2_MIDR, 78 .cpu_errata_list = { 79 [0] = {2728475, 0x00, 0x02, ERRATA_N2_2728475, ERRATA_NON_ARM_INTERCONNECT}, 80 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 81 } 82 }, 83 #endif /* NEOVERSE_N2_H_INC */ 84 85 #if CORTEX_X2_H_INC 86 { 87 .cpu_partnumber = CORTEX_X2_MIDR, 88 .cpu_errata_list = { 89 [0] = {2701952, 0x00, 0x21, ERRATA_X2_2701952, ERRATA_NON_ARM_INTERCONNECT}, 90 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 91 } 92 }, 93 #endif /* CORTEX_X2_H_INC */ 94 95 #if NEOVERSE_V2_H_INC 96 { 97 .cpu_partnumber = NEOVERSE_V2_MIDR, 98 .cpu_errata_list = { 99 [0] = {2719103, 0x00, 0x01, ERRATA_V2_2719103, ERRATA_NON_ARM_INTERCONNECT}, 100 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 101 } 102 }, 103 #endif /* NEOVERSE_V2_H_INC */ 104 105 #if CORTEX_A715_H_INC 106 { 107 .cpu_partnumber = CORTEX_A715_MIDR, 108 .cpu_errata_list = { 109 [0] = {2701951, 0x00, 0x11, ERRATA_A715_2701951, ERRATA_NON_ARM_INTERCONNECT}, 110 [1 ... ERRATA_LIST_END] = UNDEF_ERRATA, 111 } 112 }, 113 #endif /* CORTEX_A715_H_INC */ 114 115 }; 116 117 /* Function to check if the errata exists for the specific CPU and rxpx */ 118 int32_t verify_errata_implemented(uint32_t errata_id, uint32_t forward_flag) 119 { 120 int32_t ret_val; 121 struct cpu_ops *cpu_ops; 122 struct erratum_entry *entry, *end; 123 long rev_var; 124 125 ret_val = EM_UNKNOWN_ERRATUM; 126 127 cpu_ops = get_cpu_ops_ptr(); 128 assert(cpu_ops != NULL); 129 130 entry = cpu_ops->errata_list_start; 131 assert(entry != NULL); 132 133 end = cpu_ops->errata_list_end; 134 assert(end != NULL); 135 136 rev_var = cpu_get_rev_var(); 137 138 end--; /* point to the last erratum entry of the queried cpu */ 139 140 while (entry <= end) { 141 if (entry->id == errata_id) { 142 if (entry->check_func(rev_var)) { 143 if (entry->chosen) 144 return EM_HIGHER_EL_MITIGATION; 145 else 146 return EM_AFFECTED; 147 } 148 return EM_NOT_AFFECTED; 149 } 150 entry += 1; 151 } 152 return ret_val; 153 } 154 155 /* Predicate indicating that a function id is part of EM_ABI */ 156 bool is_errata_fid(uint32_t smc_fid) 157 { 158 return ((smc_fid == ARM_EM_VERSION) || 159 (smc_fid == ARM_EM_FEATURES) || 160 (smc_fid == ARM_EM_CPU_ERRATUM_FEATURES)); 161 162 } 163 164 bool validate_spsr_mode(void) 165 { 166 /* In AArch64, if the caller is EL1, return true */ 167 168 #if __aarch64__ 169 if (GET_EL(read_spsr_el3()) == MODE_EL1) { 170 return true; 171 } 172 return false; 173 #else 174 175 /* In AArch32, if in system/svc mode, return true */ 176 uint8_t read_el_state = GET_M32(read_spsr()); 177 178 if ((read_el_state == (MODE32_svc)) || (read_el_state == MODE32_sys)) { 179 return true; 180 } 181 return false; 182 #endif /* __aarch64__ */ 183 } 184 185 uintptr_t errata_abi_smc_handler(uint32_t smc_fid, u_register_t x1, 186 u_register_t x2, u_register_t x3, u_register_t x4, 187 void *cookie, void *handle, u_register_t flags) 188 { 189 int32_t ret_id = EM_UNKNOWN_ERRATUM; 190 191 switch (smc_fid) { 192 case ARM_EM_VERSION: 193 SMC_RET1(handle, MAKE_SMCCC_VERSION( 194 EM_VERSION_MAJOR, EM_VERSION_MINOR 195 )); 196 break; /* unreachable */ 197 case ARM_EM_FEATURES: 198 if (is_errata_fid((uint32_t)x1)) { 199 SMC_RET1(handle, EM_SUCCESS); 200 } 201 202 SMC_RET1(handle, EM_NOT_SUPPORTED); 203 break; /* unreachable */ 204 case ARM_EM_CPU_ERRATUM_FEATURES: 205 206 /* 207 * If the forward flag is greater than zero and the calling EL 208 * is EL1 in AArch64 or in system mode or svc mode in case of AArch32, 209 * return Invalid Parameters. 210 */ 211 if (((uint32_t)x2 != 0) && (validate_spsr_mode())) { 212 SMC_RET1(handle, EM_INVALID_PARAMETERS); 213 } 214 ret_id = verify_errata_implemented((uint32_t)x1, (uint32_t)x2); 215 SMC_RET1(handle, ret_id); 216 break; /* unreachable */ 217 default: 218 { 219 WARN("Unimplemented Errata ABI Service Call: 0x%x\n", smc_fid); 220 SMC_RET1(handle, EM_UNKNOWN_ERRATUM); 221 break; /* unreachable */ 222 } 223 } 224 } 225