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