]> Git Repo - linux.git/blob - drivers/firmware/efi/cper.c
Linux 6.14-rc3
[linux.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 <[email protected]>
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 #include "cper_cxl.h"
28
29 /*
30  * CPER record ID need to be unique even after reboot, because record
31  * ID is used as index for ERST storage, while CPER records from
32  * multiple boot may co-exist in ERST.
33  */
34 u64 cper_next_record_id(void)
35 {
36         static atomic64_t seq;
37
38         if (!atomic64_read(&seq)) {
39                 time64_t time = ktime_get_real_seconds();
40
41                 /*
42                  * This code is unlikely to still be needed in year 2106,
43                  * but just in case, let's use a few more bits for timestamps
44                  * after y2038 to be sure they keep increasing monotonically
45                  * for the next few hundred years...
46                  */
47                 if (time < 0x80000000)
48                         atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
49                 else
50                         atomic64_set(&seq, 0x8000000000000000ull |
51                                            ktime_get_real_seconds() << 24);
52         }
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 += scnprintf(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 const char * const cper_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                                 cper_proc_error_type_strs,
159                                 ARRAY_SIZE(cper_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 static const char * const mem_err_type_strs[] = {
190         "unknown",
191         "no error",
192         "single-bit ECC",
193         "multi-bit ECC",
194         "single-symbol chipkill ECC",
195         "multi-symbol chipkill ECC",
196         "master abort",
197         "target abort",
198         "parity error",
199         "watchdog timeout",
200         "invalid address",
201         "mirror Broken",
202         "memory sparing",
203         "scrub corrected error",
204         "scrub uncorrected error",
205         "physical memory map-out event",
206 };
207
208 const char *cper_mem_err_type_str(unsigned int etype)
209 {
210         return etype < ARRAY_SIZE(mem_err_type_strs) ?
211                 mem_err_type_strs[etype] : "unknown";
212 }
213 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
214
215 const char *cper_mem_err_status_str(u64 status)
216 {
217         switch ((status >> 8) & 0xff) {
218         case  1:        return "Error detected internal to the component";
219         case  4:        return "Storage error in DRAM memory";
220         case  5:        return "Storage error in TLB";
221         case  6:        return "Storage error in cache";
222         case  7:        return "Error in one or more functional units";
223         case  8:        return "Component failed self test";
224         case  9:        return "Overflow or undervalue of internal queue";
225         case 16:        return "Error detected in the bus";
226         case 17:        return "Virtual address not found on IO-TLB or IO-PDIR";
227         case 18:        return "Improper access error";
228         case 19:        return "Access to a memory address which is not mapped to any component";
229         case 20:        return "Loss of Lockstep";
230         case 21:        return "Response not associated with a request";
231         case 22:        return "Bus parity error - must also set the A, C, or D Bits";
232         case 23:        return "Detection of a protocol error";
233         case 24:        return "Detection of a PATH_ERROR";
234         case 25:        return "Bus operation timeout";
235         case 26:        return "A read was issued to data that has been poisoned";
236         default:        return "Reserved";
237         }
238 }
239 EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
240
241 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
242 {
243         u32 len, n;
244
245         if (!msg)
246                 return 0;
247
248         n = 0;
249         len = CPER_REC_LEN;
250         if (mem->validation_bits & CPER_MEM_VALID_NODE)
251                 n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
252         if (mem->validation_bits & CPER_MEM_VALID_CARD)
253                 n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
254         if (mem->validation_bits & CPER_MEM_VALID_MODULE)
255                 n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
256         if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
257                 n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank);
258         if (mem->validation_bits & CPER_MEM_VALID_BANK)
259                 n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
260         if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
261                 n += scnprintf(msg + n, len - n, "bank_group:%d ",
262                                mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
263         if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
264                 n += scnprintf(msg + n, len - n, "bank_address:%d ",
265                                mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
266         if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
267                 n += scnprintf(msg + n, len - n, "device:%d ", mem->device);
268         if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
269                 u32 row = mem->row;
270
271                 row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
272                 n += scnprintf(msg + n, len - n, "row:%d ", row);
273         }
274         if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
275                 n += scnprintf(msg + n, len - n, "column:%d ", mem->column);
276         if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
277                 n += scnprintf(msg + n, len - n, "bit_position:%d ",
278                                mem->bit_pos);
279         if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
280                 n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
281                                mem->requestor_id);
282         if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
283                 n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
284                                mem->responder_id);
285         if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
286                 n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
287                                mem->target_id);
288         if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
289                 n += scnprintf(msg + n, len - n, "chip_id:%d ",
290                                mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
291
292         return n;
293 }
294 EXPORT_SYMBOL_GPL(cper_mem_err_location);
295
296 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
297 {
298         u32 len, n;
299         const char *bank = NULL, *device = NULL;
300
301         if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
302                 return 0;
303
304         len = CPER_REC_LEN;
305         dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
306         if (bank && device)
307                 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
308         else
309                 n = snprintf(msg, len,
310                              "DIMM location: not present. DMI handle: 0x%.4x ",
311                              mem->mem_dev_handle);
312
313         return n;
314 }
315 EXPORT_SYMBOL_GPL(cper_dimm_err_location);
316
317 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
318                        struct cper_mem_err_compact *cmem)
319 {
320         cmem->validation_bits = mem->validation_bits;
321         cmem->node = mem->node;
322         cmem->card = mem->card;
323         cmem->module = mem->module;
324         cmem->bank = mem->bank;
325         cmem->device = mem->device;
326         cmem->row = mem->row;
327         cmem->column = mem->column;
328         cmem->bit_pos = mem->bit_pos;
329         cmem->requestor_id = mem->requestor_id;
330         cmem->responder_id = mem->responder_id;
331         cmem->target_id = mem->target_id;
332         cmem->extended = mem->extended;
333         cmem->rank = mem->rank;
334         cmem->mem_array_handle = mem->mem_array_handle;
335         cmem->mem_dev_handle = mem->mem_dev_handle;
336 }
337 EXPORT_SYMBOL_GPL(cper_mem_err_pack);
338
339 const char *cper_mem_err_unpack(struct trace_seq *p,
340                                 struct cper_mem_err_compact *cmem)
341 {
342         const char *ret = trace_seq_buffer_ptr(p);
343         char rcd_decode_str[CPER_REC_LEN];
344
345         if (cper_mem_err_location(cmem, rcd_decode_str))
346                 trace_seq_printf(p, "%s", rcd_decode_str);
347         if (cper_dimm_err_location(cmem, rcd_decode_str))
348                 trace_seq_printf(p, "%s", rcd_decode_str);
349         trace_seq_putc(p, '\0');
350
351         return ret;
352 }
353
354 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
355         int len)
356 {
357         struct cper_mem_err_compact cmem;
358         char rcd_decode_str[CPER_REC_LEN];
359
360         /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
361         if (len == sizeof(struct cper_sec_mem_err_old) &&
362             (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
363                 pr_err(FW_WARN "valid bits set for fields beyond structure\n");
364                 return;
365         }
366         if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
367                 printk("%s error_status: %s (0x%016llx)\n",
368                        pfx, cper_mem_err_status_str(mem->error_status),
369                        mem->error_status);
370         if (mem->validation_bits & CPER_MEM_VALID_PA)
371                 printk("%s""physical_address: 0x%016llx\n",
372                        pfx, mem->physical_addr);
373         if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
374                 printk("%s""physical_address_mask: 0x%016llx\n",
375                        pfx, mem->physical_addr_mask);
376         cper_mem_err_pack(mem, &cmem);
377         if (cper_mem_err_location(&cmem, rcd_decode_str))
378                 printk("%s%s\n", pfx, rcd_decode_str);
379         if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
380                 u8 etype = mem->error_type;
381                 printk("%s""error_type: %d, %s\n", pfx, etype,
382                        cper_mem_err_type_str(etype));
383         }
384         if (cper_dimm_err_location(&cmem, rcd_decode_str))
385                 printk("%s%s\n", pfx, rcd_decode_str);
386 }
387
388 static const char * const pcie_port_type_strs[] = {
389         "PCIe end point",
390         "legacy PCI end point",
391         "unknown",
392         "unknown",
393         "root port",
394         "upstream switch port",
395         "downstream switch port",
396         "PCIe to PCI/PCI-X bridge",
397         "PCI/PCI-X to PCIe bridge",
398         "root complex integrated endpoint device",
399         "root complex event collector",
400 };
401
402 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
403                             const struct acpi_hest_generic_data *gdata)
404 {
405         if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
406                 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
407                        pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
408                        pcie_port_type_strs[pcie->port_type] : "unknown");
409         if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
410                 printk("%s""version: %d.%d\n", pfx,
411                        pcie->version.major, pcie->version.minor);
412         if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
413                 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
414                        pcie->command, pcie->status);
415         if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
416                 const __u8 *p;
417                 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
418                        pcie->device_id.segment, pcie->device_id.bus,
419                        pcie->device_id.device, pcie->device_id.function);
420                 printk("%s""slot: %d\n", pfx,
421                        pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
422                 printk("%s""secondary_bus: 0x%02x\n", pfx,
423                        pcie->device_id.secondary_bus);
424                 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
425                        pcie->device_id.vendor_id, pcie->device_id.device_id);
426                 p = pcie->device_id.class_code;
427                 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
428         }
429         if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
430                 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
431                        pcie->serial_number.lower, pcie->serial_number.upper);
432         if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
433                 printk(
434         "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
435         pfx, pcie->bridge.secondary_status, pcie->bridge.control);
436
437         /*
438          * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time).
439          *
440          * Fatal errors call __ghes_panic() before AER handler prints this.
441          */
442         if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
443                 struct aer_capability_regs *aer;
444
445                 aer = (struct aer_capability_regs *)pcie->aer_info;
446                 printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n",
447                        pfx, aer->cor_status, aer->cor_mask);
448                 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
449                        pfx, aer->uncor_status, aer->uncor_mask);
450                 printk("%saer_uncor_severity: 0x%08x\n",
451                        pfx, aer->uncor_severity);
452                 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
453                        aer->header_log.dw[0], aer->header_log.dw[1],
454                        aer->header_log.dw[2], aer->header_log.dw[3]);
455         }
456 }
457
458 static const char * const fw_err_rec_type_strs[] = {
459         "IPF SAL Error Record",
460         "SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
461         "SOC Firmware Error Record Type2",
462 };
463
464 static void cper_print_fw_err(const char *pfx,
465                               struct acpi_hest_generic_data *gdata,
466                               const struct cper_sec_fw_err_rec_ref *fw_err)
467 {
468         void *buf = acpi_hest_get_payload(gdata);
469         u32 offset, length = gdata->error_data_length;
470
471         printk("%s""Firmware Error Record Type: %s\n", pfx,
472                fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
473                fw_err_rec_type_strs[fw_err->record_type] : "unknown");
474         printk("%s""Revision: %d\n", pfx, fw_err->revision);
475
476         /* Record Type based on UEFI 2.7 */
477         if (fw_err->revision == 0) {
478                 printk("%s""Record Identifier: %08llx\n", pfx,
479                        fw_err->record_identifier);
480         } else if (fw_err->revision == 2) {
481                 printk("%s""Record Identifier: %pUl\n", pfx,
482                        &fw_err->record_identifier_guid);
483         }
484
485         /*
486          * The FW error record may contain trailing data beyond the
487          * structure defined by the specification. As the fields
488          * defined (and hence the offset of any trailing data) vary
489          * with the revision, set the offset to account for this
490          * variation.
491          */
492         if (fw_err->revision == 0) {
493                 /* record_identifier_guid not defined */
494                 offset = offsetof(struct cper_sec_fw_err_rec_ref,
495                                   record_identifier_guid);
496         } else if (fw_err->revision == 1) {
497                 /* record_identifier not defined */
498                 offset = offsetof(struct cper_sec_fw_err_rec_ref,
499                                   record_identifier);
500         } else {
501                 offset = sizeof(*fw_err);
502         }
503
504         buf += offset;
505         length -= offset;
506
507         print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
508 }
509
510 static void cper_print_tstamp(const char *pfx,
511                                    struct acpi_hest_generic_data_v300 *gdata)
512 {
513         __u8 hour, min, sec, day, mon, year, century, *timestamp;
514
515         if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
516                 timestamp = (__u8 *)&(gdata->time_stamp);
517                 sec       = bcd2bin(timestamp[0]);
518                 min       = bcd2bin(timestamp[1]);
519                 hour      = bcd2bin(timestamp[2]);
520                 day       = bcd2bin(timestamp[4]);
521                 mon       = bcd2bin(timestamp[5]);
522                 year      = bcd2bin(timestamp[6]);
523                 century   = bcd2bin(timestamp[7]);
524
525                 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
526                        (timestamp[3] & 0x1 ? "precise " : "imprecise "),
527                        century, year, mon, day, hour, min, sec);
528         }
529 }
530
531 struct ignore_section {
532         guid_t guid;
533         const char *name;
534 };
535
536 static const struct ignore_section ignore_sections[] = {
537         { .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" },
538         { .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" },
539         { .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" },
540 };
541
542 static void
543 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
544                            int sec_no)
545 {
546         guid_t *sec_type = (guid_t *)gdata->section_type;
547         __u16 severity;
548         char newpfx[64];
549
550         if (acpi_hest_get_version(gdata) >= 3)
551                 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
552
553         severity = gdata->error_severity;
554         printk("%s""Error %d, type: %s\n", pfx, sec_no,
555                cper_severity_str(severity));
556         if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
557                 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
558         if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
559                 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
560
561         snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
562
563         for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) {
564                 if (guid_equal(sec_type, &ignore_sections[i].guid)) {
565                         printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name);
566                         return;
567                 }
568         }
569
570         if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
571                 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
572
573                 printk("%s""section_type: general processor error\n", newpfx);
574                 if (gdata->error_data_length >= sizeof(*proc_err))
575                         cper_print_proc_generic(newpfx, proc_err);
576                 else
577                         goto err_section_too_small;
578         } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
579                 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
580
581                 printk("%s""section_type: memory error\n", newpfx);
582                 if (gdata->error_data_length >=
583                     sizeof(struct cper_sec_mem_err_old))
584                         cper_print_mem(newpfx, mem_err,
585                                        gdata->error_data_length);
586                 else
587                         goto err_section_too_small;
588         } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
589                 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
590
591                 printk("%s""section_type: PCIe error\n", newpfx);
592                 if (gdata->error_data_length >= sizeof(*pcie))
593                         cper_print_pcie(newpfx, pcie, gdata);
594                 else
595                         goto err_section_too_small;
596 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
597         } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
598                 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
599
600                 printk("%ssection_type: ARM processor error\n", newpfx);
601                 if (gdata->error_data_length >= sizeof(*arm_err))
602                         cper_print_proc_arm(newpfx, arm_err);
603                 else
604                         goto err_section_too_small;
605 #endif
606 #if defined(CONFIG_UEFI_CPER_X86)
607         } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
608                 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
609
610                 printk("%ssection_type: IA32/X64 processor error\n", newpfx);
611                 if (gdata->error_data_length >= sizeof(*ia_err))
612                         cper_print_proc_ia(newpfx, ia_err);
613                 else
614                         goto err_section_too_small;
615 #endif
616         } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
617                 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
618
619                 printk("%ssection_type: Firmware Error Record Reference\n",
620                        newpfx);
621                 /* The minimal FW Error Record contains 16 bytes */
622                 if (gdata->error_data_length >= SZ_16)
623                         cper_print_fw_err(newpfx, gdata, fw_err);
624                 else
625                         goto err_section_too_small;
626         } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
627                 struct cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
628
629                 printk("%ssection_type: CXL Protocol Error\n", newpfx);
630                 if (gdata->error_data_length >= sizeof(*prot_err))
631                         cper_print_prot_err(newpfx, prot_err);
632                 else
633                         goto err_section_too_small;
634         } else {
635                 const void *err = acpi_hest_get_payload(gdata);
636
637                 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
638                 printk("%ssection length: %#x\n", newpfx,
639                        gdata->error_data_length);
640                 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
641                                gdata->error_data_length, true);
642         }
643
644         return;
645
646 err_section_too_small:
647         pr_err(FW_WARN "error section length is too small\n");
648 }
649
650 void cper_estatus_print(const char *pfx,
651                         const struct acpi_hest_generic_status *estatus)
652 {
653         struct acpi_hest_generic_data *gdata;
654         int sec_no = 0;
655         char newpfx[64];
656         __u16 severity;
657
658         severity = estatus->error_severity;
659         if (severity == CPER_SEV_CORRECTED)
660                 printk("%s%s\n", pfx,
661                        "It has been corrected by h/w "
662                        "and requires no further action");
663         printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
664         snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
665
666         apei_estatus_for_each_section(estatus, gdata) {
667                 cper_estatus_print_section(newpfx, gdata, sec_no);
668                 sec_no++;
669         }
670 }
671 EXPORT_SYMBOL_GPL(cper_estatus_print);
672
673 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
674 {
675         if (estatus->data_length &&
676             estatus->data_length < sizeof(struct acpi_hest_generic_data))
677                 return -EINVAL;
678         if (estatus->raw_data_length &&
679             estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
680                 return -EINVAL;
681
682         return 0;
683 }
684 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
685
686 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
687 {
688         struct acpi_hest_generic_data *gdata;
689         unsigned int data_len, record_size;
690         int rc;
691
692         rc = cper_estatus_check_header(estatus);
693         if (rc)
694                 return rc;
695
696         data_len = estatus->data_length;
697
698         apei_estatus_for_each_section(estatus, gdata) {
699                 if (acpi_hest_get_size(gdata) > data_len)
700                         return -EINVAL;
701
702                 record_size = acpi_hest_get_record_size(gdata);
703                 if (record_size > data_len)
704                         return -EINVAL;
705
706                 data_len -= record_size;
707         }
708         if (data_len)
709                 return -EINVAL;
710
711         return 0;
712 }
713 EXPORT_SYMBOL_GPL(cper_estatus_check);
This page took 0.08001 seconds and 4 git commands to generate.