• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
cper_next_record_id(void)33 u64 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 }
55 EXPORT_SYMBOL_GPL(cper_next_record_id);
56 
57 static const char * const severity_strs[] = {
58 	"recoverable",
59 	"fatal",
60 	"corrected",
61 	"info",
62 };
63 
cper_severity_str(unsigned int severity)64 const char *cper_severity_str(unsigned int severity)
65 {
66 	return severity < ARRAY_SIZE(severity_strs) ?
67 		severity_strs[severity] : "unknown";
68 }
69 EXPORT_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  */
cper_print_bits(const char * pfx,unsigned int bits,const char * const strs[],unsigned int strs_size)82 void 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 
108 static const char * const proc_type_strs[] = {
109 	"IA32/X64",
110 	"IA64",
111 	"ARM",
112 };
113 
114 static const char * const proc_isa_strs[] = {
115 	"IA32",
116 	"IA64",
117 	"X64",
118 	"ARM A32/T32",
119 	"ARM A64",
120 };
121 
122 const char * const cper_proc_error_type_strs[] = {
123 	"cache error",
124 	"TLB error",
125 	"bus error",
126 	"micro-architectural error",
127 };
128 
129 static const char * const proc_op_strs[] = {
130 	"unknown or generic",
131 	"data read",
132 	"data write",
133 	"instruction execution",
134 };
135 
136 static const char * const proc_flag_strs[] = {
137 	"restartable",
138 	"precise IP",
139 	"overflow",
140 	"corrected",
141 };
142 
cper_print_proc_generic(const char * pfx,const struct cper_sec_proc_generic * proc)143 static 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 
188 static 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 
cper_mem_err_type_str(unsigned int etype)207 const 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 }
212 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
213 
cper_mem_err_location(struct cper_mem_err_compact * mem,char * msg)214 static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
215 {
216 	u32 len, n;
217 
218 	if (!msg)
219 		return 0;
220 
221 	n = 0;
222 	len = CPER_REC_LEN - 1;
223 	if (mem->validation_bits & CPER_MEM_VALID_NODE)
224 		n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
225 	if (mem->validation_bits & CPER_MEM_VALID_CARD)
226 		n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
227 	if (mem->validation_bits & CPER_MEM_VALID_MODULE)
228 		n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
229 	if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
230 		n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
231 	if (mem->validation_bits & CPER_MEM_VALID_BANK)
232 		n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
233 	if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
234 		n += scnprintf(msg + n, len - n, "bank_group: %d ",
235 			       mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
236 	if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
237 		n += scnprintf(msg + n, len - n, "bank_address: %d ",
238 			       mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
239 	if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
240 		n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
241 	if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
242 		u32 row = mem->row;
243 
244 		row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
245 		n += scnprintf(msg + n, len - n, "row: %d ", row);
246 	}
247 	if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
248 		n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
249 	if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
250 		n += scnprintf(msg + n, len - n, "bit_position: %d ",
251 			       mem->bit_pos);
252 	if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
253 		n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
254 			       mem->requestor_id);
255 	if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
256 		n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
257 			       mem->responder_id);
258 	if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
259 		scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
260 			  mem->target_id);
261 	if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
262 		scnprintf(msg + n, len - n, "chip_id: %d ",
263 			  mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
264 
265 	msg[n] = '\0';
266 	return n;
267 }
268 
cper_dimm_err_location(struct cper_mem_err_compact * mem,char * msg)269 static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
270 {
271 	u32 len, n;
272 	const char *bank = NULL, *device = NULL;
273 
274 	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
275 		return 0;
276 
277 	len = CPER_REC_LEN;
278 	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
279 	if (bank && device)
280 		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
281 	else
282 		n = snprintf(msg, len,
283 			     "DIMM location: not present. DMI handle: 0x%.4x ",
284 			     mem->mem_dev_handle);
285 
286 	return n;
287 }
288 
cper_mem_err_pack(const struct cper_sec_mem_err * mem,struct cper_mem_err_compact * cmem)289 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
290 		       struct cper_mem_err_compact *cmem)
291 {
292 	cmem->validation_bits = mem->validation_bits;
293 	cmem->node = mem->node;
294 	cmem->card = mem->card;
295 	cmem->module = mem->module;
296 	cmem->bank = mem->bank;
297 	cmem->device = mem->device;
298 	cmem->row = mem->row;
299 	cmem->column = mem->column;
300 	cmem->bit_pos = mem->bit_pos;
301 	cmem->requestor_id = mem->requestor_id;
302 	cmem->responder_id = mem->responder_id;
303 	cmem->target_id = mem->target_id;
304 	cmem->extended = mem->extended;
305 	cmem->rank = mem->rank;
306 	cmem->mem_array_handle = mem->mem_array_handle;
307 	cmem->mem_dev_handle = mem->mem_dev_handle;
308 }
309 
cper_mem_err_unpack(struct trace_seq * p,struct cper_mem_err_compact * cmem)310 const char *cper_mem_err_unpack(struct trace_seq *p,
311 				struct cper_mem_err_compact *cmem)
312 {
313 	const char *ret = trace_seq_buffer_ptr(p);
314 	char rcd_decode_str[CPER_REC_LEN];
315 
316 	if (cper_mem_err_location(cmem, rcd_decode_str))
317 		trace_seq_printf(p, "%s", rcd_decode_str);
318 	if (cper_dimm_err_location(cmem, rcd_decode_str))
319 		trace_seq_printf(p, "%s", rcd_decode_str);
320 	trace_seq_putc(p, '\0');
321 
322 	return ret;
323 }
324 
cper_print_mem(const char * pfx,const struct cper_sec_mem_err * mem,int len)325 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
326 	int len)
327 {
328 	struct cper_mem_err_compact cmem;
329 	char rcd_decode_str[CPER_REC_LEN];
330 
331 	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
332 	if (len == sizeof(struct cper_sec_mem_err_old) &&
333 	    (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
334 		pr_err(FW_WARN "valid bits set for fields beyond structure\n");
335 		return;
336 	}
337 	if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
338 		printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
339 	if (mem->validation_bits & CPER_MEM_VALID_PA)
340 		printk("%s""physical_address: 0x%016llx\n",
341 		       pfx, mem->physical_addr);
342 	if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
343 		printk("%s""physical_address_mask: 0x%016llx\n",
344 		       pfx, mem->physical_addr_mask);
345 	cper_mem_err_pack(mem, &cmem);
346 	if (cper_mem_err_location(&cmem, rcd_decode_str))
347 		printk("%s%s\n", pfx, rcd_decode_str);
348 	if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
349 		u8 etype = mem->error_type;
350 		printk("%s""error_type: %d, %s\n", pfx, etype,
351 		       cper_mem_err_type_str(etype));
352 	}
353 	if (cper_dimm_err_location(&cmem, rcd_decode_str))
354 		printk("%s%s\n", pfx, rcd_decode_str);
355 }
356 
357 static const char * const pcie_port_type_strs[] = {
358 	"PCIe end point",
359 	"legacy PCI end point",
360 	"unknown",
361 	"unknown",
362 	"root port",
363 	"upstream switch port",
364 	"downstream switch port",
365 	"PCIe to PCI/PCI-X bridge",
366 	"PCI/PCI-X to PCIe bridge",
367 	"root complex integrated endpoint device",
368 	"root complex event collector",
369 };
370 
cper_print_pcie(const char * pfx,const struct cper_sec_pcie * pcie,const struct acpi_hest_generic_data * gdata)371 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
372 			    const struct acpi_hest_generic_data *gdata)
373 {
374 	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
375 		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
376 		       pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
377 		       pcie_port_type_strs[pcie->port_type] : "unknown");
378 	if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
379 		printk("%s""version: %d.%d\n", pfx,
380 		       pcie->version.major, pcie->version.minor);
381 	if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
382 		printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
383 		       pcie->command, pcie->status);
384 	if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
385 		const __u8 *p;
386 		printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
387 		       pcie->device_id.segment, pcie->device_id.bus,
388 		       pcie->device_id.device, pcie->device_id.function);
389 		printk("%s""slot: %d\n", pfx,
390 		       pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
391 		printk("%s""secondary_bus: 0x%02x\n", pfx,
392 		       pcie->device_id.secondary_bus);
393 		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
394 		       pcie->device_id.vendor_id, pcie->device_id.device_id);
395 		p = pcie->device_id.class_code;
396 		printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
397 	}
398 	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
399 		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
400 		       pcie->serial_number.lower, pcie->serial_number.upper);
401 	if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
402 		printk(
403 	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
404 	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
405 
406 	/* Fatal errors call __ghes_panic() before AER handler prints this */
407 	if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
408 	    (gdata->error_severity & CPER_SEV_FATAL)) {
409 		struct aer_capability_regs *aer;
410 
411 		aer = (struct aer_capability_regs *)pcie->aer_info;
412 		printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
413 		       pfx, aer->uncor_status, aer->uncor_mask);
414 		printk("%saer_uncor_severity: 0x%08x\n",
415 		       pfx, aer->uncor_severity);
416 		printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
417 		       aer->header_log.dw0, aer->header_log.dw1,
418 		       aer->header_log.dw2, aer->header_log.dw3);
419 	}
420 }
421 
422 static const char * const fw_err_rec_type_strs[] = {
423 	"IPF SAL Error Record",
424 	"SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
425 	"SOC Firmware Error Record Type2",
426 };
427 
cper_print_fw_err(const char * pfx,struct acpi_hest_generic_data * gdata,const struct cper_sec_fw_err_rec_ref * fw_err)428 static void cper_print_fw_err(const char *pfx,
429 			      struct acpi_hest_generic_data *gdata,
430 			      const struct cper_sec_fw_err_rec_ref *fw_err)
431 {
432 	void *buf = acpi_hest_get_payload(gdata);
433 	u32 offset, length = gdata->error_data_length;
434 
435 	printk("%s""Firmware Error Record Type: %s\n", pfx,
436 	       fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
437 	       fw_err_rec_type_strs[fw_err->record_type] : "unknown");
438 	printk("%s""Revision: %d\n", pfx, fw_err->revision);
439 
440 	/* Record Type based on UEFI 2.7 */
441 	if (fw_err->revision == 0) {
442 		printk("%s""Record Identifier: %08llx\n", pfx,
443 		       fw_err->record_identifier);
444 	} else if (fw_err->revision == 2) {
445 		printk("%s""Record Identifier: %pUl\n", pfx,
446 		       &fw_err->record_identifier_guid);
447 	}
448 
449 	/*
450 	 * The FW error record may contain trailing data beyond the
451 	 * structure defined by the specification. As the fields
452 	 * defined (and hence the offset of any trailing data) vary
453 	 * with the revision, set the offset to account for this
454 	 * variation.
455 	 */
456 	if (fw_err->revision == 0) {
457 		/* record_identifier_guid not defined */
458 		offset = offsetof(struct cper_sec_fw_err_rec_ref,
459 				  record_identifier_guid);
460 	} else if (fw_err->revision == 1) {
461 		/* record_identifier not defined */
462 		offset = offsetof(struct cper_sec_fw_err_rec_ref,
463 				  record_identifier);
464 	} else {
465 		offset = sizeof(*fw_err);
466 	}
467 
468 	buf += offset;
469 	length -= offset;
470 
471 	print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
472 }
473 
cper_print_tstamp(const char * pfx,struct acpi_hest_generic_data_v300 * gdata)474 static void cper_print_tstamp(const char *pfx,
475 				   struct acpi_hest_generic_data_v300 *gdata)
476 {
477 	__u8 hour, min, sec, day, mon, year, century, *timestamp;
478 
479 	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
480 		timestamp = (__u8 *)&(gdata->time_stamp);
481 		sec       = bcd2bin(timestamp[0]);
482 		min       = bcd2bin(timestamp[1]);
483 		hour      = bcd2bin(timestamp[2]);
484 		day       = bcd2bin(timestamp[4]);
485 		mon       = bcd2bin(timestamp[5]);
486 		year      = bcd2bin(timestamp[6]);
487 		century   = bcd2bin(timestamp[7]);
488 
489 		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
490 		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),
491 		       century, year, mon, day, hour, min, sec);
492 	}
493 }
494 
495 static void
cper_estatus_print_section(const char * pfx,struct acpi_hest_generic_data * gdata,int sec_no)496 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
497 			   int sec_no)
498 {
499 	guid_t *sec_type = (guid_t *)gdata->section_type;
500 	__u16 severity;
501 	char newpfx[64];
502 
503 	if (acpi_hest_get_version(gdata) >= 3)
504 		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
505 
506 	severity = gdata->error_severity;
507 	printk("%s""Error %d, type: %s\n", pfx, sec_no,
508 	       cper_severity_str(severity));
509 	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
510 		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
511 	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
512 		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
513 
514 	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
515 	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
516 		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
517 
518 		printk("%s""section_type: general processor error\n", newpfx);
519 		if (gdata->error_data_length >= sizeof(*proc_err))
520 			cper_print_proc_generic(newpfx, proc_err);
521 		else
522 			goto err_section_too_small;
523 	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
524 		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
525 
526 		printk("%s""section_type: memory error\n", newpfx);
527 		if (gdata->error_data_length >=
528 		    sizeof(struct cper_sec_mem_err_old))
529 			cper_print_mem(newpfx, mem_err,
530 				       gdata->error_data_length);
531 		else
532 			goto err_section_too_small;
533 	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
534 		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
535 
536 		printk("%s""section_type: PCIe error\n", newpfx);
537 		if (gdata->error_data_length >= sizeof(*pcie))
538 			cper_print_pcie(newpfx, pcie, gdata);
539 		else
540 			goto err_section_too_small;
541 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
542 	} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
543 		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
544 
545 		printk("%ssection_type: ARM processor error\n", newpfx);
546 		if (gdata->error_data_length >= sizeof(*arm_err))
547 			cper_print_proc_arm(newpfx, arm_err);
548 		else
549 			goto err_section_too_small;
550 #endif
551 #if defined(CONFIG_UEFI_CPER_X86)
552 	} else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
553 		struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
554 
555 		printk("%ssection_type: IA32/X64 processor error\n", newpfx);
556 		if (gdata->error_data_length >= sizeof(*ia_err))
557 			cper_print_proc_ia(newpfx, ia_err);
558 		else
559 			goto err_section_too_small;
560 #endif
561 	} else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
562 		struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
563 
564 		printk("%ssection_type: Firmware Error Record Reference\n",
565 		       newpfx);
566 		/* The minimal FW Error Record contains 16 bytes */
567 		if (gdata->error_data_length >= SZ_16)
568 			cper_print_fw_err(newpfx, gdata, fw_err);
569 		else
570 			goto err_section_too_small;
571 	} else {
572 		const void *err = acpi_hest_get_payload(gdata);
573 
574 		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
575 		printk("%ssection length: %#x\n", newpfx,
576 		       gdata->error_data_length);
577 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
578 			       gdata->error_data_length, true);
579 	}
580 
581 	return;
582 
583 err_section_too_small:
584 	pr_err(FW_WARN "error section length is too small\n");
585 }
586 
cper_estatus_print(const char * pfx,const struct acpi_hest_generic_status * estatus)587 void cper_estatus_print(const char *pfx,
588 			const struct acpi_hest_generic_status *estatus)
589 {
590 	struct acpi_hest_generic_data *gdata;
591 	int sec_no = 0;
592 	char newpfx[64];
593 	__u16 severity;
594 
595 	severity = estatus->error_severity;
596 	if (severity == CPER_SEV_CORRECTED)
597 		printk("%s%s\n", pfx,
598 		       "It has been corrected by h/w "
599 		       "and requires no further action");
600 	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
601 	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
602 
603 	apei_estatus_for_each_section(estatus, gdata) {
604 		cper_estatus_print_section(newpfx, gdata, sec_no);
605 		sec_no++;
606 	}
607 }
608 EXPORT_SYMBOL_GPL(cper_estatus_print);
609 
cper_estatus_check_header(const struct acpi_hest_generic_status * estatus)610 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
611 {
612 	if (estatus->data_length &&
613 	    estatus->data_length < sizeof(struct acpi_hest_generic_data))
614 		return -EINVAL;
615 	if (estatus->raw_data_length &&
616 	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
617 		return -EINVAL;
618 
619 	return 0;
620 }
621 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
622 
cper_estatus_check(const struct acpi_hest_generic_status * estatus)623 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
624 {
625 	struct acpi_hest_generic_data *gdata;
626 	unsigned int data_len, record_size;
627 	int rc;
628 
629 	rc = cper_estatus_check_header(estatus);
630 	if (rc)
631 		return rc;
632 
633 	data_len = estatus->data_length;
634 
635 	apei_estatus_for_each_section(estatus, gdata) {
636 		if (sizeof(struct acpi_hest_generic_data) > data_len)
637 			return -EINVAL;
638 
639 		record_size = acpi_hest_get_record_size(gdata);
640 		if (record_size > data_len)
641 			return -EINVAL;
642 
643 		data_len -= record_size;
644 	}
645 	if (data_len)
646 		return -EINVAL;
647 
648 	return 0;
649 }
650 EXPORT_SYMBOL_GPL(cper_estatus_check);
651