Merge tag 'uuid-for-4.14' of git://git.infradead.org/users/hch/uuid
[sfrench/cifs-2.6.git] / drivers / firmware / efi / cper.c
1 /*
2  * UEFI Common Platform Error Record (CPER) support
3  *
4  * Copyright (C) 2010, Intel Corp.
5  *      Author: Huang Ying <ying.huang@intel.com>
6  *
7  * CPER is the format used to describe platform hardware error by
8  * various tables, such as ERST, BERT and HEST etc.
9  *
10  * For more information about CPER, please refer to Appendix N of UEFI
11  * Specification version 2.4.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License version
15  * 2 as published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/time.h>
30 #include <linux/cper.h>
31 #include <linux/dmi.h>
32 #include <linux/acpi.h>
33 #include <linux/pci.h>
34 #include <linux/aer.h>
35 #include <linux/printk.h>
36 #include <linux/bcd.h>
37 #include <acpi/ghes.h>
38 #include <ras/ras_event.h>
39
40 #define INDENT_SP       " "
41
42 static char rcd_decode_str[CPER_REC_LEN];
43
44 /*
45  * CPER record ID need to be unique even after reboot, because record
46  * ID is used as index for ERST storage, while CPER records from
47  * multiple boot may co-exist in ERST.
48  */
49 u64 cper_next_record_id(void)
50 {
51         static atomic64_t seq;
52
53         if (!atomic64_read(&seq))
54                 atomic64_set(&seq, ((u64)get_seconds()) << 32);
55
56         return atomic64_inc_return(&seq);
57 }
58 EXPORT_SYMBOL_GPL(cper_next_record_id);
59
60 static const char * const severity_strs[] = {
61         "recoverable",
62         "fatal",
63         "corrected",
64         "info",
65 };
66
67 const char *cper_severity_str(unsigned int severity)
68 {
69         return severity < ARRAY_SIZE(severity_strs) ?
70                 severity_strs[severity] : "unknown";
71 }
72 EXPORT_SYMBOL_GPL(cper_severity_str);
73
74 /*
75  * cper_print_bits - print strings for set bits
76  * @pfx: prefix for each line, including log level and prefix string
77  * @bits: bit mask
78  * @strs: string array, indexed by bit position
79  * @strs_size: size of the string array: @strs
80  *
81  * For each set bit in @bits, print the corresponding string in @strs.
82  * If the output length is longer than 80, multiple line will be
83  * printed, with @pfx is printed at the beginning of each line.
84  */
85 void cper_print_bits(const char *pfx, unsigned int bits,
86                      const char * const strs[], unsigned int strs_size)
87 {
88         int i, len = 0;
89         const char *str;
90         char buf[84];
91
92         for (i = 0; i < strs_size; i++) {
93                 if (!(bits & (1U << i)))
94                         continue;
95                 str = strs[i];
96                 if (!str)
97                         continue;
98                 if (len && len + strlen(str) + 2 > 80) {
99                         printk("%s\n", buf);
100                         len = 0;
101                 }
102                 if (!len)
103                         len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
104                 else
105                         len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
106         }
107         if (len)
108                 printk("%s\n", buf);
109 }
110
111 static const char * const proc_type_strs[] = {
112         "IA32/X64",
113         "IA64",
114         "ARM",
115 };
116
117 static const char * const proc_isa_strs[] = {
118         "IA32",
119         "IA64",
120         "X64",
121         "ARM A32/T32",
122         "ARM A64",
123 };
124
125 static const char * const proc_error_type_strs[] = {
126         "cache error",
127         "TLB error",
128         "bus error",
129         "micro-architectural error",
130 };
131
132 static const char * const proc_op_strs[] = {
133         "unknown or generic",
134         "data read",
135         "data write",
136         "instruction execution",
137 };
138
139 static const char * const proc_flag_strs[] = {
140         "restartable",
141         "precise IP",
142         "overflow",
143         "corrected",
144 };
145
146 static void cper_print_proc_generic(const char *pfx,
147                                     const struct cper_sec_proc_generic *proc)
148 {
149         if (proc->validation_bits & CPER_PROC_VALID_TYPE)
150                 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
151                        proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
152                        proc_type_strs[proc->proc_type] : "unknown");
153         if (proc->validation_bits & CPER_PROC_VALID_ISA)
154                 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
155                        proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
156                        proc_isa_strs[proc->proc_isa] : "unknown");
157         if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
158                 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
159                 cper_print_bits(pfx, proc->proc_error_type,
160                                 proc_error_type_strs,
161                                 ARRAY_SIZE(proc_error_type_strs));
162         }
163         if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
164                 printk("%s""operation: %d, %s\n", pfx, proc->operation,
165                        proc->operation < ARRAY_SIZE(proc_op_strs) ?
166                        proc_op_strs[proc->operation] : "unknown");
167         if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
168                 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
169                 cper_print_bits(pfx, proc->flags, proc_flag_strs,
170                                 ARRAY_SIZE(proc_flag_strs));
171         }
172         if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
173                 printk("%s""level: %d\n", pfx, proc->level);
174         if (proc->validation_bits & CPER_PROC_VALID_VERSION)
175                 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
176         if (proc->validation_bits & CPER_PROC_VALID_ID)
177                 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
178         if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
179                 printk("%s""target_address: 0x%016llx\n",
180                        pfx, proc->target_addr);
181         if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
182                 printk("%s""requestor_id: 0x%016llx\n",
183                        pfx, proc->requestor_id);
184         if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
185                 printk("%s""responder_id: 0x%016llx\n",
186                        pfx, proc->responder_id);
187         if (proc->validation_bits & CPER_PROC_VALID_IP)
188                 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
189 }
190
191 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
192 static const char * const arm_reg_ctx_strs[] = {
193         "AArch32 general purpose registers",
194         "AArch32 EL1 context registers",
195         "AArch32 EL2 context registers",
196         "AArch32 secure context registers",
197         "AArch64 general purpose registers",
198         "AArch64 EL1 context registers",
199         "AArch64 EL2 context registers",
200         "AArch64 EL3 context registers",
201         "Misc. system register structure",
202 };
203
204 static void cper_print_proc_arm(const char *pfx,
205                                 const struct cper_sec_proc_arm *proc)
206 {
207         int i, len, max_ctx_type;
208         struct cper_arm_err_info *err_info;
209         struct cper_arm_ctx_info *ctx_info;
210         char newpfx[64];
211
212         printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
213
214         len = proc->section_length - (sizeof(*proc) +
215                 proc->err_info_num * (sizeof(*err_info)));
216         if (len < 0) {
217                 printk("%ssection length: %d\n", pfx, proc->section_length);
218                 printk("%ssection length is too small\n", pfx);
219                 printk("%sfirmware-generated error record is incorrect\n", pfx);
220                 printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
221                 return;
222         }
223
224         if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
225                 printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
226                         pfx, proc->mpidr);
227
228         if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
229                 printk("%serror affinity level: %d\n", pfx,
230                         proc->affinity_level);
231
232         if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
233                 printk("%srunning state: 0x%x\n", pfx, proc->running_state);
234                 printk("%sPower State Coordination Interface state: %d\n",
235                         pfx, proc->psci_state);
236         }
237
238         snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
239
240         err_info = (struct cper_arm_err_info *)(proc + 1);
241         for (i = 0; i < proc->err_info_num; i++) {
242                 printk("%sError info structure %d:\n", pfx, i);
243
244                 printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
245
246                 if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
247                         if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
248                                 printk("%sfirst error captured\n", newpfx);
249                         if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
250                                 printk("%slast error captured\n", newpfx);
251                         if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
252                                 printk("%spropagated error captured\n",
253                                        newpfx);
254                         if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
255                                 printk("%soverflow occurred, error info is incomplete\n",
256                                        newpfx);
257                 }
258
259                 printk("%serror_type: %d, %s\n", newpfx, err_info->type,
260                         err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
261                         proc_error_type_strs[err_info->type] : "unknown");
262                 if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO)
263                         printk("%serror_info: 0x%016llx\n", newpfx,
264                                err_info->error_info);
265                 if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
266                         printk("%svirtual fault address: 0x%016llx\n",
267                                 newpfx, err_info->virt_fault_addr);
268                 if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
269                         printk("%sphysical fault address: 0x%016llx\n",
270                                 newpfx, err_info->physical_fault_addr);
271                 err_info += 1;
272         }
273
274         ctx_info = (struct cper_arm_ctx_info *)err_info;
275         max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
276         for (i = 0; i < proc->context_info_num; i++) {
277                 int size = sizeof(*ctx_info) + ctx_info->size;
278
279                 printk("%sContext info structure %d:\n", pfx, i);
280                 if (len < size) {
281                         printk("%ssection length is too small\n", newpfx);
282                         printk("%sfirmware-generated error record is incorrect\n", pfx);
283                         return;
284                 }
285                 if (ctx_info->type > max_ctx_type) {
286                         printk("%sInvalid context type: %d (max: %d)\n",
287                                 newpfx, ctx_info->type, max_ctx_type);
288                         return;
289                 }
290                 printk("%sregister context type: %s\n", newpfx,
291                         arm_reg_ctx_strs[ctx_info->type]);
292                 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
293                                 (ctx_info + 1), ctx_info->size, 0);
294                 len -= size;
295                 ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
296         }
297
298         if (len > 0) {
299                 printk("%sVendor specific error info has %u bytes:\n", pfx,
300                        len);
301                 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
302                                 len, true);
303         }
304 }
305 #endif
306
307 static const char * const mem_err_type_strs[] = {
308         "unknown",
309         "no error",
310         "single-bit ECC",
311         "multi-bit ECC",
312         "single-symbol chipkill ECC",
313         "multi-symbol chipkill ECC",
314         "master abort",
315         "target abort",
316         "parity error",
317         "watchdog timeout",
318         "invalid address",
319         "mirror Broken",
320         "memory sparing",
321         "scrub corrected error",
322         "scrub uncorrected error",
323         "physical memory map-out event",
324 };
325
326 const char *cper_mem_err_type_str(unsigned int etype)
327 {
328         return etype < ARRAY_SIZE(mem_err_type_strs) ?
329                 mem_err_type_strs[etype] : "unknown";
330 }
331 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
332
333 static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
334 {
335         u32 len, n;
336
337         if (!msg)
338                 return 0;
339
340         n = 0;
341         len = CPER_REC_LEN - 1;
342         if (mem->validation_bits & CPER_MEM_VALID_NODE)
343                 n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
344         if (mem->validation_bits & CPER_MEM_VALID_CARD)
345                 n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
346         if (mem->validation_bits & CPER_MEM_VALID_MODULE)
347                 n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
348         if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
349                 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
350         if (mem->validation_bits & CPER_MEM_VALID_BANK)
351                 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
352         if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
353                 n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
354         if (mem->validation_bits & CPER_MEM_VALID_ROW)
355                 n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
356         if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
357                 n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
358         if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
359                 n += scnprintf(msg + n, len - n, "bit_position: %d ",
360                                mem->bit_pos);
361         if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
362                 n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
363                                mem->requestor_id);
364         if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
365                 n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
366                                mem->responder_id);
367         if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
368                 scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
369                           mem->target_id);
370
371         msg[n] = '\0';
372         return n;
373 }
374
375 static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
376 {
377         u32 len, n;
378         const char *bank = NULL, *device = NULL;
379
380         if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
381                 return 0;
382
383         n = 0;
384         len = CPER_REC_LEN - 1;
385         dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
386         if (bank && device)
387                 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
388         else
389                 n = snprintf(msg, len,
390                              "DIMM location: not present. DMI handle: 0x%.4x ",
391                              mem->mem_dev_handle);
392
393         msg[n] = '\0';
394         return n;
395 }
396
397 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
398                        struct cper_mem_err_compact *cmem)
399 {
400         cmem->validation_bits = mem->validation_bits;
401         cmem->node = mem->node;
402         cmem->card = mem->card;
403         cmem->module = mem->module;
404         cmem->bank = mem->bank;
405         cmem->device = mem->device;
406         cmem->row = mem->row;
407         cmem->column = mem->column;
408         cmem->bit_pos = mem->bit_pos;
409         cmem->requestor_id = mem->requestor_id;
410         cmem->responder_id = mem->responder_id;
411         cmem->target_id = mem->target_id;
412         cmem->rank = mem->rank;
413         cmem->mem_array_handle = mem->mem_array_handle;
414         cmem->mem_dev_handle = mem->mem_dev_handle;
415 }
416
417 const char *cper_mem_err_unpack(struct trace_seq *p,
418                                 struct cper_mem_err_compact *cmem)
419 {
420         const char *ret = trace_seq_buffer_ptr(p);
421
422         if (cper_mem_err_location(cmem, rcd_decode_str))
423                 trace_seq_printf(p, "%s", rcd_decode_str);
424         if (cper_dimm_err_location(cmem, rcd_decode_str))
425                 trace_seq_printf(p, "%s", rcd_decode_str);
426         trace_seq_putc(p, '\0');
427
428         return ret;
429 }
430
431 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
432         int len)
433 {
434         struct cper_mem_err_compact cmem;
435
436         /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
437         if (len == sizeof(struct cper_sec_mem_err_old) &&
438             (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
439                 pr_err(FW_WARN "valid bits set for fields beyond structure\n");
440                 return;
441         }
442         if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
443                 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
444         if (mem->validation_bits & CPER_MEM_VALID_PA)
445                 printk("%s""physical_address: 0x%016llx\n",
446                        pfx, mem->physical_addr);
447         if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
448                 printk("%s""physical_address_mask: 0x%016llx\n",
449                        pfx, mem->physical_addr_mask);
450         cper_mem_err_pack(mem, &cmem);
451         if (cper_mem_err_location(&cmem, rcd_decode_str))
452                 printk("%s%s\n", pfx, rcd_decode_str);
453         if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
454                 u8 etype = mem->error_type;
455                 printk("%s""error_type: %d, %s\n", pfx, etype,
456                        cper_mem_err_type_str(etype));
457         }
458         if (cper_dimm_err_location(&cmem, rcd_decode_str))
459                 printk("%s%s\n", pfx, rcd_decode_str);
460 }
461
462 static const char * const pcie_port_type_strs[] = {
463         "PCIe end point",
464         "legacy PCI end point",
465         "unknown",
466         "unknown",
467         "root port",
468         "upstream switch port",
469         "downstream switch port",
470         "PCIe to PCI/PCI-X bridge",
471         "PCI/PCI-X to PCIe bridge",
472         "root complex integrated endpoint device",
473         "root complex event collector",
474 };
475
476 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
477                             const struct acpi_hest_generic_data *gdata)
478 {
479         if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
480                 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
481                        pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
482                        pcie_port_type_strs[pcie->port_type] : "unknown");
483         if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
484                 printk("%s""version: %d.%d\n", pfx,
485                        pcie->version.major, pcie->version.minor);
486         if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
487                 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
488                        pcie->command, pcie->status);
489         if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
490                 const __u8 *p;
491                 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
492                        pcie->device_id.segment, pcie->device_id.bus,
493                        pcie->device_id.device, pcie->device_id.function);
494                 printk("%s""slot: %d\n", pfx,
495                        pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
496                 printk("%s""secondary_bus: 0x%02x\n", pfx,
497                        pcie->device_id.secondary_bus);
498                 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
499                        pcie->device_id.vendor_id, pcie->device_id.device_id);
500                 p = pcie->device_id.class_code;
501                 printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
502         }
503         if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
504                 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
505                        pcie->serial_number.lower, pcie->serial_number.upper);
506         if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
507                 printk(
508         "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
509         pfx, pcie->bridge.secondary_status, pcie->bridge.control);
510 }
511
512 static void cper_print_tstamp(const char *pfx,
513                                    struct acpi_hest_generic_data_v300 *gdata)
514 {
515         __u8 hour, min, sec, day, mon, year, century, *timestamp;
516
517         if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
518                 timestamp = (__u8 *)&(gdata->time_stamp);
519                 sec       = bcd2bin(timestamp[0]);
520                 min       = bcd2bin(timestamp[1]);
521                 hour      = bcd2bin(timestamp[2]);
522                 day       = bcd2bin(timestamp[4]);
523                 mon       = bcd2bin(timestamp[5]);
524                 year      = bcd2bin(timestamp[6]);
525                 century   = bcd2bin(timestamp[7]);
526
527                 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
528                        (timestamp[3] & 0x1 ? "precise " : "imprecise "),
529                        century, year, mon, day, hour, min, sec);
530         }
531 }
532
533 static void
534 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
535                            int sec_no)
536 {
537         guid_t *sec_type = (guid_t *)gdata->section_type;
538         __u16 severity;
539         char newpfx[64];
540
541         if (acpi_hest_get_version(gdata) >= 3)
542                 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
543
544         severity = gdata->error_severity;
545         printk("%s""Error %d, type: %s\n", pfx, sec_no,
546                cper_severity_str(severity));
547         if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
548                 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
549         if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
550                 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
551
552         snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
553         if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
554                 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
555
556                 printk("%s""section_type: general processor error\n", newpfx);
557                 if (gdata->error_data_length >= sizeof(*proc_err))
558                         cper_print_proc_generic(newpfx, proc_err);
559                 else
560                         goto err_section_too_small;
561         } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
562                 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
563
564                 printk("%s""section_type: memory error\n", newpfx);
565                 if (gdata->error_data_length >=
566                     sizeof(struct cper_sec_mem_err_old))
567                         cper_print_mem(newpfx, mem_err,
568                                        gdata->error_data_length);
569                 else
570                         goto err_section_too_small;
571         } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
572                 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
573
574                 printk("%s""section_type: PCIe error\n", newpfx);
575                 if (gdata->error_data_length >= sizeof(*pcie))
576                         cper_print_pcie(newpfx, pcie, gdata);
577                 else
578                         goto err_section_too_small;
579 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
580         } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
581                 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
582
583                 printk("%ssection_type: ARM processor error\n", newpfx);
584                 if (gdata->error_data_length >= sizeof(*arm_err))
585                         cper_print_proc_arm(newpfx, arm_err);
586                 else
587                         goto err_section_too_small;
588 #endif
589         } else {
590                 const void *err = acpi_hest_get_payload(gdata);
591
592                 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
593                 printk("%ssection length: %#x\n", newpfx,
594                        gdata->error_data_length);
595                 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
596                                gdata->error_data_length, true);
597         }
598
599         return;
600
601 err_section_too_small:
602         pr_err(FW_WARN "error section length is too small\n");
603 }
604
605 void cper_estatus_print(const char *pfx,
606                         const struct acpi_hest_generic_status *estatus)
607 {
608         struct acpi_hest_generic_data *gdata;
609         int sec_no = 0;
610         char newpfx[64];
611         __u16 severity;
612
613         severity = estatus->error_severity;
614         if (severity == CPER_SEV_CORRECTED)
615                 printk("%s%s\n", pfx,
616                        "It has been corrected by h/w "
617                        "and requires no further action");
618         printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
619         snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
620
621         apei_estatus_for_each_section(estatus, gdata) {
622                 cper_estatus_print_section(newpfx, gdata, sec_no);
623                 sec_no++;
624         }
625 }
626 EXPORT_SYMBOL_GPL(cper_estatus_print);
627
628 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
629 {
630         if (estatus->data_length &&
631             estatus->data_length < sizeof(struct acpi_hest_generic_data))
632                 return -EINVAL;
633         if (estatus->raw_data_length &&
634             estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
635                 return -EINVAL;
636
637         return 0;
638 }
639 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
640
641 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
642 {
643         struct acpi_hest_generic_data *gdata;
644         unsigned int data_len, gedata_len;
645         int rc;
646
647         rc = cper_estatus_check_header(estatus);
648         if (rc)
649                 return rc;
650         data_len = estatus->data_length;
651
652         apei_estatus_for_each_section(estatus, gdata) {
653                 gedata_len = acpi_hest_get_error_length(gdata);
654                 if (gedata_len > data_len - acpi_hest_get_size(gdata))
655                         return -EINVAL;
656                 data_len -= acpi_hest_get_record_size(gdata);
657         }
658         if (data_len)
659                 return -EINVAL;
660
661         return 0;
662 }
663 EXPORT_SYMBOL_GPL(cper_estatus_check);