1 // SPDX-License-Identifier: GPL-2.0
3 * UEFI Common Platform Error Record (CPER) support
5 * Copyright (C) 2017, The Linux Foundation. All rights reserved.
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/time.h>
11 #include <linux/cper.h>
12 #include <linux/dmi.h>
13 #include <linux/acpi.h>
14 #include <linux/pci.h>
15 #include <linux/printk.h>
16 #include <linux/bcd.h>
17 #include <acpi/ghes.h>
18 #include <ras/ras_event.h>
20 static const char * const arm_reg_ctx_strs[] = {
21 "AArch32 general purpose registers",
22 "AArch32 EL1 context registers",
23 "AArch32 EL2 context registers",
24 "AArch32 secure context registers",
25 "AArch64 general purpose registers",
26 "AArch64 EL1 context registers",
27 "AArch64 EL2 context registers",
28 "AArch64 EL3 context registers",
29 "Misc. system register structure",
32 static const char * const arm_err_trans_type_strs[] = {
38 static const char * const arm_bus_err_op_strs[] = {
39 "Generic error (type cannot be determined)",
40 "Generic read (type of instruction or data request cannot be determined)",
41 "Generic write (type of instruction of data request cannot be determined)",
48 static const char * const arm_cache_err_op_strs[] = {
49 "Generic error (type cannot be determined)",
50 "Generic read (type of instruction or data request cannot be determined)",
51 "Generic write (type of instruction of data request cannot be determined)",
57 "Snooping (processor initiated a cache snoop that resulted in an error)",
58 "Snooped (processor raised a cache error caused by another processor or device snooping its cache)",
62 static const char * const arm_tlb_err_op_strs[] = {
63 "Generic error (type cannot be determined)",
64 "Generic read (type of instruction or data request cannot be determined)",
65 "Generic write (type of instruction of data request cannot be determined)",
70 "Local management operation (processor initiated a TLB management operation that resulted in an error)",
71 "External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)",
74 static const char * const arm_bus_err_part_type_strs[] = {
75 "Local processor originated request",
76 "Local processor responded to request",
77 "Local processor observed",
81 static const char * const arm_bus_err_addr_space_strs[] = {
82 "External Memory Access",
83 "Internal Memory Access",
85 "Device Memory Access",
88 static void cper_print_arm_err_info(const char *pfx, u32 type,
91 u8 trans_type, op_type, level, participation_type, address_space;
93 bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
94 bool time_out, access_mode;
96 /* If the type is unknown, bail. */
97 if (type > CPER_ARM_MAX_TYPE)
101 * Vendor type errors have error information values that are vendor
104 if (type == CPER_ARM_VENDOR_ERROR)
107 if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
108 trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
109 & CPER_ARM_ERR_TRANSACTION_MASK);
110 if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
111 printk("%stransaction type: %s\n", pfx,
112 arm_err_trans_type_strs[trans_type]);
116 if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
117 op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
118 & CPER_ARM_ERR_OPERATION_MASK);
120 case CPER_ARM_CACHE_ERROR:
121 if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
122 printk("%soperation type: %s\n", pfx,
123 arm_cache_err_op_strs[op_type]);
126 case CPER_ARM_TLB_ERROR:
127 if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
128 printk("%soperation type: %s\n", pfx,
129 arm_tlb_err_op_strs[op_type]);
132 case CPER_ARM_BUS_ERROR:
133 if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
134 printk("%soperation type: %s\n", pfx,
135 arm_bus_err_op_strs[op_type]);
141 if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
142 level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
143 & CPER_ARM_ERR_LEVEL_MASK);
145 case CPER_ARM_CACHE_ERROR:
146 printk("%scache level: %d\n", pfx, level);
148 case CPER_ARM_TLB_ERROR:
149 printk("%sTLB level: %d\n", pfx, level);
151 case CPER_ARM_BUS_ERROR:
152 printk("%saffinity level at which the bus error occurred: %d\n",
158 if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
159 proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
160 & CPER_ARM_ERR_PC_CORRUPT_MASK);
161 if (proc_context_corrupt)
162 printk("%sprocessor context corrupted\n", pfx);
164 printk("%sprocessor context not corrupted\n", pfx);
167 if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
168 corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
169 & CPER_ARM_ERR_CORRECTED_MASK);
171 printk("%sthe error has been corrected\n", pfx);
173 printk("%sthe error has not been corrected\n", pfx);
176 if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
177 precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
178 & CPER_ARM_ERR_PRECISE_PC_MASK);
180 printk("%sPC is precise\n", pfx);
182 printk("%sPC is imprecise\n", pfx);
185 if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
186 restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
187 & CPER_ARM_ERR_RESTARTABLE_PC_MASK);
189 printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
192 /* The rest of the fields are specific to bus errors */
193 if (type != CPER_ARM_BUS_ERROR)
196 if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
197 participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
198 & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
199 if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
200 printk("%sparticipation type: %s\n", pfx,
201 arm_bus_err_part_type_strs[participation_type]);
205 if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
206 time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
207 & CPER_ARM_ERR_TIME_OUT_MASK);
209 printk("%srequest timed out\n", pfx);
212 if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
213 address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
214 & CPER_ARM_ERR_ADDRESS_SPACE_MASK);
215 if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
216 printk("%saddress space: %s\n", pfx,
217 arm_bus_err_addr_space_strs[address_space]);
221 if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
222 mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
223 & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
224 printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
227 if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
228 access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
229 & CPER_ARM_ERR_ACCESS_MODE_MASK);
231 printk("%saccess mode: normal\n", pfx);
233 printk("%saccess mode: secure\n", pfx);
237 void cper_print_proc_arm(const char *pfx,
238 const struct cper_sec_proc_arm *proc)
240 int i, len, max_ctx_type;
241 struct cper_arm_err_info *err_info;
242 struct cper_arm_ctx_info *ctx_info;
243 char newpfx[64], infopfx[64];
245 printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
247 len = proc->section_length - (sizeof(*proc) +
248 proc->err_info_num * (sizeof(*err_info)));
250 printk("%ssection length: %d\n", pfx, proc->section_length);
251 printk("%ssection length is too small\n", pfx);
252 printk("%sfirmware-generated error record is incorrect\n", pfx);
253 printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
257 if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
258 printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
261 if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
262 printk("%serror affinity level: %d\n", pfx,
263 proc->affinity_level);
265 if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
266 printk("%srunning state: 0x%x\n", pfx, proc->running_state);
267 printk("%sPower State Coordination Interface state: %d\n",
268 pfx, proc->psci_state);
271 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
273 err_info = (struct cper_arm_err_info *)(proc + 1);
274 for (i = 0; i < proc->err_info_num; i++) {
275 printk("%sError info structure %d:\n", pfx, i);
277 printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
279 if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
280 if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
281 printk("%sfirst error captured\n", newpfx);
282 if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
283 printk("%slast error captured\n", newpfx);
284 if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
285 printk("%spropagated error captured\n",
287 if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
288 printk("%soverflow occurred, error info is incomplete\n",
292 printk("%serror_type: %d, %s\n", newpfx, err_info->type,
293 err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
294 cper_proc_error_type_strs[err_info->type] : "unknown");
295 if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
296 printk("%serror_info: 0x%016llx\n", newpfx,
297 err_info->error_info);
298 snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
299 cper_print_arm_err_info(infopfx, err_info->type,
300 err_info->error_info);
302 if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
303 printk("%svirtual fault address: 0x%016llx\n",
304 newpfx, err_info->virt_fault_addr);
305 if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
306 printk("%sphysical fault address: 0x%016llx\n",
307 newpfx, err_info->physical_fault_addr);
311 ctx_info = (struct cper_arm_ctx_info *)err_info;
312 max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
313 for (i = 0; i < proc->context_info_num; i++) {
314 int size = sizeof(*ctx_info) + ctx_info->size;
316 printk("%sContext info structure %d:\n", pfx, i);
318 printk("%ssection length is too small\n", newpfx);
319 printk("%sfirmware-generated error record is incorrect\n", pfx);
322 if (ctx_info->type > max_ctx_type) {
323 printk("%sInvalid context type: %d (max: %d)\n",
324 newpfx, ctx_info->type, max_ctx_type);
327 printk("%sregister context type: %s\n", newpfx,
328 arm_reg_ctx_strs[ctx_info->type]);
329 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
330 (ctx_info + 1), ctx_info->size, 0);
332 ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
336 printk("%sVendor specific error info has %u bytes:\n", pfx,
338 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,