xref: /linux/drivers/firmware/efi/cper-arm.c (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * UEFI Common Platform Error Record (CPER) support
4  *
5  * Copyright (C) 2017, The Linux Foundation. All rights reserved.
6  */
7 
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>
19 
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",
30 };
31 
32 static const char * const arm_err_trans_type_strs[] = {
33 	"Instruction",
34 	"Data Access",
35 	"Generic",
36 };
37 
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)",
42 	"Data read",
43 	"Data write",
44 	"Instruction fetch",
45 	"Prefetch",
46 };
47 
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)",
52 	"Data read",
53 	"Data write",
54 	"Instruction fetch",
55 	"Prefetch",
56 	"Eviction",
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)",
59 	"Management",
60 };
61 
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)",
66 	"Data read",
67 	"Data write",
68 	"Instruction fetch",
69 	"Prefetch",
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)",
72 };
73 
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",
78 	"Generic",
79 };
80 
81 static const char * const arm_bus_err_addr_space_strs[] = {
82 	"External Memory Access",
83 	"Internal Memory Access",
84 	"Unknown",
85 	"Device Memory Access",
86 };
87 
88 static void cper_print_arm_err_info(const char *pfx, u32 type,
89 				    u64 error_info)
90 {
91 	u8 trans_type, op_type, level, participation_type, address_space;
92 	u16 mem_attributes;
93 	bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
94 	bool time_out, access_mode;
95 
96 	/*
97 	 * Vendor type errors have error information values that are vendor
98 	 * specific.
99 	 */
100 	if (type & CPER_ARM_VENDOR_ERROR)
101 		return;
102 
103 	if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
104 		trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
105 			      & CPER_ARM_ERR_TRANSACTION_MASK);
106 		if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
107 			printk("%stransaction type: %s\n", pfx,
108 			       arm_err_trans_type_strs[trans_type]);
109 		}
110 	}
111 
112 	if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
113 		op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
114 			   & CPER_ARM_ERR_OPERATION_MASK);
115 		if (type & CPER_ARM_CACHE_ERROR) {
116 			if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
117 				printk("%scache error, operation type: %s\n", pfx,
118 				       arm_cache_err_op_strs[op_type]);
119 			}
120 		}
121 		if (type & CPER_ARM_TLB_ERROR) {
122 			if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
123 				printk("%sTLB error, operation type: %s\n", pfx,
124 				       arm_tlb_err_op_strs[op_type]);
125 			}
126 		}
127 		if (type & CPER_ARM_BUS_ERROR) {
128 			if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
129 				printk("%sbus error, operation type: %s\n", pfx,
130 				       arm_bus_err_op_strs[op_type]);
131 			}
132 		}
133 	}
134 
135 	if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
136 		level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
137 			 & CPER_ARM_ERR_LEVEL_MASK);
138 		if (type & CPER_ARM_CACHE_ERROR)
139 			printk("%scache level: %d\n", pfx, level);
140 
141 		if (type & CPER_ARM_TLB_ERROR)
142 			printk("%sTLB level: %d\n", pfx, level);
143 
144 		if (type & CPER_ARM_BUS_ERROR)
145 			printk("%saffinity level at which the bus error occurred: %d\n",
146 			       pfx, level);
147 	}
148 
149 	if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
150 		proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
151 					& CPER_ARM_ERR_PC_CORRUPT_MASK);
152 		if (proc_context_corrupt)
153 			printk("%sprocessor context corrupted\n", pfx);
154 		else
155 			printk("%sprocessor context not corrupted\n", pfx);
156 	}
157 
158 	if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
159 		corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
160 			     & CPER_ARM_ERR_CORRECTED_MASK);
161 		if (corrected)
162 			printk("%sthe error has been corrected\n", pfx);
163 		else
164 			printk("%sthe error has not been corrected\n", pfx);
165 	}
166 
167 	if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
168 		precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
169 			      & CPER_ARM_ERR_PRECISE_PC_MASK);
170 		if (precise_pc)
171 			printk("%sPC is precise\n", pfx);
172 		else
173 			printk("%sPC is imprecise\n", pfx);
174 	}
175 
176 	if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
177 		restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
178 				  & CPER_ARM_ERR_RESTARTABLE_PC_MASK);
179 		if (restartable_pc)
180 			printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
181 	}
182 
183 	/* The rest of the fields are specific to bus errors */
184 	if (type != CPER_ARM_BUS_ERROR)
185 		return;
186 
187 	if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
188 		participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
189 				      & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
190 		if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
191 			printk("%sparticipation type: %s\n", pfx,
192 			       arm_bus_err_part_type_strs[participation_type]);
193 		}
194 	}
195 
196 	if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
197 		time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
198 			    & CPER_ARM_ERR_TIME_OUT_MASK);
199 		if (time_out)
200 			printk("%srequest timed out\n", pfx);
201 	}
202 
203 	if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
204 		address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
205 				 & CPER_ARM_ERR_ADDRESS_SPACE_MASK);
206 		if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
207 			printk("%saddress space: %s\n", pfx,
208 			       arm_bus_err_addr_space_strs[address_space]);
209 		}
210 	}
211 
212 	if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
213 		mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
214 				  & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
215 		printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
216 	}
217 
218 	if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
219 		access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
220 			       & CPER_ARM_ERR_ACCESS_MODE_MASK);
221 		if (access_mode)
222 			printk("%saccess mode: normal\n", pfx);
223 		else
224 			printk("%saccess mode: secure\n", pfx);
225 	}
226 }
227 
228 void cper_print_proc_arm(const char *pfx,
229 			 const struct cper_sec_proc_arm *proc,
230 			 u32 length)
231 {
232 	int i, len, max_ctx_type;
233 	struct cper_arm_err_info *err_info;
234 	struct cper_arm_ctx_info *ctx_info;
235 	char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1];
236 	char error_type[120];
237 
238 	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
239 
240 	len = proc->section_length - (sizeof(*proc) +
241 		proc->err_info_num * (sizeof(*err_info)));
242 
243 	if (len < 0 || proc->section_length > length) {
244 		printk("%ssection length: %d, CPER size: %d\n",
245 		       pfx, proc->section_length, length);
246 		printk("%ssection length is too %s\n", pfx,
247 		       (len < 0) ? "small" : "big");
248 		printk("%sfirmware-generated error record is incorrect\n", pfx);
249 		printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
250 		return;
251 	}
252 
253 	if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
254 		printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
255 			pfx, proc->mpidr);
256 
257 	if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
258 		printk("%serror affinity level: %d\n", pfx,
259 			proc->affinity_level);
260 
261 	if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
262 		printk("%srunning state: 0x%x\n", pfx, proc->running_state);
263 		printk("%sPower State Coordination Interface state: %d\n",
264 			pfx, proc->psci_state);
265 	}
266 
267 	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
268 
269 	err_info = (struct cper_arm_err_info *)(proc + 1);
270 	for (i = 0; i < proc->err_info_num; i++) {
271 		printk("%sError info structure %d:\n", pfx, i);
272 
273 		printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
274 
275 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
276 			if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
277 				printk("%sfirst error captured\n", newpfx);
278 			if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
279 				printk("%slast error captured\n", newpfx);
280 			if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
281 				printk("%spropagated error captured\n",
282 				       newpfx);
283 			if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
284 				printk("%soverflow occurred, error info is incomplete\n",
285 				       newpfx);
286 		}
287 
288 		cper_bits_to_str(error_type, sizeof(error_type),
289 				 FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
290 				 cper_proc_error_type_strs,
291 				 ARRAY_SIZE(cper_proc_error_type_strs));
292 
293 		printk("%serror_type: 0x%02x: %s%s\n", newpfx, err_info->type,
294 		       error_type,
295 		       (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
296 
297 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
298 			printk("%serror_info: 0x%016llx\n", newpfx,
299 			       err_info->error_info);
300 			snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
301 			cper_print_arm_err_info(infopfx, err_info->type,
302 						err_info->error_info);
303 		}
304 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
305 			printk("%svirtual fault address: 0x%016llx\n",
306 				newpfx, err_info->virt_fault_addr);
307 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
308 			printk("%sphysical fault address: 0x%016llx\n",
309 				newpfx, err_info->physical_fault_addr);
310 		err_info += 1;
311 	}
312 
313 	ctx_info = (struct cper_arm_ctx_info *)err_info;
314 	max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
315 	for (i = 0; i < proc->context_info_num; i++) {
316 		int size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16);
317 
318 		printk("%sContext info structure %d:\n", pfx, i);
319 		if (len < size) {
320 			printk("%ssection length is too small\n", newpfx);
321 			printk("%sfirmware-generated error record is incorrect\n", pfx);
322 			return;
323 		}
324 		if (ctx_info->type > max_ctx_type) {
325 			printk("%sInvalid context type: %d (max: %d)\n",
326 				newpfx, ctx_info->type, max_ctx_type);
327 			return;
328 		}
329 		printk("%sregister context type: %s\n", newpfx,
330 			arm_reg_ctx_strs[ctx_info->type]);
331 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
332 				(ctx_info + 1), ctx_info->size, 0);
333 		len -= size;
334 		ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
335 	}
336 
337 	if (len > 0) {
338 		printk("%sVendor specific error info has %u bytes:\n", pfx,
339 		       len);
340 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
341 				len, true);
342 	}
343 }
344