2 * UEFI Common Platform Error Record (CPER) support
4 * Copyright (C) 2010, Intel Corp.
5 * Author: Huang Ying <ying.huang@intel.com>
7 * CPER is the format used to describe platform hardware error by
8 * various tables, such as ERST, BERT and HEST etc.
10 * For more information about CPER, please refer to Appendix N of UEFI
11 * Specification version 2.4.
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.
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.
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
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>
43 * CPER record ID need to be unique even after reboot, because record
44 * ID is used as index for ERST storage, while CPER records from
45 * multiple boot may co-exist in ERST.
47 u64 cper_next_record_id(void)
49 static atomic64_t seq;
51 if (!atomic64_read(&seq))
52 atomic64_set(&seq, ((u64)get_seconds()) << 32);
54 return atomic64_inc_return(&seq);
56 EXPORT_SYMBOL_GPL(cper_next_record_id);
58 static const char * const severity_strs[] = {
65 const char *cper_severity_str(unsigned int severity)
67 return severity < ARRAY_SIZE(severity_strs) ?
68 severity_strs[severity] : "unknown";
70 EXPORT_SYMBOL_GPL(cper_severity_str);
73 * cper_print_bits - print strings for set bits
74 * @pfx: prefix for each line, including log level and prefix string
76 * @strs: string array, indexed by bit position
77 * @strs_size: size of the string array: @strs
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.
83 void cper_print_bits(const char *pfx, unsigned int bits,
84 const char * const strs[], unsigned int strs_size)
90 for (i = 0; i < strs_size; i++) {
91 if (!(bits & (1U << i)))
96 if (len && len + strlen(str) + 2 > 80) {
101 len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
103 len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
109 static const char * const proc_type_strs[] = {
115 static const char * const proc_isa_strs[] = {
123 static const char * const proc_error_type_strs[] = {
127 "micro-architectural error",
130 static const char * const proc_op_strs[] = {
131 "unknown or generic",
134 "instruction execution",
137 static const char * const proc_flag_strs[] = {
144 static void cper_print_proc_generic(const char *pfx,
145 const struct cper_sec_proc_generic *proc)
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 proc_error_type_strs,
159 ARRAY_SIZE(proc_error_type_strs));
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));
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);
189 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
190 static const char * const arm_reg_ctx_strs[] = {
191 "AArch32 general purpose registers",
192 "AArch32 EL1 context registers",
193 "AArch32 EL2 context registers",
194 "AArch32 secure context registers",
195 "AArch64 general purpose registers",
196 "AArch64 EL1 context registers",
197 "AArch64 EL2 context registers",
198 "AArch64 EL3 context registers",
199 "Misc. system register structure",
202 static void cper_print_proc_arm(const char *pfx,
203 const struct cper_sec_proc_arm *proc)
205 int i, len, max_ctx_type;
206 struct cper_arm_err_info *err_info;
207 struct cper_arm_ctx_info *ctx_info;
210 printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
212 len = proc->section_length - (sizeof(*proc) +
213 proc->err_info_num * (sizeof(*err_info)));
215 printk("%ssection length: %d\n", pfx, proc->section_length);
216 printk("%ssection length is too small\n", pfx);
217 printk("%sfirmware-generated error record is incorrect\n", pfx);
218 printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
222 if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
223 printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
226 if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
227 printk("%serror affinity level: %d\n", pfx,
228 proc->affinity_level);
230 if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
231 printk("%srunning state: 0x%x\n", pfx, proc->running_state);
232 printk("%sPower State Coordination Interface state: %d\n",
233 pfx, proc->psci_state);
236 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
238 err_info = (struct cper_arm_err_info *)(proc + 1);
239 for (i = 0; i < proc->err_info_num; i++) {
240 printk("%sError info structure %d:\n", pfx, i);
242 printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
244 if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
245 if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
246 printk("%sfirst error captured\n", newpfx);
247 if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
248 printk("%slast error captured\n", newpfx);
249 if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
250 printk("%spropagated error captured\n",
252 if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
253 printk("%soverflow occurred, error info is incomplete\n",
257 printk("%serror_type: %d, %s\n", newpfx, err_info->type,
258 err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
259 proc_error_type_strs[err_info->type] : "unknown");
260 if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO)
261 printk("%serror_info: 0x%016llx\n", newpfx,
262 err_info->error_info);
263 if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
264 printk("%svirtual fault address: 0x%016llx\n",
265 newpfx, err_info->virt_fault_addr);
266 if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
267 printk("%sphysical fault address: 0x%016llx\n",
268 newpfx, err_info->physical_fault_addr);
272 ctx_info = (struct cper_arm_ctx_info *)err_info;
273 max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
274 for (i = 0; i < proc->context_info_num; i++) {
275 int size = sizeof(*ctx_info) + ctx_info->size;
277 printk("%sContext info structure %d:\n", pfx, i);
279 printk("%ssection length is too small\n", newpfx);
280 printk("%sfirmware-generated error record is incorrect\n", pfx);
283 if (ctx_info->type > max_ctx_type) {
284 printk("%sInvalid context type: %d (max: %d)\n",
285 newpfx, ctx_info->type, max_ctx_type);
288 printk("%sregister context type: %s\n", newpfx,
289 arm_reg_ctx_strs[ctx_info->type]);
290 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
291 (ctx_info + 1), ctx_info->size, 0);
293 ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
297 printk("%sVendor specific error info has %u bytes:\n", pfx,
299 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
305 static const char * const mem_err_type_strs[] = {
310 "single-symbol chipkill ECC",
311 "multi-symbol chipkill ECC",
319 "scrub corrected error",
320 "scrub uncorrected error",
321 "physical memory map-out event",
324 const char *cper_mem_err_type_str(unsigned int etype)
326 return etype < ARRAY_SIZE(mem_err_type_strs) ?
327 mem_err_type_strs[etype] : "unknown";
329 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
331 static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
339 len = CPER_REC_LEN - 1;
340 if (mem->validation_bits & CPER_MEM_VALID_NODE)
341 n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
342 if (mem->validation_bits & CPER_MEM_VALID_CARD)
343 n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
344 if (mem->validation_bits & CPER_MEM_VALID_MODULE)
345 n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
346 if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
347 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
348 if (mem->validation_bits & CPER_MEM_VALID_BANK)
349 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
350 if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
351 n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
352 if (mem->validation_bits & CPER_MEM_VALID_ROW)
353 n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
354 if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
355 n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
356 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
357 n += scnprintf(msg + n, len - n, "bit_position: %d ",
359 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
360 n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
362 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
363 n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
365 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
366 scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
373 static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
376 const char *bank = NULL, *device = NULL;
378 if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
382 dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
384 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
386 n = snprintf(msg, len,
387 "DIMM location: not present. DMI handle: 0x%.4x ",
388 mem->mem_dev_handle);
393 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
394 struct cper_mem_err_compact *cmem)
396 cmem->validation_bits = mem->validation_bits;
397 cmem->node = mem->node;
398 cmem->card = mem->card;
399 cmem->module = mem->module;
400 cmem->bank = mem->bank;
401 cmem->device = mem->device;
402 cmem->row = mem->row;
403 cmem->column = mem->column;
404 cmem->bit_pos = mem->bit_pos;
405 cmem->requestor_id = mem->requestor_id;
406 cmem->responder_id = mem->responder_id;
407 cmem->target_id = mem->target_id;
408 cmem->rank = mem->rank;
409 cmem->mem_array_handle = mem->mem_array_handle;
410 cmem->mem_dev_handle = mem->mem_dev_handle;
413 const char *cper_mem_err_unpack(struct trace_seq *p,
414 struct cper_mem_err_compact *cmem)
416 const char *ret = trace_seq_buffer_ptr(p);
417 char rcd_decode_str[CPER_REC_LEN];
419 if (cper_mem_err_location(cmem, rcd_decode_str))
420 trace_seq_printf(p, "%s", rcd_decode_str);
421 if (cper_dimm_err_location(cmem, rcd_decode_str))
422 trace_seq_printf(p, "%s", rcd_decode_str);
423 trace_seq_putc(p, '\0');
428 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
431 struct cper_mem_err_compact cmem;
432 char rcd_decode_str[CPER_REC_LEN];
434 /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
435 if (len == sizeof(struct cper_sec_mem_err_old) &&
436 (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
437 pr_err(FW_WARN "valid bits set for fields beyond structure\n");
440 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
441 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
442 if (mem->validation_bits & CPER_MEM_VALID_PA)
443 printk("%s""physical_address: 0x%016llx\n",
444 pfx, mem->physical_addr);
445 if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
446 printk("%s""physical_address_mask: 0x%016llx\n",
447 pfx, mem->physical_addr_mask);
448 cper_mem_err_pack(mem, &cmem);
449 if (cper_mem_err_location(&cmem, rcd_decode_str))
450 printk("%s%s\n", pfx, rcd_decode_str);
451 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
452 u8 etype = mem->error_type;
453 printk("%s""error_type: %d, %s\n", pfx, etype,
454 cper_mem_err_type_str(etype));
456 if (cper_dimm_err_location(&cmem, rcd_decode_str))
457 printk("%s%s\n", pfx, rcd_decode_str);
460 static const char * const pcie_port_type_strs[] = {
462 "legacy PCI end point",
466 "upstream switch port",
467 "downstream switch port",
468 "PCIe to PCI/PCI-X bridge",
469 "PCI/PCI-X to PCIe bridge",
470 "root complex integrated endpoint device",
471 "root complex event collector",
474 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
475 const struct acpi_hest_generic_data *gdata)
477 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
478 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
479 pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
480 pcie_port_type_strs[pcie->port_type] : "unknown");
481 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
482 printk("%s""version: %d.%d\n", pfx,
483 pcie->version.major, pcie->version.minor);
484 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
485 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
486 pcie->command, pcie->status);
487 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
489 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
490 pcie->device_id.segment, pcie->device_id.bus,
491 pcie->device_id.device, pcie->device_id.function);
492 printk("%s""slot: %d\n", pfx,
493 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
494 printk("%s""secondary_bus: 0x%02x\n", pfx,
495 pcie->device_id.secondary_bus);
496 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
497 pcie->device_id.vendor_id, pcie->device_id.device_id);
498 p = pcie->device_id.class_code;
499 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
501 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
502 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
503 pcie->serial_number.lower, pcie->serial_number.upper);
504 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
506 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
507 pfx, pcie->bridge.secondary_status, pcie->bridge.control);
509 /* Fatal errors call __ghes_panic() before AER handler prints this */
510 if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
511 (gdata->error_severity & CPER_SEV_FATAL)) {
512 struct aer_capability_regs *aer;
514 aer = (struct aer_capability_regs *)pcie->aer_info;
515 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
516 pfx, aer->uncor_status, aer->uncor_mask);
517 printk("%saer_uncor_severity: 0x%08x\n",
518 pfx, aer->uncor_severity);
519 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
520 aer->header_log.dw0, aer->header_log.dw1,
521 aer->header_log.dw2, aer->header_log.dw3);
525 static void cper_print_tstamp(const char *pfx,
526 struct acpi_hest_generic_data_v300 *gdata)
528 __u8 hour, min, sec, day, mon, year, century, *timestamp;
530 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
531 timestamp = (__u8 *)&(gdata->time_stamp);
532 sec = bcd2bin(timestamp[0]);
533 min = bcd2bin(timestamp[1]);
534 hour = bcd2bin(timestamp[2]);
535 day = bcd2bin(timestamp[4]);
536 mon = bcd2bin(timestamp[5]);
537 year = bcd2bin(timestamp[6]);
538 century = bcd2bin(timestamp[7]);
540 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
541 (timestamp[3] & 0x1 ? "precise " : "imprecise "),
542 century, year, mon, day, hour, min, sec);
547 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
550 guid_t *sec_type = (guid_t *)gdata->section_type;
554 if (acpi_hest_get_version(gdata) >= 3)
555 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
557 severity = gdata->error_severity;
558 printk("%s""Error %d, type: %s\n", pfx, sec_no,
559 cper_severity_str(severity));
560 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
561 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
562 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
563 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
565 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
566 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
567 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
569 printk("%s""section_type: general processor error\n", newpfx);
570 if (gdata->error_data_length >= sizeof(*proc_err))
571 cper_print_proc_generic(newpfx, proc_err);
573 goto err_section_too_small;
574 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
575 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
577 printk("%s""section_type: memory error\n", newpfx);
578 if (gdata->error_data_length >=
579 sizeof(struct cper_sec_mem_err_old))
580 cper_print_mem(newpfx, mem_err,
581 gdata->error_data_length);
583 goto err_section_too_small;
584 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
585 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
587 printk("%s""section_type: PCIe error\n", newpfx);
588 if (gdata->error_data_length >= sizeof(*pcie))
589 cper_print_pcie(newpfx, pcie, gdata);
591 goto err_section_too_small;
592 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
593 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
594 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
596 printk("%ssection_type: ARM processor error\n", newpfx);
597 if (gdata->error_data_length >= sizeof(*arm_err))
598 cper_print_proc_arm(newpfx, arm_err);
600 goto err_section_too_small;
603 const void *err = acpi_hest_get_payload(gdata);
605 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
606 printk("%ssection length: %#x\n", newpfx,
607 gdata->error_data_length);
608 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
609 gdata->error_data_length, true);
614 err_section_too_small:
615 pr_err(FW_WARN "error section length is too small\n");
618 void cper_estatus_print(const char *pfx,
619 const struct acpi_hest_generic_status *estatus)
621 struct acpi_hest_generic_data *gdata;
626 severity = estatus->error_severity;
627 if (severity == CPER_SEV_CORRECTED)
628 printk("%s%s\n", pfx,
629 "It has been corrected by h/w "
630 "and requires no further action");
631 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
632 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
634 apei_estatus_for_each_section(estatus, gdata) {
635 cper_estatus_print_section(newpfx, gdata, sec_no);
639 EXPORT_SYMBOL_GPL(cper_estatus_print);
641 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
643 if (estatus->data_length &&
644 estatus->data_length < sizeof(struct acpi_hest_generic_data))
646 if (estatus->raw_data_length &&
647 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
652 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
654 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
656 struct acpi_hest_generic_data *gdata;
657 unsigned int data_len, record_size;
660 rc = cper_estatus_check_header(estatus);
664 data_len = estatus->data_length;
666 apei_estatus_for_each_section(estatus, gdata) {
667 if (sizeof(struct acpi_hest_generic_data) > data_len)
670 record_size = acpi_hest_get_record_size(gdata);
671 if (record_size > data_len)
674 data_len -= record_size;
681 EXPORT_SYMBOL_GPL(cper_estatus_check);