Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/cper.c
26428 views
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 <cxl/event.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 cxl_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
cxl_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);
714
715