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