xref: /openbmc/linux/drivers/firmware/efi/cper.c (revision 8cb5d748)
1 /*
2  * UEFI Common Platform Error Record (CPER) support
3  *
4  * Copyright (C) 2010, Intel Corp.
5  *	Author: Huang Ying <ying.huang@intel.com>
6  *
7  * CPER is the format used to describe platform hardware error by
8  * various tables, such as ERST, BERT and HEST etc.
9  *
10  * For more information about CPER, please refer to Appendix N of UEFI
11  * Specification version 2.4.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License version
15  * 2 as published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26 
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/time.h>
30 #include <linux/cper.h>
31 #include <linux/dmi.h>
32 #include <linux/acpi.h>
33 #include <linux/pci.h>
34 #include <linux/aer.h>
35 #include <linux/printk.h>
36 #include <linux/bcd.h>
37 #include <acpi/ghes.h>
38 #include <ras/ras_event.h>
39 
40 #define INDENT_SP	" "
41 
42 static char rcd_decode_str[CPER_REC_LEN];
43 
44 /*
45  * CPER record ID need to be unique even after reboot, because record
46  * ID is used as index for ERST storage, while CPER records from
47  * multiple boot may co-exist in ERST.
48  */
49 u64 cper_next_record_id(void)
50 {
51 	static atomic64_t seq;
52 
53 	if (!atomic64_read(&seq))
54 		atomic64_set(&seq, ((u64)get_seconds()) << 32);
55 
56 	return atomic64_inc_return(&seq);
57 }
58 EXPORT_SYMBOL_GPL(cper_next_record_id);
59 
60 static const char * const severity_strs[] = {
61 	"recoverable",
62 	"fatal",
63 	"corrected",
64 	"info",
65 };
66 
67 const char *cper_severity_str(unsigned int severity)
68 {
69 	return severity < ARRAY_SIZE(severity_strs) ?
70 		severity_strs[severity] : "unknown";
71 }
72 EXPORT_SYMBOL_GPL(cper_severity_str);
73 
74 /*
75  * cper_print_bits - print strings for set bits
76  * @pfx: prefix for each line, including log level and prefix string
77  * @bits: bit mask
78  * @strs: string array, indexed by bit position
79  * @strs_size: size of the string array: @strs
80  *
81  * For each set bit in @bits, print the corresponding string in @strs.
82  * If the output length is longer than 80, multiple line will be
83  * printed, with @pfx is printed at the beginning of each line.
84  */
85 void cper_print_bits(const char *pfx, unsigned int bits,
86 		     const char * const strs[], unsigned int strs_size)
87 {
88 	int i, len = 0;
89 	const char *str;
90 	char buf[84];
91 
92 	for (i = 0; i < strs_size; i++) {
93 		if (!(bits & (1U << i)))
94 			continue;
95 		str = strs[i];
96 		if (!str)
97 			continue;
98 		if (len && len + strlen(str) + 2 > 80) {
99 			printk("%s\n", buf);
100 			len = 0;
101 		}
102 		if (!len)
103 			len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
104 		else
105 			len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
106 	}
107 	if (len)
108 		printk("%s\n", buf);
109 }
110 
111 static const char * const proc_type_strs[] = {
112 	"IA32/X64",
113 	"IA64",
114 	"ARM",
115 };
116 
117 static const char * const proc_isa_strs[] = {
118 	"IA32",
119 	"IA64",
120 	"X64",
121 	"ARM A32/T32",
122 	"ARM A64",
123 };
124 
125 static const char * const proc_error_type_strs[] = {
126 	"cache error",
127 	"TLB error",
128 	"bus error",
129 	"micro-architectural error",
130 };
131 
132 static const char * const proc_op_strs[] = {
133 	"unknown or generic",
134 	"data read",
135 	"data write",
136 	"instruction execution",
137 };
138 
139 static const char * const proc_flag_strs[] = {
140 	"restartable",
141 	"precise IP",
142 	"overflow",
143 	"corrected",
144 };
145 
146 static void cper_print_proc_generic(const char *pfx,
147 				    const struct cper_sec_proc_generic *proc)
148 {
149 	if (proc->validation_bits & CPER_PROC_VALID_TYPE)
150 		printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
151 		       proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
152 		       proc_type_strs[proc->proc_type] : "unknown");
153 	if (proc->validation_bits & CPER_PROC_VALID_ISA)
154 		printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
155 		       proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
156 		       proc_isa_strs[proc->proc_isa] : "unknown");
157 	if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
158 		printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
159 		cper_print_bits(pfx, proc->proc_error_type,
160 				proc_error_type_strs,
161 				ARRAY_SIZE(proc_error_type_strs));
162 	}
163 	if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
164 		printk("%s""operation: %d, %s\n", pfx, proc->operation,
165 		       proc->operation < ARRAY_SIZE(proc_op_strs) ?
166 		       proc_op_strs[proc->operation] : "unknown");
167 	if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
168 		printk("%s""flags: 0x%02x\n", pfx, proc->flags);
169 		cper_print_bits(pfx, proc->flags, proc_flag_strs,
170 				ARRAY_SIZE(proc_flag_strs));
171 	}
172 	if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
173 		printk("%s""level: %d\n", pfx, proc->level);
174 	if (proc->validation_bits & CPER_PROC_VALID_VERSION)
175 		printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
176 	if (proc->validation_bits & CPER_PROC_VALID_ID)
177 		printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
178 	if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
179 		printk("%s""target_address: 0x%016llx\n",
180 		       pfx, proc->target_addr);
181 	if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
182 		printk("%s""requestor_id: 0x%016llx\n",
183 		       pfx, proc->requestor_id);
184 	if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
185 		printk("%s""responder_id: 0x%016llx\n",
186 		       pfx, proc->responder_id);
187 	if (proc->validation_bits & CPER_PROC_VALID_IP)
188 		printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
189 }
190 
191 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
192 static const char * const arm_reg_ctx_strs[] = {
193 	"AArch32 general purpose registers",
194 	"AArch32 EL1 context registers",
195 	"AArch32 EL2 context registers",
196 	"AArch32 secure context registers",
197 	"AArch64 general purpose registers",
198 	"AArch64 EL1 context registers",
199 	"AArch64 EL2 context registers",
200 	"AArch64 EL3 context registers",
201 	"Misc. system register structure",
202 };
203 
204 static void cper_print_proc_arm(const char *pfx,
205 				const struct cper_sec_proc_arm *proc)
206 {
207 	int i, len, max_ctx_type;
208 	struct cper_arm_err_info *err_info;
209 	struct cper_arm_ctx_info *ctx_info;
210 	char newpfx[64];
211 
212 	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
213 
214 	len = proc->section_length - (sizeof(*proc) +
215 		proc->err_info_num * (sizeof(*err_info)));
216 	if (len < 0) {
217 		printk("%ssection length: %d\n", pfx, proc->section_length);
218 		printk("%ssection length is too small\n", pfx);
219 		printk("%sfirmware-generated error record is incorrect\n", pfx);
220 		printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
221 		return;
222 	}
223 
224 	if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
225 		printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
226 			pfx, proc->mpidr);
227 
228 	if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
229 		printk("%serror affinity level: %d\n", pfx,
230 			proc->affinity_level);
231 
232 	if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
233 		printk("%srunning state: 0x%x\n", pfx, proc->running_state);
234 		printk("%sPower State Coordination Interface state: %d\n",
235 			pfx, proc->psci_state);
236 	}
237 
238 	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
239 
240 	err_info = (struct cper_arm_err_info *)(proc + 1);
241 	for (i = 0; i < proc->err_info_num; i++) {
242 		printk("%sError info structure %d:\n", pfx, i);
243 
244 		printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
245 
246 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
247 			if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
248 				printk("%sfirst error captured\n", newpfx);
249 			if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
250 				printk("%slast error captured\n", newpfx);
251 			if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
252 				printk("%spropagated error captured\n",
253 				       newpfx);
254 			if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
255 				printk("%soverflow occurred, error info is incomplete\n",
256 				       newpfx);
257 		}
258 
259 		printk("%serror_type: %d, %s\n", newpfx, err_info->type,
260 			err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
261 			proc_error_type_strs[err_info->type] : "unknown");
262 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO)
263 			printk("%serror_info: 0x%016llx\n", newpfx,
264 			       err_info->error_info);
265 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
266 			printk("%svirtual fault address: 0x%016llx\n",
267 				newpfx, err_info->virt_fault_addr);
268 		if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
269 			printk("%sphysical fault address: 0x%016llx\n",
270 				newpfx, err_info->physical_fault_addr);
271 		err_info += 1;
272 	}
273 
274 	ctx_info = (struct cper_arm_ctx_info *)err_info;
275 	max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
276 	for (i = 0; i < proc->context_info_num; i++) {
277 		int size = sizeof(*ctx_info) + ctx_info->size;
278 
279 		printk("%sContext info structure %d:\n", pfx, i);
280 		if (len < size) {
281 			printk("%ssection length is too small\n", newpfx);
282 			printk("%sfirmware-generated error record is incorrect\n", pfx);
283 			return;
284 		}
285 		if (ctx_info->type > max_ctx_type) {
286 			printk("%sInvalid context type: %d (max: %d)\n",
287 				newpfx, ctx_info->type, max_ctx_type);
288 			return;
289 		}
290 		printk("%sregister context type: %s\n", newpfx,
291 			arm_reg_ctx_strs[ctx_info->type]);
292 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
293 				(ctx_info + 1), ctx_info->size, 0);
294 		len -= size;
295 		ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
296 	}
297 
298 	if (len > 0) {
299 		printk("%sVendor specific error info has %u bytes:\n", pfx,
300 		       len);
301 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
302 				len, true);
303 	}
304 }
305 #endif
306 
307 static const char * const mem_err_type_strs[] = {
308 	"unknown",
309 	"no error",
310 	"single-bit ECC",
311 	"multi-bit ECC",
312 	"single-symbol chipkill ECC",
313 	"multi-symbol chipkill ECC",
314 	"master abort",
315 	"target abort",
316 	"parity error",
317 	"watchdog timeout",
318 	"invalid address",
319 	"mirror Broken",
320 	"memory sparing",
321 	"scrub corrected error",
322 	"scrub uncorrected error",
323 	"physical memory map-out event",
324 };
325 
326 const char *cper_mem_err_type_str(unsigned int etype)
327 {
328 	return etype < ARRAY_SIZE(mem_err_type_strs) ?
329 		mem_err_type_strs[etype] : "unknown";
330 }
331 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
332 
333 static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
334 {
335 	u32 len, n;
336 
337 	if (!msg)
338 		return 0;
339 
340 	n = 0;
341 	len = CPER_REC_LEN - 1;
342 	if (mem->validation_bits & CPER_MEM_VALID_NODE)
343 		n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
344 	if (mem->validation_bits & CPER_MEM_VALID_CARD)
345 		n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
346 	if (mem->validation_bits & CPER_MEM_VALID_MODULE)
347 		n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
348 	if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
349 		n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
350 	if (mem->validation_bits & CPER_MEM_VALID_BANK)
351 		n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
352 	if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
353 		n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
354 	if (mem->validation_bits & CPER_MEM_VALID_ROW)
355 		n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
356 	if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
357 		n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
358 	if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
359 		n += scnprintf(msg + n, len - n, "bit_position: %d ",
360 			       mem->bit_pos);
361 	if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
362 		n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
363 			       mem->requestor_id);
364 	if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
365 		n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
366 			       mem->responder_id);
367 	if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
368 		scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
369 			  mem->target_id);
370 
371 	msg[n] = '\0';
372 	return n;
373 }
374 
375 static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
376 {
377 	u32 len, n;
378 	const char *bank = NULL, *device = NULL;
379 
380 	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
381 		return 0;
382 
383 	n = 0;
384 	len = CPER_REC_LEN - 1;
385 	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
386 	if (bank && device)
387 		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
388 	else
389 		n = snprintf(msg, len,
390 			     "DIMM location: not present. DMI handle: 0x%.4x ",
391 			     mem->mem_dev_handle);
392 
393 	msg[n] = '\0';
394 	return n;
395 }
396 
397 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
398 		       struct cper_mem_err_compact *cmem)
399 {
400 	cmem->validation_bits = mem->validation_bits;
401 	cmem->node = mem->node;
402 	cmem->card = mem->card;
403 	cmem->module = mem->module;
404 	cmem->bank = mem->bank;
405 	cmem->device = mem->device;
406 	cmem->row = mem->row;
407 	cmem->column = mem->column;
408 	cmem->bit_pos = mem->bit_pos;
409 	cmem->requestor_id = mem->requestor_id;
410 	cmem->responder_id = mem->responder_id;
411 	cmem->target_id = mem->target_id;
412 	cmem->rank = mem->rank;
413 	cmem->mem_array_handle = mem->mem_array_handle;
414 	cmem->mem_dev_handle = mem->mem_dev_handle;
415 }
416 
417 const char *cper_mem_err_unpack(struct trace_seq *p,
418 				struct cper_mem_err_compact *cmem)
419 {
420 	const char *ret = trace_seq_buffer_ptr(p);
421 
422 	if (cper_mem_err_location(cmem, rcd_decode_str))
423 		trace_seq_printf(p, "%s", rcd_decode_str);
424 	if (cper_dimm_err_location(cmem, rcd_decode_str))
425 		trace_seq_printf(p, "%s", rcd_decode_str);
426 	trace_seq_putc(p, '\0');
427 
428 	return ret;
429 }
430 
431 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
432 	int len)
433 {
434 	struct cper_mem_err_compact cmem;
435 
436 	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
437 	if (len == sizeof(struct cper_sec_mem_err_old) &&
438 	    (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
439 		pr_err(FW_WARN "valid bits set for fields beyond structure\n");
440 		return;
441 	}
442 	if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
443 		printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
444 	if (mem->validation_bits & CPER_MEM_VALID_PA)
445 		printk("%s""physical_address: 0x%016llx\n",
446 		       pfx, mem->physical_addr);
447 	if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
448 		printk("%s""physical_address_mask: 0x%016llx\n",
449 		       pfx, mem->physical_addr_mask);
450 	cper_mem_err_pack(mem, &cmem);
451 	if (cper_mem_err_location(&cmem, rcd_decode_str))
452 		printk("%s%s\n", pfx, rcd_decode_str);
453 	if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
454 		u8 etype = mem->error_type;
455 		printk("%s""error_type: %d, %s\n", pfx, etype,
456 		       cper_mem_err_type_str(etype));
457 	}
458 	if (cper_dimm_err_location(&cmem, rcd_decode_str))
459 		printk("%s%s\n", pfx, rcd_decode_str);
460 }
461 
462 static const char * const pcie_port_type_strs[] = {
463 	"PCIe end point",
464 	"legacy PCI end point",
465 	"unknown",
466 	"unknown",
467 	"root port",
468 	"upstream switch port",
469 	"downstream switch port",
470 	"PCIe to PCI/PCI-X bridge",
471 	"PCI/PCI-X to PCIe bridge",
472 	"root complex integrated endpoint device",
473 	"root complex event collector",
474 };
475 
476 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
477 			    const struct acpi_hest_generic_data *gdata)
478 {
479 	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
480 		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
481 		       pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
482 		       pcie_port_type_strs[pcie->port_type] : "unknown");
483 	if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
484 		printk("%s""version: %d.%d\n", pfx,
485 		       pcie->version.major, pcie->version.minor);
486 	if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
487 		printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
488 		       pcie->command, pcie->status);
489 	if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
490 		const __u8 *p;
491 		printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
492 		       pcie->device_id.segment, pcie->device_id.bus,
493 		       pcie->device_id.device, pcie->device_id.function);
494 		printk("%s""slot: %d\n", pfx,
495 		       pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
496 		printk("%s""secondary_bus: 0x%02x\n", pfx,
497 		       pcie->device_id.secondary_bus);
498 		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
499 		       pcie->device_id.vendor_id, pcie->device_id.device_id);
500 		p = pcie->device_id.class_code;
501 		printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
502 	}
503 	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
504 		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
505 		       pcie->serial_number.lower, pcie->serial_number.upper);
506 	if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
507 		printk(
508 	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
509 	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
510 }
511 
512 static void cper_print_tstamp(const char *pfx,
513 				   struct acpi_hest_generic_data_v300 *gdata)
514 {
515 	__u8 hour, min, sec, day, mon, year, century, *timestamp;
516 
517 	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
518 		timestamp = (__u8 *)&(gdata->time_stamp);
519 		sec       = bcd2bin(timestamp[0]);
520 		min       = bcd2bin(timestamp[1]);
521 		hour      = bcd2bin(timestamp[2]);
522 		day       = bcd2bin(timestamp[4]);
523 		mon       = bcd2bin(timestamp[5]);
524 		year      = bcd2bin(timestamp[6]);
525 		century   = bcd2bin(timestamp[7]);
526 
527 		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
528 		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),
529 		       century, year, mon, day, hour, min, sec);
530 	}
531 }
532 
533 static void
534 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
535 			   int sec_no)
536 {
537 	guid_t *sec_type = (guid_t *)gdata->section_type;
538 	__u16 severity;
539 	char newpfx[64];
540 
541 	if (acpi_hest_get_version(gdata) >= 3)
542 		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
543 
544 	severity = gdata->error_severity;
545 	printk("%s""Error %d, type: %s\n", pfx, sec_no,
546 	       cper_severity_str(severity));
547 	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
548 		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
549 	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
550 		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
551 
552 	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
553 	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
554 		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
555 
556 		printk("%s""section_type: general processor error\n", newpfx);
557 		if (gdata->error_data_length >= sizeof(*proc_err))
558 			cper_print_proc_generic(newpfx, proc_err);
559 		else
560 			goto err_section_too_small;
561 	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
562 		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
563 
564 		printk("%s""section_type: memory error\n", newpfx);
565 		if (gdata->error_data_length >=
566 		    sizeof(struct cper_sec_mem_err_old))
567 			cper_print_mem(newpfx, mem_err,
568 				       gdata->error_data_length);
569 		else
570 			goto err_section_too_small;
571 	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
572 		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
573 
574 		printk("%s""section_type: PCIe error\n", newpfx);
575 		if (gdata->error_data_length >= sizeof(*pcie))
576 			cper_print_pcie(newpfx, pcie, gdata);
577 		else
578 			goto err_section_too_small;
579 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
580 	} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
581 		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
582 
583 		printk("%ssection_type: ARM processor error\n", newpfx);
584 		if (gdata->error_data_length >= sizeof(*arm_err))
585 			cper_print_proc_arm(newpfx, arm_err);
586 		else
587 			goto err_section_too_small;
588 #endif
589 	} else {
590 		const void *err = acpi_hest_get_payload(gdata);
591 
592 		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
593 		printk("%ssection length: %#x\n", newpfx,
594 		       gdata->error_data_length);
595 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
596 			       gdata->error_data_length, true);
597 	}
598 
599 	return;
600 
601 err_section_too_small:
602 	pr_err(FW_WARN "error section length is too small\n");
603 }
604 
605 void cper_estatus_print(const char *pfx,
606 			const struct acpi_hest_generic_status *estatus)
607 {
608 	struct acpi_hest_generic_data *gdata;
609 	int sec_no = 0;
610 	char newpfx[64];
611 	__u16 severity;
612 
613 	severity = estatus->error_severity;
614 	if (severity == CPER_SEV_CORRECTED)
615 		printk("%s%s\n", pfx,
616 		       "It has been corrected by h/w "
617 		       "and requires no further action");
618 	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
619 	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
620 
621 	apei_estatus_for_each_section(estatus, gdata) {
622 		cper_estatus_print_section(newpfx, gdata, sec_no);
623 		sec_no++;
624 	}
625 }
626 EXPORT_SYMBOL_GPL(cper_estatus_print);
627 
628 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
629 {
630 	if (estatus->data_length &&
631 	    estatus->data_length < sizeof(struct acpi_hest_generic_data))
632 		return -EINVAL;
633 	if (estatus->raw_data_length &&
634 	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
635 		return -EINVAL;
636 
637 	return 0;
638 }
639 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
640 
641 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
642 {
643 	struct acpi_hest_generic_data *gdata;
644 	unsigned int data_len, gedata_len;
645 	int rc;
646 
647 	rc = cper_estatus_check_header(estatus);
648 	if (rc)
649 		return rc;
650 	data_len = estatus->data_length;
651 
652 	apei_estatus_for_each_section(estatus, gdata) {
653 		gedata_len = acpi_hest_get_error_length(gdata);
654 		if (gedata_len > data_len - acpi_hest_get_size(gdata))
655 			return -EINVAL;
656 		data_len -= acpi_hest_get_record_size(gdata);
657 	}
658 	if (data_len)
659 		return -EINVAL;
660 
661 	return 0;
662 }
663 EXPORT_SYMBOL_GPL(cper_estatus_check);
664