Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * UEFI Common Platform Error Record (CPER) support
  4 *
  5 * Copyright (C) 2010, Intel Corp.
  6 *	Author: Huang Ying <ying.huang@intel.com>
  7 *
  8 * CPER is the format used to describe platform hardware error by
  9 * various tables, such as ERST, BERT and HEST etc.
 10 *
 11 * For more information about CPER, please refer to Appendix N of UEFI
 12 * Specification version 2.4.
 13 */
 14
 15#include <linux/kernel.h>
 16#include <linux/module.h>
 17#include <linux/time.h>
 18#include <linux/cper.h>
 19#include <linux/dmi.h>
 20#include <linux/acpi.h>
 21#include <linux/pci.h>
 22#include <linux/aer.h>
 23#include <linux/printk.h>
 24#include <linux/bcd.h>
 25#include <acpi/ghes.h>
 26#include <ras/ras_event.h>
 27#include "cper_cxl.h"
 
 28
 29/*
 30 * CPER record ID need to be unique even after reboot, because record
 31 * ID is used as index for ERST storage, while CPER records from
 32 * multiple boot may co-exist in ERST.
 33 */
 34u64 cper_next_record_id(void)
 35{
 36	static atomic64_t seq;
 37
 38	if (!atomic64_read(&seq)) {
 39		time64_t time = ktime_get_real_seconds();
 40
 41		/*
 42		 * This code is unlikely to still be needed in year 2106,
 43		 * but just in case, let's use a few more bits for timestamps
 44		 * after y2038 to be sure they keep increasing monotonically
 45		 * for the next few hundred years...
 46		 */
 47		if (time < 0x80000000)
 48			atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
 49		else
 50			atomic64_set(&seq, 0x8000000000000000ull |
 51					   ktime_get_real_seconds() << 24);
 52	}
 53
 54	return atomic64_inc_return(&seq);
 55}
 56EXPORT_SYMBOL_GPL(cper_next_record_id);
 57
 58static const char * const severity_strs[] = {
 59	"recoverable",
 60	"fatal",
 61	"corrected",
 62	"info",
 63};
 64
 65const char *cper_severity_str(unsigned int severity)
 66{
 67	return severity < ARRAY_SIZE(severity_strs) ?
 68		severity_strs[severity] : "unknown";
 69}
 70EXPORT_SYMBOL_GPL(cper_severity_str);
 71
 72/*
 73 * cper_print_bits - print strings for set bits
 74 * @pfx: prefix for each line, including log level and prefix string
 75 * @bits: bit mask
 76 * @strs: string array, indexed by bit position
 77 * @strs_size: size of the string array: @strs
 78 *
 79 * For each set bit in @bits, print the corresponding string in @strs.
 80 * If the output length is longer than 80, multiple line will be
 81 * printed, with @pfx is printed at the beginning of each line.
 82 */
 83void cper_print_bits(const char *pfx, unsigned int bits,
 84		     const char * const strs[], unsigned int strs_size)
 85{
 86	int i, len = 0;
 87	const char *str;
 88	char buf[84];
 89
 90	for (i = 0; i < strs_size; i++) {
 91		if (!(bits & (1U << i)))
 92			continue;
 93		str = strs[i];
 94		if (!str)
 95			continue;
 96		if (len && len + strlen(str) + 2 > 80) {
 97			printk("%s\n", buf);
 98			len = 0;
 99		}
100		if (!len)
101			len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
102		else
103			len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
104	}
105	if (len)
106		printk("%s\n", buf);
107}
108
109static const char * const proc_type_strs[] = {
110	"IA32/X64",
111	"IA64",
112	"ARM",
113};
114
115static const char * const proc_isa_strs[] = {
116	"IA32",
117	"IA64",
118	"X64",
119	"ARM A32/T32",
120	"ARM A64",
121};
122
123const char * const cper_proc_error_type_strs[] = {
124	"cache error",
125	"TLB error",
126	"bus error",
127	"micro-architectural error",
128};
129
130static const char * const proc_op_strs[] = {
131	"unknown or generic",
132	"data read",
133	"data write",
134	"instruction execution",
135};
136
137static const char * const proc_flag_strs[] = {
138	"restartable",
139	"precise IP",
140	"overflow",
141	"corrected",
142};
143
144static void cper_print_proc_generic(const char *pfx,
145				    const struct cper_sec_proc_generic *proc)
146{
147	if (proc->validation_bits & CPER_PROC_VALID_TYPE)
148		printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
149		       proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
150		       proc_type_strs[proc->proc_type] : "unknown");
151	if (proc->validation_bits & CPER_PROC_VALID_ISA)
152		printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
153		       proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
154		       proc_isa_strs[proc->proc_isa] : "unknown");
155	if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
156		printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
157		cper_print_bits(pfx, proc->proc_error_type,
158				cper_proc_error_type_strs,
159				ARRAY_SIZE(cper_proc_error_type_strs));
160	}
161	if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
162		printk("%s""operation: %d, %s\n", pfx, proc->operation,
163		       proc->operation < ARRAY_SIZE(proc_op_strs) ?
164		       proc_op_strs[proc->operation] : "unknown");
165	if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
166		printk("%s""flags: 0x%02x\n", pfx, proc->flags);
167		cper_print_bits(pfx, proc->flags, proc_flag_strs,
168				ARRAY_SIZE(proc_flag_strs));
169	}
170	if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
171		printk("%s""level: %d\n", pfx, proc->level);
172	if (proc->validation_bits & CPER_PROC_VALID_VERSION)
173		printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
174	if (proc->validation_bits & CPER_PROC_VALID_ID)
175		printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
176	if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
177		printk("%s""target_address: 0x%016llx\n",
178		       pfx, proc->target_addr);
179	if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
180		printk("%s""requestor_id: 0x%016llx\n",
181		       pfx, proc->requestor_id);
182	if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
183		printk("%s""responder_id: 0x%016llx\n",
184		       pfx, proc->responder_id);
185	if (proc->validation_bits & CPER_PROC_VALID_IP)
186		printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
187}
188
189static const char * const mem_err_type_strs[] = {
190	"unknown",
191	"no error",
192	"single-bit ECC",
193	"multi-bit ECC",
194	"single-symbol chipkill ECC",
195	"multi-symbol chipkill ECC",
196	"master abort",
197	"target abort",
198	"parity error",
199	"watchdog timeout",
200	"invalid address",
201	"mirror Broken",
202	"memory sparing",
203	"scrub corrected error",
204	"scrub uncorrected error",
205	"physical memory map-out event",
206};
207
208const char *cper_mem_err_type_str(unsigned int etype)
209{
210	return etype < ARRAY_SIZE(mem_err_type_strs) ?
211		mem_err_type_strs[etype] : "unknown";
212}
213EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
214
215const char *cper_mem_err_status_str(u64 status)
216{
217	switch ((status >> 8) & 0xff) {
218	case  1:	return "Error detected internal to the component";
219	case  4:	return "Storage error in DRAM memory";
220	case  5:	return "Storage error in TLB";
221	case  6:	return "Storage error in cache";
222	case  7:	return "Error in one or more functional units";
223	case  8:	return "Component failed self test";
224	case  9:	return "Overflow or undervalue of internal queue";
225	case 16:	return "Error detected in the bus";
226	case 17:	return "Virtual address not found on IO-TLB or IO-PDIR";
227	case 18:	return "Improper access error";
228	case 19:	return "Access to a memory address which is not mapped to any component";
229	case 20:	return "Loss of Lockstep";
230	case 21:	return "Response not associated with a request";
231	case 22:	return "Bus parity error - must also set the A, C, or D Bits";
232	case 23:	return "Detection of a protocol error";
233	case 24:	return "Detection of a PATH_ERROR";
234	case 25:	return "Bus operation timeout";
235	case 26:	return "A read was issued to data that has been poisoned";
236	default:	return "Reserved";
237	}
238}
239EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
240
241int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
242{
243	u32 len, n;
244
245	if (!msg)
246		return 0;
247
248	n = 0;
249	len = CPER_REC_LEN;
250	if (mem->validation_bits & CPER_MEM_VALID_NODE)
251		n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
252	if (mem->validation_bits & CPER_MEM_VALID_CARD)
253		n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
254	if (mem->validation_bits & CPER_MEM_VALID_MODULE)
255		n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
256	if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
257		n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank);
258	if (mem->validation_bits & CPER_MEM_VALID_BANK)
259		n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
260	if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
261		n += scnprintf(msg + n, len - n, "bank_group:%d ",
262			       mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
263	if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
264		n += scnprintf(msg + n, len - n, "bank_address:%d ",
265			       mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
266	if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
267		n += scnprintf(msg + n, len - n, "device:%d ", mem->device);
268	if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
269		u32 row = mem->row;
270
271		row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
272		n += scnprintf(msg + n, len - n, "row:%d ", row);
273	}
274	if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
275		n += scnprintf(msg + n, len - n, "column:%d ", mem->column);
276	if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
277		n += scnprintf(msg + n, len - n, "bit_position:%d ",
278			       mem->bit_pos);
279	if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
280		n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
281			       mem->requestor_id);
282	if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
283		n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
284			       mem->responder_id);
285	if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
286		n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
287			       mem->target_id);
288	if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
289		n += scnprintf(msg + n, len - n, "chip_id:%d ",
290			       mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
291
 
292	return n;
293}
294EXPORT_SYMBOL_GPL(cper_mem_err_location);
295
296int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
297{
298	u32 len, n;
299	const char *bank = NULL, *device = NULL;
300
301	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
302		return 0;
303
304	len = CPER_REC_LEN;
 
305	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
306	if (bank && device)
307		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
308	else
309		n = snprintf(msg, len,
310			     "DIMM location: not present. DMI handle: 0x%.4x ",
311			     mem->mem_dev_handle);
312
 
313	return n;
314}
315EXPORT_SYMBOL_GPL(cper_dimm_err_location);
316
317void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
318		       struct cper_mem_err_compact *cmem)
319{
320	cmem->validation_bits = mem->validation_bits;
321	cmem->node = mem->node;
322	cmem->card = mem->card;
323	cmem->module = mem->module;
324	cmem->bank = mem->bank;
325	cmem->device = mem->device;
326	cmem->row = mem->row;
327	cmem->column = mem->column;
328	cmem->bit_pos = mem->bit_pos;
329	cmem->requestor_id = mem->requestor_id;
330	cmem->responder_id = mem->responder_id;
331	cmem->target_id = mem->target_id;
332	cmem->extended = mem->extended;
333	cmem->rank = mem->rank;
334	cmem->mem_array_handle = mem->mem_array_handle;
335	cmem->mem_dev_handle = mem->mem_dev_handle;
336}
337EXPORT_SYMBOL_GPL(cper_mem_err_pack);
338
339const char *cper_mem_err_unpack(struct trace_seq *p,
340				struct cper_mem_err_compact *cmem)
341{
342	const char *ret = trace_seq_buffer_ptr(p);
343	char rcd_decode_str[CPER_REC_LEN];
344
345	if (cper_mem_err_location(cmem, rcd_decode_str))
346		trace_seq_printf(p, "%s", rcd_decode_str);
347	if (cper_dimm_err_location(cmem, rcd_decode_str))
348		trace_seq_printf(p, "%s", rcd_decode_str);
349	trace_seq_putc(p, '\0');
350
351	return ret;
352}
353
354static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
355	int len)
356{
357	struct cper_mem_err_compact cmem;
358	char rcd_decode_str[CPER_REC_LEN];
359
360	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
361	if (len == sizeof(struct cper_sec_mem_err_old) &&
362	    (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
363		pr_err(FW_WARN "valid bits set for fields beyond structure\n");
364		return;
365	}
366	if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
367		printk("%s error_status: %s (0x%016llx)\n",
368		       pfx, cper_mem_err_status_str(mem->error_status),
369		       mem->error_status);
370	if (mem->validation_bits & CPER_MEM_VALID_PA)
371		printk("%s""physical_address: 0x%016llx\n",
372		       pfx, mem->physical_addr);
373	if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
374		printk("%s""physical_address_mask: 0x%016llx\n",
375		       pfx, mem->physical_addr_mask);
376	cper_mem_err_pack(mem, &cmem);
377	if (cper_mem_err_location(&cmem, rcd_decode_str))
378		printk("%s%s\n", pfx, rcd_decode_str);
379	if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
380		u8 etype = mem->error_type;
381		printk("%s""error_type: %d, %s\n", pfx, etype,
382		       cper_mem_err_type_str(etype));
383	}
384	if (cper_dimm_err_location(&cmem, rcd_decode_str))
385		printk("%s%s\n", pfx, rcd_decode_str);
386}
387
388static const char * const pcie_port_type_strs[] = {
389	"PCIe end point",
390	"legacy PCI end point",
391	"unknown",
392	"unknown",
393	"root port",
394	"upstream switch port",
395	"downstream switch port",
396	"PCIe to PCI/PCI-X bridge",
397	"PCI/PCI-X to PCIe bridge",
398	"root complex integrated endpoint device",
399	"root complex event collector",
400};
401
402static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
403			    const struct acpi_hest_generic_data *gdata)
404{
405	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
406		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
407		       pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
408		       pcie_port_type_strs[pcie->port_type] : "unknown");
409	if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
410		printk("%s""version: %d.%d\n", pfx,
411		       pcie->version.major, pcie->version.minor);
412	if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
413		printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
414		       pcie->command, pcie->status);
415	if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
416		const __u8 *p;
417		printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
418		       pcie->device_id.segment, pcie->device_id.bus,
419		       pcie->device_id.device, pcie->device_id.function);
420		printk("%s""slot: %d\n", pfx,
421		       pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
422		printk("%s""secondary_bus: 0x%02x\n", pfx,
423		       pcie->device_id.secondary_bus);
424		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
425		       pcie->device_id.vendor_id, pcie->device_id.device_id);
426		p = pcie->device_id.class_code;
427		printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
428	}
429	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
430		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
431		       pcie->serial_number.lower, pcie->serial_number.upper);
432	if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
433		printk(
434	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
435	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
436
437	/* Fatal errors call __ghes_panic() before AER handler prints this */
438	if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
439	    (gdata->error_severity & CPER_SEV_FATAL)) {
440		struct aer_capability_regs *aer;
441
442		aer = (struct aer_capability_regs *)pcie->aer_info;
443		printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
444		       pfx, aer->uncor_status, aer->uncor_mask);
445		printk("%saer_uncor_severity: 0x%08x\n",
446		       pfx, aer->uncor_severity);
447		printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
448		       aer->header_log.dw0, aer->header_log.dw1,
449		       aer->header_log.dw2, aer->header_log.dw3);
450	}
451}
452
453static const char * const fw_err_rec_type_strs[] = {
454	"IPF SAL Error Record",
455	"SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
456	"SOC Firmware Error Record Type2",
457};
458
459static void cper_print_fw_err(const char *pfx,
460			      struct acpi_hest_generic_data *gdata,
461			      const struct cper_sec_fw_err_rec_ref *fw_err)
462{
463	void *buf = acpi_hest_get_payload(gdata);
464	u32 offset, length = gdata->error_data_length;
465
466	printk("%s""Firmware Error Record Type: %s\n", pfx,
467	       fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
468	       fw_err_rec_type_strs[fw_err->record_type] : "unknown");
469	printk("%s""Revision: %d\n", pfx, fw_err->revision);
470
471	/* Record Type based on UEFI 2.7 */
472	if (fw_err->revision == 0) {
473		printk("%s""Record Identifier: %08llx\n", pfx,
474		       fw_err->record_identifier);
475	} else if (fw_err->revision == 2) {
476		printk("%s""Record Identifier: %pUl\n", pfx,
477		       &fw_err->record_identifier_guid);
478	}
479
480	/*
481	 * The FW error record may contain trailing data beyond the
482	 * structure defined by the specification. As the fields
483	 * defined (and hence the offset of any trailing data) vary
484	 * with the revision, set the offset to account for this
485	 * variation.
486	 */
487	if (fw_err->revision == 0) {
488		/* record_identifier_guid not defined */
489		offset = offsetof(struct cper_sec_fw_err_rec_ref,
490				  record_identifier_guid);
491	} else if (fw_err->revision == 1) {
492		/* record_identifier not defined */
493		offset = offsetof(struct cper_sec_fw_err_rec_ref,
494				  record_identifier);
495	} else {
496		offset = sizeof(*fw_err);
497	}
498
499	buf += offset;
500	length -= offset;
501
502	print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
503}
504
505static void cper_print_tstamp(const char *pfx,
506				   struct acpi_hest_generic_data_v300 *gdata)
507{
508	__u8 hour, min, sec, day, mon, year, century, *timestamp;
509
510	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
511		timestamp = (__u8 *)&(gdata->time_stamp);
512		sec       = bcd2bin(timestamp[0]);
513		min       = bcd2bin(timestamp[1]);
514		hour      = bcd2bin(timestamp[2]);
515		day       = bcd2bin(timestamp[4]);
516		mon       = bcd2bin(timestamp[5]);
517		year      = bcd2bin(timestamp[6]);
518		century   = bcd2bin(timestamp[7]);
519
520		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
521		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),
522		       century, year, mon, day, hour, min, sec);
523	}
524}
525
526static void
527cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
528			   int sec_no)
529{
530	guid_t *sec_type = (guid_t *)gdata->section_type;
531	__u16 severity;
532	char newpfx[64];
533
534	if (acpi_hest_get_version(gdata) >= 3)
535		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
536
537	severity = gdata->error_severity;
538	printk("%s""Error %d, type: %s\n", pfx, sec_no,
539	       cper_severity_str(severity));
540	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
541		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
542	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
543		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
544
545	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
546	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
547		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
548
549		printk("%s""section_type: general processor error\n", newpfx);
550		if (gdata->error_data_length >= sizeof(*proc_err))
551			cper_print_proc_generic(newpfx, proc_err);
552		else
553			goto err_section_too_small;
554	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
555		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
556
557		printk("%s""section_type: memory error\n", newpfx);
558		if (gdata->error_data_length >=
559		    sizeof(struct cper_sec_mem_err_old))
560			cper_print_mem(newpfx, mem_err,
561				       gdata->error_data_length);
562		else
563			goto err_section_too_small;
564	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
565		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
566
567		printk("%s""section_type: PCIe error\n", newpfx);
568		if (gdata->error_data_length >= sizeof(*pcie))
569			cper_print_pcie(newpfx, pcie, gdata);
570		else
571			goto err_section_too_small;
572#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
573	} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
574		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
575
576		printk("%ssection_type: ARM processor error\n", newpfx);
577		if (gdata->error_data_length >= sizeof(*arm_err))
578			cper_print_proc_arm(newpfx, arm_err);
579		else
580			goto err_section_too_small;
581#endif
582#if defined(CONFIG_UEFI_CPER_X86)
583	} else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
584		struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
585
586		printk("%ssection_type: IA32/X64 processor error\n", newpfx);
587		if (gdata->error_data_length >= sizeof(*ia_err))
588			cper_print_proc_ia(newpfx, ia_err);
589		else
590			goto err_section_too_small;
591#endif
592	} else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
593		struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
594
595		printk("%ssection_type: Firmware Error Record Reference\n",
596		       newpfx);
597		/* The minimal FW Error Record contains 16 bytes */
598		if (gdata->error_data_length >= SZ_16)
599			cper_print_fw_err(newpfx, gdata, fw_err);
600		else
601			goto err_section_too_small;
602	} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
603		struct cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
604
605		printk("%ssection_type: CXL Protocol Error\n", newpfx);
606		if (gdata->error_data_length >= sizeof(*prot_err))
607			cper_print_prot_err(newpfx, prot_err);
608		else
609			goto err_section_too_small;
610	} else {
611		const void *err = acpi_hest_get_payload(gdata);
612
613		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
614		printk("%ssection length: %#x\n", newpfx,
615		       gdata->error_data_length);
616		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
617			       gdata->error_data_length, true);
618	}
619
620	return;
621
622err_section_too_small:
623	pr_err(FW_WARN "error section length is too small\n");
624}
625
626void cper_estatus_print(const char *pfx,
627			const struct acpi_hest_generic_status *estatus)
628{
629	struct acpi_hest_generic_data *gdata;
630	int sec_no = 0;
631	char newpfx[64];
632	__u16 severity;
633
634	severity = estatus->error_severity;
635	if (severity == CPER_SEV_CORRECTED)
636		printk("%s%s\n", pfx,
637		       "It has been corrected by h/w "
638		       "and requires no further action");
639	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
640	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
641
642	apei_estatus_for_each_section(estatus, gdata) {
643		cper_estatus_print_section(newpfx, gdata, sec_no);
644		sec_no++;
645	}
646}
647EXPORT_SYMBOL_GPL(cper_estatus_print);
648
649int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
650{
651	if (estatus->data_length &&
652	    estatus->data_length < sizeof(struct acpi_hest_generic_data))
653		return -EINVAL;
654	if (estatus->raw_data_length &&
655	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
656		return -EINVAL;
657
658	return 0;
659}
660EXPORT_SYMBOL_GPL(cper_estatus_check_header);
661
662int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
663{
664	struct acpi_hest_generic_data *gdata;
665	unsigned int data_len, record_size;
666	int rc;
667
668	rc = cper_estatus_check_header(estatus);
669	if (rc)
670		return rc;
671
672	data_len = estatus->data_length;
673
674	apei_estatus_for_each_section(estatus, gdata) {
675		if (acpi_hest_get_size(gdata) > data_len)
676			return -EINVAL;
677
678		record_size = acpi_hest_get_record_size(gdata);
679		if (record_size > data_len)
680			return -EINVAL;
681
682		data_len -= record_size;
683	}
684	if (data_len)
685		return -EINVAL;
686
687	return 0;
688}
689EXPORT_SYMBOL_GPL(cper_estatus_check);
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * UEFI Common Platform Error Record (CPER) support
  4 *
  5 * Copyright (C) 2010, Intel Corp.
  6 *	Author: Huang Ying <ying.huang@intel.com>
  7 *
  8 * CPER is the format used to describe platform hardware error by
  9 * various tables, such as ERST, BERT and HEST etc.
 10 *
 11 * For more information about CPER, please refer to Appendix N of UEFI
 12 * Specification version 2.4.
 13 */
 14
 15#include <linux/kernel.h>
 16#include <linux/module.h>
 17#include <linux/time.h>
 18#include <linux/cper.h>
 19#include <linux/dmi.h>
 20#include <linux/acpi.h>
 21#include <linux/pci.h>
 22#include <linux/aer.h>
 23#include <linux/printk.h>
 24#include <linux/bcd.h>
 25#include <acpi/ghes.h>
 26#include <ras/ras_event.h>
 27
 28static char rcd_decode_str[CPER_REC_LEN];
 29
 30/*
 31 * CPER record ID need to be unique even after reboot, because record
 32 * ID is used as index for ERST storage, while CPER records from
 33 * multiple boot may co-exist in ERST.
 34 */
 35u64 cper_next_record_id(void)
 36{
 37	static atomic64_t seq;
 38
 39	if (!atomic64_read(&seq)) {
 40		time64_t time = ktime_get_real_seconds();
 41
 42		/*
 43		 * This code is unlikely to still be needed in year 2106,
 44		 * but just in case, let's use a few more bits for timestamps
 45		 * after y2038 to be sure they keep increasing monotonically
 46		 * for the next few hundred years...
 47		 */
 48		if (time < 0x80000000)
 49			atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
 50		else
 51			atomic64_set(&seq, 0x8000000000000000ull |
 52					   ktime_get_real_seconds() << 24);
 53	}
 54
 55	return atomic64_inc_return(&seq);
 56}
 57EXPORT_SYMBOL_GPL(cper_next_record_id);
 58
 59static const char * const severity_strs[] = {
 60	"recoverable",
 61	"fatal",
 62	"corrected",
 63	"info",
 64};
 65
 66const char *cper_severity_str(unsigned int severity)
 67{
 68	return severity < ARRAY_SIZE(severity_strs) ?
 69		severity_strs[severity] : "unknown";
 70}
 71EXPORT_SYMBOL_GPL(cper_severity_str);
 72
 73/*
 74 * cper_print_bits - print strings for set bits
 75 * @pfx: prefix for each line, including log level and prefix string
 76 * @bits: bit mask
 77 * @strs: string array, indexed by bit position
 78 * @strs_size: size of the string array: @strs
 79 *
 80 * For each set bit in @bits, print the corresponding string in @strs.
 81 * If the output length is longer than 80, multiple line will be
 82 * printed, with @pfx is printed at the beginning of each line.
 83 */
 84void cper_print_bits(const char *pfx, unsigned int bits,
 85		     const char * const strs[], unsigned int strs_size)
 86{
 87	int i, len = 0;
 88	const char *str;
 89	char buf[84];
 90
 91	for (i = 0; i < strs_size; i++) {
 92		if (!(bits & (1U << i)))
 93			continue;
 94		str = strs[i];
 95		if (!str)
 96			continue;
 97		if (len && len + strlen(str) + 2 > 80) {
 98			printk("%s\n", buf);
 99			len = 0;
100		}
101		if (!len)
102			len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
103		else
104			len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
105	}
106	if (len)
107		printk("%s\n", buf);
108}
109
110static const char * const proc_type_strs[] = {
111	"IA32/X64",
112	"IA64",
113	"ARM",
114};
115
116static const char * const proc_isa_strs[] = {
117	"IA32",
118	"IA64",
119	"X64",
120	"ARM A32/T32",
121	"ARM A64",
122};
123
124const char * const cper_proc_error_type_strs[] = {
125	"cache error",
126	"TLB error",
127	"bus error",
128	"micro-architectural error",
129};
130
131static const char * const proc_op_strs[] = {
132	"unknown or generic",
133	"data read",
134	"data write",
135	"instruction execution",
136};
137
138static const char * const proc_flag_strs[] = {
139	"restartable",
140	"precise IP",
141	"overflow",
142	"corrected",
143};
144
145static void cper_print_proc_generic(const char *pfx,
146				    const struct cper_sec_proc_generic *proc)
147{
148	if (proc->validation_bits & CPER_PROC_VALID_TYPE)
149		printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
150		       proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
151		       proc_type_strs[proc->proc_type] : "unknown");
152	if (proc->validation_bits & CPER_PROC_VALID_ISA)
153		printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
154		       proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
155		       proc_isa_strs[proc->proc_isa] : "unknown");
156	if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
157		printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
158		cper_print_bits(pfx, proc->proc_error_type,
159				cper_proc_error_type_strs,
160				ARRAY_SIZE(cper_proc_error_type_strs));
161	}
162	if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
163		printk("%s""operation: %d, %s\n", pfx, proc->operation,
164		       proc->operation < ARRAY_SIZE(proc_op_strs) ?
165		       proc_op_strs[proc->operation] : "unknown");
166	if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
167		printk("%s""flags: 0x%02x\n", pfx, proc->flags);
168		cper_print_bits(pfx, proc->flags, proc_flag_strs,
169				ARRAY_SIZE(proc_flag_strs));
170	}
171	if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
172		printk("%s""level: %d\n", pfx, proc->level);
173	if (proc->validation_bits & CPER_PROC_VALID_VERSION)
174		printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
175	if (proc->validation_bits & CPER_PROC_VALID_ID)
176		printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
177	if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
178		printk("%s""target_address: 0x%016llx\n",
179		       pfx, proc->target_addr);
180	if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
181		printk("%s""requestor_id: 0x%016llx\n",
182		       pfx, proc->requestor_id);
183	if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
184		printk("%s""responder_id: 0x%016llx\n",
185		       pfx, proc->responder_id);
186	if (proc->validation_bits & CPER_PROC_VALID_IP)
187		printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
188}
189
190static const char * const mem_err_type_strs[] = {
191	"unknown",
192	"no error",
193	"single-bit ECC",
194	"multi-bit ECC",
195	"single-symbol chipkill ECC",
196	"multi-symbol chipkill ECC",
197	"master abort",
198	"target abort",
199	"parity error",
200	"watchdog timeout",
201	"invalid address",
202	"mirror Broken",
203	"memory sparing",
204	"scrub corrected error",
205	"scrub uncorrected error",
206	"physical memory map-out event",
207};
208
209const char *cper_mem_err_type_str(unsigned int etype)
210{
211	return etype < ARRAY_SIZE(mem_err_type_strs) ?
212		mem_err_type_strs[etype] : "unknown";
213}
214EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
215
216static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217{
218	u32 len, n;
219
220	if (!msg)
221		return 0;
222
223	n = 0;
224	len = CPER_REC_LEN - 1;
225	if (mem->validation_bits & CPER_MEM_VALID_NODE)
226		n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
227	if (mem->validation_bits & CPER_MEM_VALID_CARD)
228		n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
229	if (mem->validation_bits & CPER_MEM_VALID_MODULE)
230		n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
231	if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
232		n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
233	if (mem->validation_bits & CPER_MEM_VALID_BANK)
234		n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
 
 
 
 
 
 
235	if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
236		n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
237	if (mem->validation_bits & CPER_MEM_VALID_ROW)
238		n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
 
 
 
 
239	if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
240		n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
241	if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
242		n += scnprintf(msg + n, len - n, "bit_position: %d ",
243			       mem->bit_pos);
244	if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
245		n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
246			       mem->requestor_id);
247	if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
248		n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
249			       mem->responder_id);
250	if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
251		scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
252			  mem->target_id);
 
 
 
253
254	msg[n] = '\0';
255	return n;
256}
 
257
258static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
259{
260	u32 len, n;
261	const char *bank = NULL, *device = NULL;
262
263	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
264		return 0;
265
266	n = 0;
267	len = CPER_REC_LEN - 1;
268	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
269	if (bank && device)
270		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
271	else
272		n = snprintf(msg, len,
273			     "DIMM location: not present. DMI handle: 0x%.4x ",
274			     mem->mem_dev_handle);
275
276	msg[n] = '\0';
277	return n;
278}
 
279
280void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
281		       struct cper_mem_err_compact *cmem)
282{
283	cmem->validation_bits = mem->validation_bits;
284	cmem->node = mem->node;
285	cmem->card = mem->card;
286	cmem->module = mem->module;
287	cmem->bank = mem->bank;
288	cmem->device = mem->device;
289	cmem->row = mem->row;
290	cmem->column = mem->column;
291	cmem->bit_pos = mem->bit_pos;
292	cmem->requestor_id = mem->requestor_id;
293	cmem->responder_id = mem->responder_id;
294	cmem->target_id = mem->target_id;
 
295	cmem->rank = mem->rank;
296	cmem->mem_array_handle = mem->mem_array_handle;
297	cmem->mem_dev_handle = mem->mem_dev_handle;
298}
 
299
300const char *cper_mem_err_unpack(struct trace_seq *p,
301				struct cper_mem_err_compact *cmem)
302{
303	const char *ret = trace_seq_buffer_ptr(p);
 
304
305	if (cper_mem_err_location(cmem, rcd_decode_str))
306		trace_seq_printf(p, "%s", rcd_decode_str);
307	if (cper_dimm_err_location(cmem, rcd_decode_str))
308		trace_seq_printf(p, "%s", rcd_decode_str);
309	trace_seq_putc(p, '\0');
310
311	return ret;
312}
313
314static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
315	int len)
316{
317	struct cper_mem_err_compact cmem;
 
318
319	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
320	if (len == sizeof(struct cper_sec_mem_err_old) &&
321	    (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
322		pr_err(FW_WARN "valid bits set for fields beyond structure\n");
323		return;
324	}
325	if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
326		printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
 
 
327	if (mem->validation_bits & CPER_MEM_VALID_PA)
328		printk("%s""physical_address: 0x%016llx\n",
329		       pfx, mem->physical_addr);
330	if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
331		printk("%s""physical_address_mask: 0x%016llx\n",
332		       pfx, mem->physical_addr_mask);
333	cper_mem_err_pack(mem, &cmem);
334	if (cper_mem_err_location(&cmem, rcd_decode_str))
335		printk("%s%s\n", pfx, rcd_decode_str);
336	if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
337		u8 etype = mem->error_type;
338		printk("%s""error_type: %d, %s\n", pfx, etype,
339		       cper_mem_err_type_str(etype));
340	}
341	if (cper_dimm_err_location(&cmem, rcd_decode_str))
342		printk("%s%s\n", pfx, rcd_decode_str);
343}
344
345static const char * const pcie_port_type_strs[] = {
346	"PCIe end point",
347	"legacy PCI end point",
348	"unknown",
349	"unknown",
350	"root port",
351	"upstream switch port",
352	"downstream switch port",
353	"PCIe to PCI/PCI-X bridge",
354	"PCI/PCI-X to PCIe bridge",
355	"root complex integrated endpoint device",
356	"root complex event collector",
357};
358
359static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
360			    const struct acpi_hest_generic_data *gdata)
361{
362	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
363		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
364		       pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
365		       pcie_port_type_strs[pcie->port_type] : "unknown");
366	if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
367		printk("%s""version: %d.%d\n", pfx,
368		       pcie->version.major, pcie->version.minor);
369	if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
370		printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
371		       pcie->command, pcie->status);
372	if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
373		const __u8 *p;
374		printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
375		       pcie->device_id.segment, pcie->device_id.bus,
376		       pcie->device_id.device, pcie->device_id.function);
377		printk("%s""slot: %d\n", pfx,
378		       pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
379		printk("%s""secondary_bus: 0x%02x\n", pfx,
380		       pcie->device_id.secondary_bus);
381		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
382		       pcie->device_id.vendor_id, pcie->device_id.device_id);
383		p = pcie->device_id.class_code;
384		printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
385	}
386	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
387		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
388		       pcie->serial_number.lower, pcie->serial_number.upper);
389	if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
390		printk(
391	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
392	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
393
394	/* Fatal errors call __ghes_panic() before AER handler prints this */
395	if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
396	    (gdata->error_severity & CPER_SEV_FATAL)) {
397		struct aer_capability_regs *aer;
398
399		aer = (struct aer_capability_regs *)pcie->aer_info;
400		printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
401		       pfx, aer->uncor_status, aer->uncor_mask);
402		printk("%saer_uncor_severity: 0x%08x\n",
403		       pfx, aer->uncor_severity);
404		printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
405		       aer->header_log.dw0, aer->header_log.dw1,
406		       aer->header_log.dw2, aer->header_log.dw3);
407	}
408}
409
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410static void cper_print_tstamp(const char *pfx,
411				   struct acpi_hest_generic_data_v300 *gdata)
412{
413	__u8 hour, min, sec, day, mon, year, century, *timestamp;
414
415	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
416		timestamp = (__u8 *)&(gdata->time_stamp);
417		sec       = bcd2bin(timestamp[0]);
418		min       = bcd2bin(timestamp[1]);
419		hour      = bcd2bin(timestamp[2]);
420		day       = bcd2bin(timestamp[4]);
421		mon       = bcd2bin(timestamp[5]);
422		year      = bcd2bin(timestamp[6]);
423		century   = bcd2bin(timestamp[7]);
424
425		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
426		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),
427		       century, year, mon, day, hour, min, sec);
428	}
429}
430
431static void
432cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
433			   int sec_no)
434{
435	guid_t *sec_type = (guid_t *)gdata->section_type;
436	__u16 severity;
437	char newpfx[64];
438
439	if (acpi_hest_get_version(gdata) >= 3)
440		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
441
442	severity = gdata->error_severity;
443	printk("%s""Error %d, type: %s\n", pfx, sec_no,
444	       cper_severity_str(severity));
445	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
446		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
447	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
448		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
449
450	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
451	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
452		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
453
454		printk("%s""section_type: general processor error\n", newpfx);
455		if (gdata->error_data_length >= sizeof(*proc_err))
456			cper_print_proc_generic(newpfx, proc_err);
457		else
458			goto err_section_too_small;
459	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
460		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
461
462		printk("%s""section_type: memory error\n", newpfx);
463		if (gdata->error_data_length >=
464		    sizeof(struct cper_sec_mem_err_old))
465			cper_print_mem(newpfx, mem_err,
466				       gdata->error_data_length);
467		else
468			goto err_section_too_small;
469	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
470		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
471
472		printk("%s""section_type: PCIe error\n", newpfx);
473		if (gdata->error_data_length >= sizeof(*pcie))
474			cper_print_pcie(newpfx, pcie, gdata);
475		else
476			goto err_section_too_small;
477#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
478	} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
479		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
480
481		printk("%ssection_type: ARM processor error\n", newpfx);
482		if (gdata->error_data_length >= sizeof(*arm_err))
483			cper_print_proc_arm(newpfx, arm_err);
484		else
485			goto err_section_too_small;
486#endif
487#if defined(CONFIG_UEFI_CPER_X86)
488	} else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
489		struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
490
491		printk("%ssection_type: IA32/X64 processor error\n", newpfx);
492		if (gdata->error_data_length >= sizeof(*ia_err))
493			cper_print_proc_ia(newpfx, ia_err);
494		else
495			goto err_section_too_small;
496#endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497	} else {
498		const void *err = acpi_hest_get_payload(gdata);
499
500		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
501		printk("%ssection length: %#x\n", newpfx,
502		       gdata->error_data_length);
503		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
504			       gdata->error_data_length, true);
505	}
506
507	return;
508
509err_section_too_small:
510	pr_err(FW_WARN "error section length is too small\n");
511}
512
513void cper_estatus_print(const char *pfx,
514			const struct acpi_hest_generic_status *estatus)
515{
516	struct acpi_hest_generic_data *gdata;
517	int sec_no = 0;
518	char newpfx[64];
519	__u16 severity;
520
521	severity = estatus->error_severity;
522	if (severity == CPER_SEV_CORRECTED)
523		printk("%s%s\n", pfx,
524		       "It has been corrected by h/w "
525		       "and requires no further action");
526	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
527	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
528
529	apei_estatus_for_each_section(estatus, gdata) {
530		cper_estatus_print_section(newpfx, gdata, sec_no);
531		sec_no++;
532	}
533}
534EXPORT_SYMBOL_GPL(cper_estatus_print);
535
536int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
537{
538	if (estatus->data_length &&
539	    estatus->data_length < sizeof(struct acpi_hest_generic_data))
540		return -EINVAL;
541	if (estatus->raw_data_length &&
542	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
543		return -EINVAL;
544
545	return 0;
546}
547EXPORT_SYMBOL_GPL(cper_estatus_check_header);
548
549int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
550{
551	struct acpi_hest_generic_data *gdata;
552	unsigned int data_len, record_size;
553	int rc;
554
555	rc = cper_estatus_check_header(estatus);
556	if (rc)
557		return rc;
558
559	data_len = estatus->data_length;
560
561	apei_estatus_for_each_section(estatus, gdata) {
562		if (sizeof(struct acpi_hest_generic_data) > data_len)
563			return -EINVAL;
564
565		record_size = acpi_hest_get_record_size(gdata);
566		if (record_size > data_len)
567			return -EINVAL;
568
569		data_len -= record_size;
570	}
571	if (data_len)
572		return -EINVAL;
573
574	return 0;
575}
576EXPORT_SYMBOL_GPL(cper_estatus_check);