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