GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / firmware / efi / cper.c
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  */
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
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  */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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);