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_status_str(u64 status)214 const 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 }
238 EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
239
cper_mem_err_location(struct cper_mem_err_compact * mem,char * msg)240 int 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
cper_dimm_err_location(struct cper_mem_err_compact * mem,char * msg)294 int 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
cper_mem_err_pack(const struct cper_sec_mem_err * mem,struct cper_mem_err_compact * cmem)314 void 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
cper_mem_err_unpack(struct trace_seq * p,struct cper_mem_err_compact * cmem)335 const 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
cper_print_mem(const char * pfx,const struct cper_sec_mem_err * mem,int len)350 static 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
384 static 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
cper_print_pcie(const char * pfx,const struct cper_sec_pcie * pcie,const struct acpi_hest_generic_data * gdata)398 static 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
449 static 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
cper_print_fw_err(const char * pfx,struct acpi_hest_generic_data * gdata,const struct cper_sec_fw_err_rec_ref * fw_err)455 static 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
cper_print_tstamp(const char * pfx,struct acpi_hest_generic_data_v300 * gdata)501 static 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
522 static void
cper_estatus_print_section(const char * pfx,struct acpi_hest_generic_data * gdata,int sec_no)523 cper_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
610 err_section_too_small:
611 pr_err(FW_WARN "error section length is too small\n");
612 }
613
cper_estatus_print(const char * pfx,const struct acpi_hest_generic_status * estatus)614 void 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 }
635 EXPORT_SYMBOL_GPL(cper_estatus_print);
636
cper_estatus_check_header(const struct acpi_hest_generic_status * estatus)637 int 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 }
648 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
649
cper_estatus_check(const struct acpi_hest_generic_status * estatus)650 int 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 }
677 EXPORT_SYMBOL_GPL(cper_estatus_check);
678