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/bitmap.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/time.h>
19 #include <linux/cper.h>
20 #include <linux/dmi.h>
21 #include <linux/acpi.h>
22 #include <linux/pci.h>
23 #include <linux/aer.h>
24 #include <linux/printk.h>
25 #include <linux/bcd.h>
26 #include <acpi/ghes.h>
27 #include <ras/ras_event.h>
28 #include <cxl/event.h>
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 */
cper_next_record_id(void)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
cper_severity_str(unsigned int severity)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 */
cper_print_bits(const char * pfx,unsigned int bits,const char * const strs[],unsigned int strs_size)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 /**
111 * cper_bits_to_str - return a string for set bits
112 * @buf: buffer to store the output string
113 * @buf_size: size of the output string buffer
114 * @bits: bit mask
115 * @strs: string array, indexed by bit position
116 * @strs_size: size of the string array: @strs
117 *
118 * Add to @buf the bitmask in hexadecimal. Then, for each set bit in @bits,
119 * add the corresponding string describing the bit in @strs to @buf.
120 *
121 * A typical example is::
122 *
123 * const char * const bits[] = {
124 * "bit 3 name",
125 * "bit 4 name",
126 * "bit 5 name",
127 * };
128 * char str[120];
129 * unsigned int bitmask = BIT(3) | BIT(5);
130 * #define MASK GENMASK(5,3)
131 *
132 * cper_bits_to_str(str, sizeof(str), FIELD_GET(MASK, bitmask),
133 * bits, ARRAY_SIZE(bits));
134 *
135 * The above code fills the string ``str`` with ``bit 3 name|bit 5 name``.
136 *
137 * Return: number of bytes stored or an error code if lower than zero.
138 */
cper_bits_to_str(char * buf,int buf_size,unsigned long bits,const char * const strs[],unsigned int strs_size)139 int cper_bits_to_str(char *buf, int buf_size, unsigned long bits,
140 const char * const strs[], unsigned int strs_size)
141 {
142 int len = buf_size;
143 char *str = buf;
144 int i, size;
145
146 *buf = '\0';
147
148 for_each_set_bit(i, &bits, strs_size) {
149 if (!(bits & BIT_ULL(i)))
150 continue;
151
152 if (*buf && len > 0) {
153 *str = '|';
154 len--;
155 str++;
156 }
157
158 size = strscpy(str, strs[i], len);
159 if (size < 0)
160 return size;
161
162 len -= size;
163 str += size;
164 }
165 return buf_size - len;
166 }
167 EXPORT_SYMBOL_GPL(cper_bits_to_str);
168
169 static const char * const proc_type_strs[] = {
170 "IA32/X64",
171 "IA64",
172 "ARM",
173 };
174
175 static const char * const proc_isa_strs[] = {
176 "IA32",
177 "IA64",
178 "X64",
179 "ARM A32/T32",
180 "ARM A64",
181 };
182
183 const char * const cper_proc_error_type_strs[] = {
184 "cache error",
185 "TLB error",
186 "bus error",
187 "micro-architectural error",
188 };
189
190 static const char * const proc_op_strs[] = {
191 "unknown or generic",
192 "data read",
193 "data write",
194 "instruction execution",
195 };
196
197 static const char * const proc_flag_strs[] = {
198 "restartable",
199 "precise IP",
200 "overflow",
201 "corrected",
202 };
203
cper_print_proc_generic(const char * pfx,const struct cper_sec_proc_generic * proc)204 static void cper_print_proc_generic(const char *pfx,
205 const struct cper_sec_proc_generic *proc)
206 {
207 if (proc->validation_bits & CPER_PROC_VALID_TYPE)
208 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
209 proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
210 proc_type_strs[proc->proc_type] : "unknown");
211 if (proc->validation_bits & CPER_PROC_VALID_ISA)
212 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
213 proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
214 proc_isa_strs[proc->proc_isa] : "unknown");
215 if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
216 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
217 cper_print_bits(pfx, proc->proc_error_type,
218 cper_proc_error_type_strs,
219 ARRAY_SIZE(cper_proc_error_type_strs));
220 }
221 if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
222 printk("%s""operation: %d, %s\n", pfx, proc->operation,
223 proc->operation < ARRAY_SIZE(proc_op_strs) ?
224 proc_op_strs[proc->operation] : "unknown");
225 if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
226 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
227 cper_print_bits(pfx, proc->flags, proc_flag_strs,
228 ARRAY_SIZE(proc_flag_strs));
229 }
230 if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
231 printk("%s""level: %d\n", pfx, proc->level);
232 if (proc->validation_bits & CPER_PROC_VALID_VERSION)
233 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
234 if (proc->validation_bits & CPER_PROC_VALID_ID)
235 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
236 if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
237 printk("%s""target_address: 0x%016llx\n",
238 pfx, proc->target_addr);
239 if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
240 printk("%s""requestor_id: 0x%016llx\n",
241 pfx, proc->requestor_id);
242 if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
243 printk("%s""responder_id: 0x%016llx\n",
244 pfx, proc->responder_id);
245 if (proc->validation_bits & CPER_PROC_VALID_IP)
246 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
247 }
248
249 static const char * const mem_err_type_strs[] = {
250 "unknown",
251 "no error",
252 "single-bit ECC",
253 "multi-bit ECC",
254 "single-symbol chipkill ECC",
255 "multi-symbol chipkill ECC",
256 "master abort",
257 "target abort",
258 "parity error",
259 "watchdog timeout",
260 "invalid address",
261 "mirror Broken",
262 "memory sparing",
263 "scrub corrected error",
264 "scrub uncorrected error",
265 "physical memory map-out event",
266 };
267
cper_mem_err_type_str(unsigned int etype)268 const char *cper_mem_err_type_str(unsigned int etype)
269 {
270 return etype < ARRAY_SIZE(mem_err_type_strs) ?
271 mem_err_type_strs[etype] : "unknown";
272 }
273 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
274
cper_mem_err_status_str(u64 status)275 const char *cper_mem_err_status_str(u64 status)
276 {
277 switch ((status >> 8) & 0xff) {
278 case 1: return "Error detected internal to the component";
279 case 4: return "Storage error in DRAM memory";
280 case 5: return "Storage error in TLB";
281 case 6: return "Storage error in cache";
282 case 7: return "Error in one or more functional units";
283 case 8: return "Component failed self test";
284 case 9: return "Overflow or undervalue of internal queue";
285 case 16: return "Error detected in the bus";
286 case 17: return "Virtual address not found on IO-TLB or IO-PDIR";
287 case 18: return "Improper access error";
288 case 19: return "Access to a memory address which is not mapped to any component";
289 case 20: return "Loss of Lockstep";
290 case 21: return "Response not associated with a request";
291 case 22: return "Bus parity error - must also set the A, C, or D Bits";
292 case 23: return "Detection of a protocol error";
293 case 24: return "Detection of a PATH_ERROR";
294 case 25: return "Bus operation timeout";
295 case 26: return "A read was issued to data that has been poisoned";
296 default: return "Reserved";
297 }
298 }
299 EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
300
cper_mem_err_location(struct cper_mem_err_compact * mem,char * msg)301 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
302 {
303 u32 len, n;
304
305 if (!msg)
306 return 0;
307
308 n = 0;
309 len = CPER_REC_LEN;
310 if (mem->validation_bits & CPER_MEM_VALID_NODE)
311 n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
312 if (mem->validation_bits & CPER_MEM_VALID_CARD)
313 n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
314 if (mem->validation_bits & CPER_MEM_VALID_MODULE)
315 n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
316 if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
317 n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank);
318 if (mem->validation_bits & CPER_MEM_VALID_BANK)
319 n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
320 if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
321 n += scnprintf(msg + n, len - n, "bank_group:%d ",
322 mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
323 if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
324 n += scnprintf(msg + n, len - n, "bank_address:%d ",
325 mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
326 if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
327 n += scnprintf(msg + n, len - n, "device:%d ", mem->device);
328 if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
329 u32 row = mem->row;
330
331 row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
332 n += scnprintf(msg + n, len - n, "row:%d ", row);
333 }
334 if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
335 n += scnprintf(msg + n, len - n, "column:%d ", mem->column);
336 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
337 n += scnprintf(msg + n, len - n, "bit_position:%d ",
338 mem->bit_pos);
339 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
340 n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
341 mem->requestor_id);
342 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
343 n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
344 mem->responder_id);
345 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
346 n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
347 mem->target_id);
348 if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
349 n += scnprintf(msg + n, len - n, "chip_id:%d ",
350 mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
351
352 return n;
353 }
354 EXPORT_SYMBOL_GPL(cper_mem_err_location);
355
cper_dimm_err_location(struct cper_mem_err_compact * mem,char * msg)356 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
357 {
358 u32 len, n;
359 const char *bank = NULL, *device = NULL;
360
361 if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
362 return 0;
363
364 len = CPER_REC_LEN;
365 dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
366 if (bank && device)
367 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
368 else
369 n = snprintf(msg, len,
370 "DIMM location: not present. DMI handle: 0x%.4x ",
371 mem->mem_dev_handle);
372
373 return n;
374 }
375 EXPORT_SYMBOL_GPL(cper_dimm_err_location);
376
cper_mem_err_pack(const struct cper_sec_mem_err * mem,struct cper_mem_err_compact * cmem)377 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
378 struct cper_mem_err_compact *cmem)
379 {
380 cmem->validation_bits = mem->validation_bits;
381 cmem->node = mem->node;
382 cmem->card = mem->card;
383 cmem->module = mem->module;
384 cmem->bank = mem->bank;
385 cmem->device = mem->device;
386 cmem->row = mem->row;
387 cmem->column = mem->column;
388 cmem->bit_pos = mem->bit_pos;
389 cmem->requestor_id = mem->requestor_id;
390 cmem->responder_id = mem->responder_id;
391 cmem->target_id = mem->target_id;
392 cmem->extended = mem->extended;
393 cmem->rank = mem->rank;
394 cmem->mem_array_handle = mem->mem_array_handle;
395 cmem->mem_dev_handle = mem->mem_dev_handle;
396 }
397 EXPORT_SYMBOL_GPL(cper_mem_err_pack);
398
cper_mem_err_unpack(struct trace_seq * p,struct cper_mem_err_compact * cmem)399 const char *cper_mem_err_unpack(struct trace_seq *p,
400 struct cper_mem_err_compact *cmem)
401 {
402 const char *ret = trace_seq_buffer_ptr(p);
403 char rcd_decode_str[CPER_REC_LEN];
404
405 if (cper_mem_err_location(cmem, rcd_decode_str))
406 trace_seq_printf(p, "%s", rcd_decode_str);
407 if (cper_dimm_err_location(cmem, rcd_decode_str))
408 trace_seq_printf(p, "%s", rcd_decode_str);
409 trace_seq_putc(p, '\0');
410
411 return ret;
412 }
413
cper_print_mem(const char * pfx,const struct cper_sec_mem_err * mem,int len)414 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
415 int len)
416 {
417 struct cper_mem_err_compact cmem;
418 char rcd_decode_str[CPER_REC_LEN];
419
420 /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
421 if (len == sizeof(struct cper_sec_mem_err_old) &&
422 (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
423 pr_err(FW_WARN "valid bits set for fields beyond structure\n");
424 return;
425 }
426 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
427 printk("%s error_status: %s (0x%016llx)\n",
428 pfx, cper_mem_err_status_str(mem->error_status),
429 mem->error_status);
430 if (mem->validation_bits & CPER_MEM_VALID_PA)
431 printk("%s""physical_address: 0x%016llx\n",
432 pfx, mem->physical_addr);
433 if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
434 printk("%s""physical_address_mask: 0x%016llx\n",
435 pfx, mem->physical_addr_mask);
436 cper_mem_err_pack(mem, &cmem);
437 if (cper_mem_err_location(&cmem, rcd_decode_str))
438 printk("%s%s\n", pfx, rcd_decode_str);
439 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
440 u8 etype = mem->error_type;
441 printk("%s""error_type: %d, %s\n", pfx, etype,
442 cper_mem_err_type_str(etype));
443 }
444 if (cper_dimm_err_location(&cmem, rcd_decode_str))
445 printk("%s%s\n", pfx, rcd_decode_str);
446 }
447
448 static const char * const pcie_port_type_strs[] = {
449 "PCIe end point",
450 "legacy PCI end point",
451 "unknown",
452 "unknown",
453 "root port",
454 "upstream switch port",
455 "downstream switch port",
456 "PCIe to PCI/PCI-X bridge",
457 "PCI/PCI-X to PCIe bridge",
458 "root complex integrated endpoint device",
459 "root complex event collector",
460 };
461
cper_print_pcie(const char * pfx,const struct cper_sec_pcie * pcie,const struct acpi_hest_generic_data * gdata)462 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
463 const struct acpi_hest_generic_data *gdata)
464 {
465 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
466 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
467 pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
468 pcie_port_type_strs[pcie->port_type] : "unknown");
469 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
470 printk("%s""version: %d.%d\n", pfx,
471 pcie->version.major, pcie->version.minor);
472 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
473 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
474 pcie->command, pcie->status);
475 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
476 const __u8 *p;
477 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
478 pcie->device_id.segment, pcie->device_id.bus,
479 pcie->device_id.device, pcie->device_id.function);
480 printk("%s""slot: %d\n", pfx,
481 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
482 printk("%s""secondary_bus: 0x%02x\n", pfx,
483 pcie->device_id.secondary_bus);
484 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
485 pcie->device_id.vendor_id, pcie->device_id.device_id);
486 p = pcie->device_id.class_code;
487 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
488 }
489 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
490 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
491 pcie->serial_number.lower, pcie->serial_number.upper);
492 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
493 printk(
494 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
495 pfx, pcie->bridge.secondary_status, pcie->bridge.control);
496
497 /*
498 * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time).
499 *
500 * Fatal errors call __ghes_panic() before AER handler prints this.
501 */
502 if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
503 struct aer_capability_regs *aer;
504
505 aer = (struct aer_capability_regs *)pcie->aer_info;
506 printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n",
507 pfx, aer->cor_status, aer->cor_mask);
508 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
509 pfx, aer->uncor_status, aer->uncor_mask);
510 printk("%saer_uncor_severity: 0x%08x\n",
511 pfx, aer->uncor_severity);
512 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
513 aer->header_log.dw[0], aer->header_log.dw[1],
514 aer->header_log.dw[2], aer->header_log.dw[3]);
515 }
516 }
517
518 static const char * const fw_err_rec_type_strs[] = {
519 "IPF SAL Error Record",
520 "SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
521 "SOC Firmware Error Record Type2",
522 };
523
cper_print_fw_err(const char * pfx,struct acpi_hest_generic_data * gdata,const struct cper_sec_fw_err_rec_ref * fw_err)524 static void cper_print_fw_err(const char *pfx,
525 struct acpi_hest_generic_data *gdata,
526 const struct cper_sec_fw_err_rec_ref *fw_err)
527 {
528 void *buf = acpi_hest_get_payload(gdata);
529 u32 offset, length = gdata->error_data_length;
530
531 printk("%s""Firmware Error Record Type: %s\n", pfx,
532 fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
533 fw_err_rec_type_strs[fw_err->record_type] : "unknown");
534 printk("%s""Revision: %d\n", pfx, fw_err->revision);
535
536 /* Record Type based on UEFI 2.7 */
537 if (fw_err->revision == 0) {
538 printk("%s""Record Identifier: %08llx\n", pfx,
539 fw_err->record_identifier);
540 } else if (fw_err->revision == 2) {
541 printk("%s""Record Identifier: %pUl\n", pfx,
542 &fw_err->record_identifier_guid);
543 }
544
545 /*
546 * The FW error record may contain trailing data beyond the
547 * structure defined by the specification. As the fields
548 * defined (and hence the offset of any trailing data) vary
549 * with the revision, set the offset to account for this
550 * variation.
551 */
552 if (fw_err->revision == 0) {
553 /* record_identifier_guid not defined */
554 offset = offsetof(struct cper_sec_fw_err_rec_ref,
555 record_identifier_guid);
556 } else if (fw_err->revision == 1) {
557 /* record_identifier not defined */
558 offset = offsetof(struct cper_sec_fw_err_rec_ref,
559 record_identifier);
560 } else {
561 offset = sizeof(*fw_err);
562 }
563 if (offset > length) {
564 printk("%s""error section length is too small: offset=%d, length=%d\n",
565 pfx, offset, length);
566 return;
567 }
568
569 buf += offset;
570 length -= offset;
571
572 print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
573 }
574
cper_print_tstamp(const char * pfx,struct acpi_hest_generic_data_v300 * gdata)575 static void cper_print_tstamp(const char *pfx,
576 struct acpi_hest_generic_data_v300 *gdata)
577 {
578 __u8 hour, min, sec, day, mon, year, century, *timestamp;
579
580 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
581 timestamp = (__u8 *)&(gdata->time_stamp);
582 sec = bcd2bin(timestamp[0]);
583 min = bcd2bin(timestamp[1]);
584 hour = bcd2bin(timestamp[2]);
585 day = bcd2bin(timestamp[4]);
586 mon = bcd2bin(timestamp[5]);
587 year = bcd2bin(timestamp[6]);
588 century = bcd2bin(timestamp[7]);
589
590 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
591 (timestamp[3] & 0x1 ? "precise " : "imprecise "),
592 century, year, mon, day, hour, min, sec);
593 }
594 }
595
596 struct ignore_section {
597 guid_t guid;
598 const char *name;
599 };
600
601 static const struct ignore_section ignore_sections[] = {
602 { .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" },
603 { .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" },
604 { .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" },
605 };
606
607 static void
cper_estatus_print_section(const char * pfx,struct acpi_hest_generic_data * gdata,int sec_no)608 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
609 int sec_no)
610 {
611 guid_t *sec_type = (guid_t *)gdata->section_type;
612 __u16 severity;
613 char newpfx[64];
614
615 if (acpi_hest_get_version(gdata) >= 3)
616 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
617
618 severity = gdata->error_severity;
619 printk("%s""Error %d, type: %s\n", pfx, sec_no,
620 cper_severity_str(severity));
621 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
622 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
623 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
624 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
625
626 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
627
628 for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) {
629 if (guid_equal(sec_type, &ignore_sections[i].guid)) {
630 printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name);
631 return;
632 }
633 }
634
635 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
636 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
637
638 printk("%s""section_type: general processor error\n", newpfx);
639 if (gdata->error_data_length >= sizeof(*proc_err))
640 cper_print_proc_generic(newpfx, proc_err);
641 else
642 goto err_section_too_small;
643 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
644 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
645
646 printk("%s""section_type: memory error\n", newpfx);
647 if (gdata->error_data_length >=
648 sizeof(struct cper_sec_mem_err_old))
649 cper_print_mem(newpfx, mem_err,
650 gdata->error_data_length);
651 else
652 goto err_section_too_small;
653 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
654 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
655
656 printk("%s""section_type: PCIe error\n", newpfx);
657 if (gdata->error_data_length >= sizeof(*pcie))
658 cper_print_pcie(newpfx, pcie, gdata);
659 else
660 goto err_section_too_small;
661 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
662 } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
663 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
664
665 printk("%ssection_type: ARM processor error\n", newpfx);
666 if (gdata->error_data_length >= sizeof(*arm_err))
667 cper_print_proc_arm(newpfx, arm_err,
668 gdata->error_data_length);
669 else
670 goto err_section_too_small;
671 #endif
672 #if defined(CONFIG_UEFI_CPER_X86)
673 } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
674 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
675
676 printk("%ssection_type: IA32/X64 processor error\n", newpfx);
677 if (gdata->error_data_length >= sizeof(*ia_err))
678 cper_print_proc_ia(newpfx, ia_err);
679 else
680 goto err_section_too_small;
681 #endif
682 } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
683 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
684
685 printk("%ssection_type: Firmware Error Record Reference\n",
686 newpfx);
687 /* The minimal FW Error Record contains 16 bytes */
688 if (gdata->error_data_length >= SZ_16)
689 cper_print_fw_err(newpfx, gdata, fw_err);
690 else
691 goto err_section_too_small;
692 } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
693 struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
694
695 printk("%ssection_type: CXL Protocol Error\n", newpfx);
696 if (gdata->error_data_length >= sizeof(*prot_err))
697 cxl_cper_print_prot_err(newpfx, prot_err);
698 else
699 goto err_section_too_small;
700 } else {
701 const void *err = acpi_hest_get_payload(gdata);
702
703 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
704 printk("%ssection length: %#x\n", newpfx,
705 gdata->error_data_length);
706 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
707 gdata->error_data_length, true);
708 }
709
710 return;
711
712 err_section_too_small:
713 pr_err(FW_WARN "error section length is too small\n");
714 }
715
cper_estatus_print(const char * pfx,const struct acpi_hest_generic_status * estatus)716 void cper_estatus_print(const char *pfx,
717 const struct acpi_hest_generic_status *estatus)
718 {
719 struct acpi_hest_generic_data *gdata;
720 int sec_no = 0;
721 char newpfx[64];
722 __u16 severity;
723
724 severity = estatus->error_severity;
725 if (severity == CPER_SEV_CORRECTED)
726 printk("%s%s\n", pfx,
727 "It has been corrected by h/w "
728 "and requires no further action");
729 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
730 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
731
732 apei_estatus_for_each_section(estatus, gdata) {
733 cper_estatus_print_section(newpfx, gdata, sec_no);
734 sec_no++;
735 }
736 }
737 EXPORT_SYMBOL_GPL(cper_estatus_print);
738
cper_estatus_check_header(const struct acpi_hest_generic_status * estatus)739 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
740 {
741 if (estatus->data_length &&
742 estatus->data_length < sizeof(struct acpi_hest_generic_data))
743 return -EINVAL;
744 if (estatus->raw_data_length &&
745 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
746 return -EINVAL;
747
748 return 0;
749 }
750 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
751
cper_estatus_check(const struct acpi_hest_generic_status * estatus)752 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
753 {
754 struct acpi_hest_generic_data *gdata;
755 unsigned int data_len, record_size;
756 int rc;
757
758 rc = cper_estatus_check_header(estatus);
759 if (rc)
760 return rc;
761
762 data_len = estatus->data_length;
763
764 apei_estatus_for_each_section(estatus, gdata) {
765 if (acpi_hest_get_size(gdata) > data_len)
766 return -EINVAL;
767
768 record_size = acpi_hest_get_record_size(gdata);
769 if (record_size > data_len)
770 return -EINVAL;
771
772 data_len -= record_size;
773 }
774 if (data_len)
775 return -EINVAL;
776
777 return 0;
778 }
779 EXPORT_SYMBOL_GPL(cper_estatus_check);
780