xref: /linux/drivers/firmware/efi/cper-arm.c (revision e7d759f31ca295d589f7420719c311870bb3166f)
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 	/* If the type is unknown, bail. */
97 	if (type > CPER_ARM_MAX_TYPE)
98 		return;
99 
100 	/*
101 	 * Vendor type errors have error information values that are vendor
102 	 * specific.
103 	 */
104 	if (type == CPER_ARM_VENDOR_ERROR)
105 		return;
106 
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]);
113 		}
114 	}
115 
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);
119 		switch (type) {
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]);
124 			}
125 			break;
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]);
130 			}
131 			break;
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]);
136 			}
137 			break;
138 		}
139 	}
140 
141 	if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
142 		level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
143 			 & CPER_ARM_ERR_LEVEL_MASK);
144 		switch (type) {
145 		case CPER_ARM_CACHE_ERROR:
146 			printk("%scache level: %d\n", pfx, level);
147 			break;
148 		case CPER_ARM_TLB_ERROR:
149 			printk("%sTLB level: %d\n", pfx, level);
150 			break;
151 		case CPER_ARM_BUS_ERROR:
152 			printk("%saffinity level at which the bus error occurred: %d\n",
153 			       pfx, level);
154 			break;
155 		}
156 	}
157 
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);
163 		else
164 			printk("%sprocessor context not corrupted\n", pfx);
165 	}
166 
167 	if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
168 		corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
169 			     & CPER_ARM_ERR_CORRECTED_MASK);
170 		if (corrected)
171 			printk("%sthe error has been corrected\n", pfx);
172 		else
173 			printk("%sthe error has not been corrected\n", pfx);
174 	}
175 
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);
179 		if (precise_pc)
180 			printk("%sPC is precise\n", pfx);
181 		else
182 			printk("%sPC is imprecise\n", pfx);
183 	}
184 
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);
188 		if (restartable_pc)
189 			printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
190 	}
191 
192 	/* The rest of the fields are specific to bus errors */
193 	if (type != CPER_ARM_BUS_ERROR)
194 		return;
195 
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]);
202 		}
203 	}
204 
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);
208 		if (time_out)
209 			printk("%srequest timed out\n", pfx);
210 	}
211 
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]);
218 		}
219 	}
220 
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);
225 	}
226 
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);
230 		if (access_mode)
231 			printk("%saccess mode: normal\n", pfx);
232 		else
233 			printk("%saccess mode: secure\n", pfx);
234 	}
235 }
236 
237 void cper_print_proc_arm(const char *pfx,
238 			 const struct cper_sec_proc_arm *proc)
239 {
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];
244 
245 	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
246 
247 	len = proc->section_length - (sizeof(*proc) +
248 		proc->err_info_num * (sizeof(*err_info)));
249 	if (len < 0) {
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);
254 		return;
255 	}
256 
257 	if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
258 		printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
259 			pfx, proc->mpidr);
260 
261 	if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
262 		printk("%serror affinity level: %d\n", pfx,
263 			proc->affinity_level);
264 
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);
269 	}
270 
271 	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
272 
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);
276 
277 		printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
278 
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",
286 				       newpfx);
287 			if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
288 				printk("%soverflow occurred, error info is incomplete\n",
289 				       newpfx);
290 		}
291 
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);
301 		}
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);
308 		err_info += 1;
309 	}
310 
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;
315 
316 		printk("%sContext info structure %d:\n", pfx, i);
317 		if (len < size) {
318 			printk("%ssection length is too small\n", newpfx);
319 			printk("%sfirmware-generated error record is incorrect\n", pfx);
320 			return;
321 		}
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);
325 			return;
326 		}
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);
331 		len -= size;
332 		ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
333 	}
334 
335 	if (len > 0) {
336 		printk("%sVendor specific error info has %u bytes:\n", pfx,
337 		       len);
338 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
339 				len, true);
340 	}
341 }
342