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
564 buf += offset;
565 length -= offset;
566
567 print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
568 }
569
cper_print_tstamp(const char * pfx,struct acpi_hest_generic_data_v300 * gdata)570 static void cper_print_tstamp(const char *pfx,
571 struct acpi_hest_generic_data_v300 *gdata)
572 {
573 __u8 hour, min, sec, day, mon, year, century, *timestamp;
574
575 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
576 timestamp = (__u8 *)&(gdata->time_stamp);
577 sec = bcd2bin(timestamp[0]);
578 min = bcd2bin(timestamp[1]);
579 hour = bcd2bin(timestamp[2]);
580 day = bcd2bin(timestamp[4]);
581 mon = bcd2bin(timestamp[5]);
582 year = bcd2bin(timestamp[6]);
583 century = bcd2bin(timestamp[7]);
584
585 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
586 (timestamp[3] & 0x1 ? "precise " : "imprecise "),
587 century, year, mon, day, hour, min, sec);
588 }
589 }
590
591 struct ignore_section {
592 guid_t guid;
593 const char *name;
594 };
595
596 static const struct ignore_section ignore_sections[] = {
597 { .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" },
598 { .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" },
599 { .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" },
600 };
601
602 static void
cper_estatus_print_section(const char * pfx,struct acpi_hest_generic_data * gdata,int sec_no)603 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
604 int sec_no)
605 {
606 guid_t *sec_type = (guid_t *)gdata->section_type;
607 __u16 severity;
608 char newpfx[64];
609
610 if (acpi_hest_get_version(gdata) >= 3)
611 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
612
613 severity = gdata->error_severity;
614 printk("%s""Error %d, type: %s\n", pfx, sec_no,
615 cper_severity_str(severity));
616 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
617 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
618 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
619 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
620
621 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
622
623 for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) {
624 if (guid_equal(sec_type, &ignore_sections[i].guid)) {
625 printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name);
626 return;
627 }
628 }
629
630 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
631 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
632
633 printk("%s""section_type: general processor error\n", newpfx);
634 if (gdata->error_data_length >= sizeof(*proc_err))
635 cper_print_proc_generic(newpfx, proc_err);
636 else
637 goto err_section_too_small;
638 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
639 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
640
641 printk("%s""section_type: memory error\n", newpfx);
642 if (gdata->error_data_length >=
643 sizeof(struct cper_sec_mem_err_old))
644 cper_print_mem(newpfx, mem_err,
645 gdata->error_data_length);
646 else
647 goto err_section_too_small;
648 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
649 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
650
651 printk("%s""section_type: PCIe error\n", newpfx);
652 if (gdata->error_data_length >= sizeof(*pcie))
653 cper_print_pcie(newpfx, pcie, gdata);
654 else
655 goto err_section_too_small;
656 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
657 } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
658 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
659
660 printk("%ssection_type: ARM processor error\n", newpfx);
661 if (gdata->error_data_length >= sizeof(*arm_err))
662 cper_print_proc_arm(newpfx, arm_err);
663 else
664 goto err_section_too_small;
665 #endif
666 #if defined(CONFIG_UEFI_CPER_X86)
667 } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
668 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
669
670 printk("%ssection_type: IA32/X64 processor error\n", newpfx);
671 if (gdata->error_data_length >= sizeof(*ia_err))
672 cper_print_proc_ia(newpfx, ia_err);
673 else
674 goto err_section_too_small;
675 #endif
676 } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
677 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
678
679 printk("%ssection_type: Firmware Error Record Reference\n",
680 newpfx);
681 /* The minimal FW Error Record contains 16 bytes */
682 if (gdata->error_data_length >= SZ_16)
683 cper_print_fw_err(newpfx, gdata, fw_err);
684 else
685 goto err_section_too_small;
686 } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
687 struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
688
689 printk("%ssection_type: CXL Protocol Error\n", newpfx);
690 if (gdata->error_data_length >= sizeof(*prot_err))
691 cxl_cper_print_prot_err(newpfx, prot_err);
692 else
693 goto err_section_too_small;
694 } else {
695 const void *err = acpi_hest_get_payload(gdata);
696
697 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
698 printk("%ssection length: %#x\n", newpfx,
699 gdata->error_data_length);
700 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
701 gdata->error_data_length, true);
702 }
703
704 return;
705
706 err_section_too_small:
707 pr_err(FW_WARN "error section length is too small\n");
708 }
709
cper_estatus_print(const char * pfx,const struct acpi_hest_generic_status * estatus)710 void cper_estatus_print(const char *pfx,
711 const struct acpi_hest_generic_status *estatus)
712 {
713 struct acpi_hest_generic_data *gdata;
714 int sec_no = 0;
715 char newpfx[64];
716 __u16 severity;
717
718 severity = estatus->error_severity;
719 if (severity == CPER_SEV_CORRECTED)
720 printk("%s%s\n", pfx,
721 "It has been corrected by h/w "
722 "and requires no further action");
723 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
724 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
725
726 apei_estatus_for_each_section(estatus, gdata) {
727 cper_estatus_print_section(newpfx, gdata, sec_no);
728 sec_no++;
729 }
730 }
731 EXPORT_SYMBOL_GPL(cper_estatus_print);
732
cper_estatus_check_header(const struct acpi_hest_generic_status * estatus)733 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
734 {
735 if (estatus->data_length &&
736 estatus->data_length < sizeof(struct acpi_hest_generic_data))
737 return -EINVAL;
738 if (estatus->raw_data_length &&
739 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
740 return -EINVAL;
741
742 return 0;
743 }
744 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
745
cper_estatus_check(const struct acpi_hest_generic_status * estatus)746 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
747 {
748 struct acpi_hest_generic_data *gdata;
749 unsigned int data_len, record_size;
750 int rc;
751
752 rc = cper_estatus_check_header(estatus);
753 if (rc)
754 return rc;
755
756 data_len = estatus->data_length;
757
758 apei_estatus_for_each_section(estatus, gdata) {
759 if (acpi_hest_get_size(gdata) > data_len)
760 return -EINVAL;
761
762 record_size = acpi_hest_get_record_size(gdata);
763 if (record_size > data_len)
764 return -EINVAL;
765
766 data_len -= record_size;
767 }
768 if (data_len)
769 return -EINVAL;
770
771 return 0;
772 }
773 EXPORT_SYMBOL_GPL(cper_estatus_check);
774