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