1
2
3
4
5
6
7
8
9
10
11
12
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
28
29
30
31
32
33u64 cper_next_record_id(void)
34{
35 static atomic64_t seq;
36
37 if (!atomic64_read(&seq)) {
38 time64_t time = ktime_get_real_seconds();
39
40
41
42
43
44
45
46 if (time < 0x80000000)
47 atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
48 else
49 atomic64_set(&seq, 0x8000000000000000ull |
50 ktime_get_real_seconds() << 24);
51 }
52
53 return atomic64_inc_return(&seq);
54}
55EXPORT_SYMBOL_GPL(cper_next_record_id);
56
57static const char * const severity_strs[] = {
58 "recoverable",
59 "fatal",
60 "corrected",
61 "info",
62};
63
64const char *cper_severity_str(unsigned int severity)
65{
66 return severity < ARRAY_SIZE(severity_strs) ?
67 severity_strs[severity] : "unknown";
68}
69EXPORT_SYMBOL_GPL(cper_severity_str);
70
71
72
73
74
75
76
77
78
79
80
81
82void cper_print_bits(const char *pfx, unsigned int bits,
83 const char * const strs[], unsigned int strs_size)
84{
85 int i, len = 0;
86 const char *str;
87 char buf[84];
88
89 for (i = 0; i < strs_size; i++) {
90 if (!(bits & (1U << i)))
91 continue;
92 str = strs[i];
93 if (!str)
94 continue;
95 if (len && len + strlen(str) + 2 > 80) {
96 printk("%s\n", buf);
97 len = 0;
98 }
99 if (!len)
100 len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
101 else
102 len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
103 }
104 if (len)
105 printk("%s\n", buf);
106}
107
108static const char * const proc_type_strs[] = {
109 "IA32/X64",
110 "IA64",
111 "ARM",
112};
113
114static const char * const proc_isa_strs[] = {
115 "IA32",
116 "IA64",
117 "X64",
118 "ARM A32/T32",
119 "ARM A64",
120};
121
122const char * const cper_proc_error_type_strs[] = {
123 "cache error",
124 "TLB error",
125 "bus error",
126 "micro-architectural error",
127};
128
129static const char * const proc_op_strs[] = {
130 "unknown or generic",
131 "data read",
132 "data write",
133 "instruction execution",
134};
135
136static const char * const proc_flag_strs[] = {
137 "restartable",
138 "precise IP",
139 "overflow",
140 "corrected",
141};
142
143static void cper_print_proc_generic(const char *pfx,
144 const struct cper_sec_proc_generic *proc)
145{
146 if (proc->validation_bits & CPER_PROC_VALID_TYPE)
147 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
148 proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
149 proc_type_strs[proc->proc_type] : "unknown");
150 if (proc->validation_bits & CPER_PROC_VALID_ISA)
151 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
152 proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
153 proc_isa_strs[proc->proc_isa] : "unknown");
154 if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
155 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
156 cper_print_bits(pfx, proc->proc_error_type,
157 cper_proc_error_type_strs,
158 ARRAY_SIZE(cper_proc_error_type_strs));
159 }
160 if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
161 printk("%s""operation: %d, %s\n", pfx, proc->operation,
162 proc->operation < ARRAY_SIZE(proc_op_strs) ?
163 proc_op_strs[proc->operation] : "unknown");
164 if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
165 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
166 cper_print_bits(pfx, proc->flags, proc_flag_strs,
167 ARRAY_SIZE(proc_flag_strs));
168 }
169 if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
170 printk("%s""level: %d\n", pfx, proc->level);
171 if (proc->validation_bits & CPER_PROC_VALID_VERSION)
172 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
173 if (proc->validation_bits & CPER_PROC_VALID_ID)
174 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
175 if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
176 printk("%s""target_address: 0x%016llx\n",
177 pfx, proc->target_addr);
178 if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
179 printk("%s""requestor_id: 0x%016llx\n",
180 pfx, proc->requestor_id);
181 if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
182 printk("%s""responder_id: 0x%016llx\n",
183 pfx, proc->responder_id);
184 if (proc->validation_bits & CPER_PROC_VALID_IP)
185 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
186}
187
188static const char * const mem_err_type_strs[] = {
189 "unknown",
190 "no error",
191 "single-bit ECC",
192 "multi-bit ECC",
193 "single-symbol chipkill ECC",
194 "multi-symbol chipkill ECC",
195 "master abort",
196 "target abort",
197 "parity error",
198 "watchdog timeout",
199 "invalid address",
200 "mirror Broken",
201 "memory sparing",
202 "scrub corrected error",
203 "scrub uncorrected error",
204 "physical memory map-out event",
205};
206
207const char *cper_mem_err_type_str(unsigned int etype)
208{
209 return etype < ARRAY_SIZE(mem_err_type_strs) ?
210 mem_err_type_strs[etype] : "unknown";
211}
212EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
213
214static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
215{
216 u32 len, n;
217
218 if (!msg)
219 return 0;
220
221 n = 0;
222 len = CPER_REC_LEN;
223 if (mem->validation_bits & CPER_MEM_VALID_NODE)
224 n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
225 if (mem->validation_bits & CPER_MEM_VALID_CARD)
226 n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
227 if (mem->validation_bits & CPER_MEM_VALID_MODULE)
228 n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
229 if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
230 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
231 if (mem->validation_bits & CPER_MEM_VALID_BANK)
232 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
233 if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
234 n += scnprintf(msg + n, len - n, "bank_group: %d ",
235 mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
236 if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
237 n += scnprintf(msg + n, len - n, "bank_address: %d ",
238 mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
239 if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
240 n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
241 if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
242 u32 row = mem->row;
243
244 row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
245 n += scnprintf(msg + n, len - n, "row: %d ", row);
246 }
247 if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
248 n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
249 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
250 n += scnprintf(msg + n, len - n, "bit_position: %d ",
251 mem->bit_pos);
252 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
253 n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
254 mem->requestor_id);
255 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
256 n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
257 mem->responder_id);
258 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
259 n += scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
260 mem->target_id);
261 if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
262 n += scnprintf(msg + n, len - n, "chip_id: %d ",
263 mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
264
265 return n;
266}
267
268static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
269{
270 u32 len, n;
271 const char *bank = NULL, *device = NULL;
272
273 if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
274 return 0;
275
276 len = CPER_REC_LEN;
277 dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
278 if (bank && device)
279 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
280 else
281 n = snprintf(msg, len,
282 "DIMM location: not present. DMI handle: 0x%.4x ",
283 mem->mem_dev_handle);
284
285 return n;
286}
287
288void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
289 struct cper_mem_err_compact *cmem)
290{
291 cmem->validation_bits = mem->validation_bits;
292 cmem->node = mem->node;
293 cmem->card = mem->card;
294 cmem->module = mem->module;
295 cmem->bank = mem->bank;
296 cmem->device = mem->device;
297 cmem->row = mem->row;
298 cmem->column = mem->column;
299 cmem->bit_pos = mem->bit_pos;
300 cmem->requestor_id = mem->requestor_id;
301 cmem->responder_id = mem->responder_id;
302 cmem->target_id = mem->target_id;
303 cmem->extended = mem->extended;
304 cmem->rank = mem->rank;
305 cmem->mem_array_handle = mem->mem_array_handle;
306 cmem->mem_dev_handle = mem->mem_dev_handle;
307}
308
309const char *cper_mem_err_unpack(struct trace_seq *p,
310 struct cper_mem_err_compact *cmem)
311{
312 const char *ret = trace_seq_buffer_ptr(p);
313 char rcd_decode_str[CPER_REC_LEN];
314
315 if (cper_mem_err_location(cmem, rcd_decode_str))
316 trace_seq_printf(p, "%s", rcd_decode_str);
317 if (cper_dimm_err_location(cmem, rcd_decode_str))
318 trace_seq_printf(p, "%s", rcd_decode_str);
319 trace_seq_putc(p, '\0');
320
321 return ret;
322}
323
324static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
325 int len)
326{
327 struct cper_mem_err_compact cmem;
328 char rcd_decode_str[CPER_REC_LEN];
329
330
331 if (len == sizeof(struct cper_sec_mem_err_old) &&
332 (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
333 pr_err(FW_WARN "valid bits set for fields beyond structure\n");
334 return;
335 }
336 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
337 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
338 if (mem->validation_bits & CPER_MEM_VALID_PA)
339 printk("%s""physical_address: 0x%016llx\n",
340 pfx, mem->physical_addr);
341 if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
342 printk("%s""physical_address_mask: 0x%016llx\n",
343 pfx, mem->physical_addr_mask);
344 cper_mem_err_pack(mem, &cmem);
345 if (cper_mem_err_location(&cmem, rcd_decode_str))
346 printk("%s%s\n", pfx, rcd_decode_str);
347 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
348 u8 etype = mem->error_type;
349 printk("%s""error_type: %d, %s\n", pfx, etype,
350 cper_mem_err_type_str(etype));
351 }
352 if (cper_dimm_err_location(&cmem, rcd_decode_str))
353 printk("%s%s\n", pfx, rcd_decode_str);
354}
355
356static const char * const pcie_port_type_strs[] = {
357 "PCIe end point",
358 "legacy PCI end point",
359 "unknown",
360 "unknown",
361 "root port",
362 "upstream switch port",
363 "downstream switch port",
364 "PCIe to PCI/PCI-X bridge",
365 "PCI/PCI-X to PCIe bridge",
366 "root complex integrated endpoint device",
367 "root complex event collector",
368};
369
370static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
371 const struct acpi_hest_generic_data *gdata)
372{
373 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
374 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
375 pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
376 pcie_port_type_strs[pcie->port_type] : "unknown");
377 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
378 printk("%s""version: %d.%d\n", pfx,
379 pcie->version.major, pcie->version.minor);
380 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
381 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
382 pcie->command, pcie->status);
383 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
384 const __u8 *p;
385 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
386 pcie->device_id.segment, pcie->device_id.bus,
387 pcie->device_id.device, pcie->device_id.function);
388 printk("%s""slot: %d\n", pfx,
389 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
390 printk("%s""secondary_bus: 0x%02x\n", pfx,
391 pcie->device_id.secondary_bus);
392 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
393 pcie->device_id.vendor_id, pcie->device_id.device_id);
394 p = pcie->device_id.class_code;
395 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
396 }
397 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
398 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
399 pcie->serial_number.lower, pcie->serial_number.upper);
400 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
401 printk(
402 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
403 pfx, pcie->bridge.secondary_status, pcie->bridge.control);
404
405
406 if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
407 (gdata->error_severity & CPER_SEV_FATAL)) {
408 struct aer_capability_regs *aer;
409
410 aer = (struct aer_capability_regs *)pcie->aer_info;
411 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
412 pfx, aer->uncor_status, aer->uncor_mask);
413 printk("%saer_uncor_severity: 0x%08x\n",
414 pfx, aer->uncor_severity);
415 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
416 aer->header_log.dw0, aer->header_log.dw1,
417 aer->header_log.dw2, aer->header_log.dw3);
418 }
419}
420
421static const char * const fw_err_rec_type_strs[] = {
422 "IPF SAL Error Record",
423 "SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
424 "SOC Firmware Error Record Type2",
425};
426
427static void cper_print_fw_err(const char *pfx,
428 struct acpi_hest_generic_data *gdata,
429 const struct cper_sec_fw_err_rec_ref *fw_err)
430{
431 void *buf = acpi_hest_get_payload(gdata);
432 u32 offset, length = gdata->error_data_length;
433
434 printk("%s""Firmware Error Record Type: %s\n", pfx,
435 fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
436 fw_err_rec_type_strs[fw_err->record_type] : "unknown");
437 printk("%s""Revision: %d\n", pfx, fw_err->revision);
438
439
440 if (fw_err->revision == 0) {
441 printk("%s""Record Identifier: %08llx\n", pfx,
442 fw_err->record_identifier);
443 } else if (fw_err->revision == 2) {
444 printk("%s""Record Identifier: %pUl\n", pfx,
445 &fw_err->record_identifier_guid);
446 }
447
448
449
450
451
452
453
454
455 if (fw_err->revision == 0) {
456
457 offset = offsetof(struct cper_sec_fw_err_rec_ref,
458 record_identifier_guid);
459 } else if (fw_err->revision == 1) {
460
461 offset = offsetof(struct cper_sec_fw_err_rec_ref,
462 record_identifier);
463 } else {
464 offset = sizeof(*fw_err);
465 }
466
467 buf += offset;
468 length -= offset;
469
470 print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
471}
472
473static void cper_print_tstamp(const char *pfx,
474 struct acpi_hest_generic_data_v300 *gdata)
475{
476 __u8 hour, min, sec, day, mon, year, century, *timestamp;
477
478 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
479 timestamp = (__u8 *)&(gdata->time_stamp);
480 sec = bcd2bin(timestamp[0]);
481 min = bcd2bin(timestamp[1]);
482 hour = bcd2bin(timestamp[2]);
483 day = bcd2bin(timestamp[4]);
484 mon = bcd2bin(timestamp[5]);
485 year = bcd2bin(timestamp[6]);
486 century = bcd2bin(timestamp[7]);
487
488 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
489 (timestamp[3] & 0x1 ? "precise " : "imprecise "),
490 century, year, mon, day, hour, min, sec);
491 }
492}
493
494static void
495cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
496 int sec_no)
497{
498 guid_t *sec_type = (guid_t *)gdata->section_type;
499 __u16 severity;
500 char newpfx[64];
501
502 if (acpi_hest_get_version(gdata) >= 3)
503 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
504
505 severity = gdata->error_severity;
506 printk("%s""Error %d, type: %s\n", pfx, sec_no,
507 cper_severity_str(severity));
508 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
509 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
510 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
511 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
512
513 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
514 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
515 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
516
517 printk("%s""section_type: general processor error\n", newpfx);
518 if (gdata->error_data_length >= sizeof(*proc_err))
519 cper_print_proc_generic(newpfx, proc_err);
520 else
521 goto err_section_too_small;
522 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
523 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
524
525 printk("%s""section_type: memory error\n", newpfx);
526 if (gdata->error_data_length >=
527 sizeof(struct cper_sec_mem_err_old))
528 cper_print_mem(newpfx, mem_err,
529 gdata->error_data_length);
530 else
531 goto err_section_too_small;
532 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
533 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
534
535 printk("%s""section_type: PCIe error\n", newpfx);
536 if (gdata->error_data_length >= sizeof(*pcie))
537 cper_print_pcie(newpfx, pcie, gdata);
538 else
539 goto err_section_too_small;
540#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
541 } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
542 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
543
544 printk("%ssection_type: ARM processor error\n", newpfx);
545 if (gdata->error_data_length >= sizeof(*arm_err))
546 cper_print_proc_arm(newpfx, arm_err);
547 else
548 goto err_section_too_small;
549#endif
550#if defined(CONFIG_UEFI_CPER_X86)
551 } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
552 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
553
554 printk("%ssection_type: IA32/X64 processor error\n", newpfx);
555 if (gdata->error_data_length >= sizeof(*ia_err))
556 cper_print_proc_ia(newpfx, ia_err);
557 else
558 goto err_section_too_small;
559#endif
560 } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
561 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
562
563 printk("%ssection_type: Firmware Error Record Reference\n",
564 newpfx);
565
566 if (gdata->error_data_length >= SZ_16)
567 cper_print_fw_err(newpfx, gdata, fw_err);
568 else
569 goto err_section_too_small;
570 } else {
571 const void *err = acpi_hest_get_payload(gdata);
572
573 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
574 printk("%ssection length: %#x\n", newpfx,
575 gdata->error_data_length);
576 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
577 gdata->error_data_length, true);
578 }
579
580 return;
581
582err_section_too_small:
583 pr_err(FW_WARN "error section length is too small\n");
584}
585
586void cper_estatus_print(const char *pfx,
587 const struct acpi_hest_generic_status *estatus)
588{
589 struct acpi_hest_generic_data *gdata;
590 int sec_no = 0;
591 char newpfx[64];
592 __u16 severity;
593
594 severity = estatus->error_severity;
595 if (severity == CPER_SEV_CORRECTED)
596 printk("%s%s\n", pfx,
597 "It has been corrected by h/w "
598 "and requires no further action");
599 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
600 snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
601
602 apei_estatus_for_each_section(estatus, gdata) {
603 cper_estatus_print_section(newpfx, gdata, sec_no);
604 sec_no++;
605 }
606}
607EXPORT_SYMBOL_GPL(cper_estatus_print);
608
609int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
610{
611 if (estatus->data_length &&
612 estatus->data_length < sizeof(struct acpi_hest_generic_data))
613 return -EINVAL;
614 if (estatus->raw_data_length &&
615 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
616 return -EINVAL;
617
618 return 0;
619}
620EXPORT_SYMBOL_GPL(cper_estatus_check_header);
621
622int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
623{
624 struct acpi_hest_generic_data *gdata;
625 unsigned int data_len, record_size;
626 int rc;
627
628 rc = cper_estatus_check_header(estatus);
629 if (rc)
630 return rc;
631
632 data_len = estatus->data_length;
633
634 apei_estatus_for_each_section(estatus, gdata) {
635 if (acpi_hest_get_size(gdata) > data_len)
636 return -EINVAL;
637
638 record_size = acpi_hest_get_record_size(gdata);
639 if (record_size > data_len)
640 return -EINVAL;
641
642 data_len -= record_size;
643 }
644 if (data_len)
645 return -EINVAL;
646
647 return 0;
648}
649EXPORT_SYMBOL_GPL(cper_estatus_check);
650