brintos

brintos / linux-shallow public Read only

0
0
Text · 22.6 KiB · b69e68e Raw
714 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * UEFI Common Platform Error Record (CPER) support4 *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 by9 * various tables, such as ERST, BERT and HEST etc.10 *11 * For more information about CPER, please refer to Appendix N of UEFI12 * 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 record31 * ID is used as index for ERST storage, while CPER records from32 * 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 timestamps44		 * after y2038 to be sure they keep increasing monotonically45		 * for the next few hundred years...46		 */47		if (time < 0x80000000)48			atomic64_set(&seq, (ktime_get_real_seconds()) << 32);49		else50			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 bits74 * @pfx: prefix for each line, including log level and prefix string75 * @bits: bit mask76 * @strs: string array, indexed by bit position77 * @strs_size: size of the string array: @strs78 *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 be81 * 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		else103			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	else309		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	/*438	 * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time).439	 *440	 * Fatal errors call __ghes_panic() before AER handler prints this.441	 */442	if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {443		struct aer_capability_regs *aer;444 445		aer = (struct aer_capability_regs *)pcie->aer_info;446		printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n",447		       pfx, aer->cor_status, aer->cor_mask);448		printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",449		       pfx, aer->uncor_status, aer->uncor_mask);450		printk("%saer_uncor_severity: 0x%08x\n",451		       pfx, aer->uncor_severity);452		printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,453		       aer->header_log.dw[0], aer->header_log.dw[1],454		       aer->header_log.dw[2], aer->header_log.dw[3]);455	}456}457 458static const char * const fw_err_rec_type_strs[] = {459	"IPF SAL Error Record",460	"SOC Firmware Error Record Type1 (Legacy CrashLog Support)",461	"SOC Firmware Error Record Type2",462};463 464static void cper_print_fw_err(const char *pfx,465			      struct acpi_hest_generic_data *gdata,466			      const struct cper_sec_fw_err_rec_ref *fw_err)467{468	void *buf = acpi_hest_get_payload(gdata);469	u32 offset, length = gdata->error_data_length;470 471	printk("%s""Firmware Error Record Type: %s\n", pfx,472	       fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?473	       fw_err_rec_type_strs[fw_err->record_type] : "unknown");474	printk("%s""Revision: %d\n", pfx, fw_err->revision);475 476	/* Record Type based on UEFI 2.7 */477	if (fw_err->revision == 0) {478		printk("%s""Record Identifier: %08llx\n", pfx,479		       fw_err->record_identifier);480	} else if (fw_err->revision == 2) {481		printk("%s""Record Identifier: %pUl\n", pfx,482		       &fw_err->record_identifier_guid);483	}484 485	/*486	 * The FW error record may contain trailing data beyond the487	 * structure defined by the specification. As the fields488	 * defined (and hence the offset of any trailing data) vary489	 * with the revision, set the offset to account for this490	 * variation.491	 */492	if (fw_err->revision == 0) {493		/* record_identifier_guid not defined */494		offset = offsetof(struct cper_sec_fw_err_rec_ref,495				  record_identifier_guid);496	} else if (fw_err->revision == 1) {497		/* record_identifier not defined */498		offset = offsetof(struct cper_sec_fw_err_rec_ref,499				  record_identifier);500	} else {501		offset = sizeof(*fw_err);502	}503 504	buf += offset;505	length -= offset;506 507	print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);508}509 510static void cper_print_tstamp(const char *pfx,511				   struct acpi_hest_generic_data_v300 *gdata)512{513	__u8 hour, min, sec, day, mon, year, century, *timestamp;514 515	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {516		timestamp = (__u8 *)&(gdata->time_stamp);517		sec       = bcd2bin(timestamp[0]);518		min       = bcd2bin(timestamp[1]);519		hour      = bcd2bin(timestamp[2]);520		day       = bcd2bin(timestamp[4]);521		mon       = bcd2bin(timestamp[5]);522		year      = bcd2bin(timestamp[6]);523		century   = bcd2bin(timestamp[7]);524 525		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,526		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),527		       century, year, mon, day, hour, min, sec);528	}529}530 531struct ignore_section {532	guid_t guid;533	const char *name;534};535 536static const struct ignore_section ignore_sections[] = {537	{ .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" },538	{ .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" },539	{ .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" },540};541 542static void543cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,544			   int sec_no)545{546	guid_t *sec_type = (guid_t *)gdata->section_type;547	__u16 severity;548	char newpfx[64];549 550	if (acpi_hest_get_version(gdata) >= 3)551		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);552 553	severity = gdata->error_severity;554	printk("%s""Error %d, type: %s\n", pfx, sec_no,555	       cper_severity_str(severity));556	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)557		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);558	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)559		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);560 561	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);562 563	for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) {564		if (guid_equal(sec_type, &ignore_sections[i].guid)) {565			printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name);566			return;567		}568	}569 570	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {571		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);572 573		printk("%s""section_type: general processor error\n", newpfx);574		if (gdata->error_data_length >= sizeof(*proc_err))575			cper_print_proc_generic(newpfx, proc_err);576		else577			goto err_section_too_small;578	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {579		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);580 581		printk("%s""section_type: memory error\n", newpfx);582		if (gdata->error_data_length >=583		    sizeof(struct cper_sec_mem_err_old))584			cper_print_mem(newpfx, mem_err,585				       gdata->error_data_length);586		else587			goto err_section_too_small;588	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {589		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);590 591		printk("%s""section_type: PCIe error\n", newpfx);592		if (gdata->error_data_length >= sizeof(*pcie))593			cper_print_pcie(newpfx, pcie, gdata);594		else595			goto err_section_too_small;596#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)597	} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {598		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);599 600		printk("%ssection_type: ARM processor error\n", newpfx);601		if (gdata->error_data_length >= sizeof(*arm_err))602			cper_print_proc_arm(newpfx, arm_err);603		else604			goto err_section_too_small;605#endif606#if defined(CONFIG_UEFI_CPER_X86)607	} else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {608		struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);609 610		printk("%ssection_type: IA32/X64 processor error\n", newpfx);611		if (gdata->error_data_length >= sizeof(*ia_err))612			cper_print_proc_ia(newpfx, ia_err);613		else614			goto err_section_too_small;615#endif616	} else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {617		struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);618 619		printk("%ssection_type: Firmware Error Record Reference\n",620		       newpfx);621		/* The minimal FW Error Record contains 16 bytes */622		if (gdata->error_data_length >= SZ_16)623			cper_print_fw_err(newpfx, gdata, fw_err);624		else625			goto err_section_too_small;626	} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {627		struct cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);628 629		printk("%ssection_type: CXL Protocol Error\n", newpfx);630		if (gdata->error_data_length >= sizeof(*prot_err))631			cper_print_prot_err(newpfx, prot_err);632		else633			goto err_section_too_small;634	} else {635		const void *err = acpi_hest_get_payload(gdata);636 637		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);638		printk("%ssection length: %#x\n", newpfx,639		       gdata->error_data_length);640		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,641			       gdata->error_data_length, true);642	}643 644	return;645 646err_section_too_small:647	pr_err(FW_WARN "error section length is too small\n");648}649 650void cper_estatus_print(const char *pfx,651			const struct acpi_hest_generic_status *estatus)652{653	struct acpi_hest_generic_data *gdata;654	int sec_no = 0;655	char newpfx[64];656	__u16 severity;657 658	severity = estatus->error_severity;659	if (severity == CPER_SEV_CORRECTED)660		printk("%s%s\n", pfx,661		       "It has been corrected by h/w "662		       "and requires no further action");663	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));664	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);665 666	apei_estatus_for_each_section(estatus, gdata) {667		cper_estatus_print_section(newpfx, gdata, sec_no);668		sec_no++;669	}670}671EXPORT_SYMBOL_GPL(cper_estatus_print);672 673int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)674{675	if (estatus->data_length &&676	    estatus->data_length < sizeof(struct acpi_hest_generic_data))677		return -EINVAL;678	if (estatus->raw_data_length &&679	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)680		return -EINVAL;681 682	return 0;683}684EXPORT_SYMBOL_GPL(cper_estatus_check_header);685 686int cper_estatus_check(const struct acpi_hest_generic_status *estatus)687{688	struct acpi_hest_generic_data *gdata;689	unsigned int data_len, record_size;690	int rc;691 692	rc = cper_estatus_check_header(estatus);693	if (rc)694		return rc;695 696	data_len = estatus->data_length;697 698	apei_estatus_for_each_section(estatus, gdata) {699		if (acpi_hest_get_size(gdata) > data_len)700			return -EINVAL;701 702		record_size = acpi_hest_get_record_size(gdata);703		if (record_size > data_len)704			return -EINVAL;705 706		data_len -= record_size;707	}708	if (data_len)709		return -EINVAL;710 711	return 0;712}713EXPORT_SYMBOL_GPL(cper_estatus_check);714