cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cper.c (21992B)


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