Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * UEFI Common Platform Error Record (CPER) support
0004  *
0005  * Copyright (C) 2010, Intel Corp.
0006  *  Author: Huang Ying <ying.huang@intel.com>
0007  *
0008  * CPER is the format used to describe platform hardware error by
0009  * various tables, such as ERST, BERT and HEST etc.
0010  *
0011  * For more information about CPER, please refer to Appendix N of UEFI
0012  * Specification version 2.4.
0013  */
0014 
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/time.h>
0018 #include <linux/cper.h>
0019 #include <linux/dmi.h>
0020 #include <linux/acpi.h>
0021 #include <linux/pci.h>
0022 #include <linux/aer.h>
0023 #include <linux/printk.h>
0024 #include <linux/bcd.h>
0025 #include <acpi/ghes.h>
0026 #include <ras/ras_event.h>
0027 
0028 /*
0029  * CPER record ID need to be unique even after reboot, because record
0030  * ID is used as index for ERST storage, while CPER records from
0031  * multiple boot may co-exist in ERST.
0032  */
0033 u64 cper_next_record_id(void)
0034 {
0035     static atomic64_t seq;
0036 
0037     if (!atomic64_read(&seq)) {
0038         time64_t time = ktime_get_real_seconds();
0039 
0040         /*
0041          * This code is unlikely to still be needed in year 2106,
0042          * but just in case, let's use a few more bits for timestamps
0043          * after y2038 to be sure they keep increasing monotonically
0044          * for the next few hundred years...
0045          */
0046         if (time < 0x80000000)
0047             atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
0048         else
0049             atomic64_set(&seq, 0x8000000000000000ull |
0050                        ktime_get_real_seconds() << 24);
0051     }
0052 
0053     return atomic64_inc_return(&seq);
0054 }
0055 EXPORT_SYMBOL_GPL(cper_next_record_id);
0056 
0057 static const char * const severity_strs[] = {
0058     "recoverable",
0059     "fatal",
0060     "corrected",
0061     "info",
0062 };
0063 
0064 const char *cper_severity_str(unsigned int severity)
0065 {
0066     return severity < ARRAY_SIZE(severity_strs) ?
0067         severity_strs[severity] : "unknown";
0068 }
0069 EXPORT_SYMBOL_GPL(cper_severity_str);
0070 
0071 /*
0072  * cper_print_bits - print strings for set bits
0073  * @pfx: prefix for each line, including log level and prefix string
0074  * @bits: bit mask
0075  * @strs: string array, indexed by bit position
0076  * @strs_size: size of the string array: @strs
0077  *
0078  * For each set bit in @bits, print the corresponding string in @strs.
0079  * If the output length is longer than 80, multiple line will be
0080  * printed, with @pfx is printed at the beginning of each line.
0081  */
0082 void cper_print_bits(const char *pfx, unsigned int bits,
0083              const char * const strs[], unsigned int strs_size)
0084 {
0085     int i, len = 0;
0086     const char *str;
0087     char buf[84];
0088 
0089     for (i = 0; i < strs_size; i++) {
0090         if (!(bits & (1U << i)))
0091             continue;
0092         str = strs[i];
0093         if (!str)
0094             continue;
0095         if (len && len + strlen(str) + 2 > 80) {
0096             printk("%s\n", buf);
0097             len = 0;
0098         }
0099         if (!len)
0100             len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
0101         else
0102             len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
0103     }
0104     if (len)
0105         printk("%s\n", buf);
0106 }
0107 
0108 static const char * const proc_type_strs[] = {
0109     "IA32/X64",
0110     "IA64",
0111     "ARM",
0112 };
0113 
0114 static const char * const proc_isa_strs[] = {
0115     "IA32",
0116     "IA64",
0117     "X64",
0118     "ARM A32/T32",
0119     "ARM A64",
0120 };
0121 
0122 const char * const cper_proc_error_type_strs[] = {
0123     "cache error",
0124     "TLB error",
0125     "bus error",
0126     "micro-architectural error",
0127 };
0128 
0129 static const char * const proc_op_strs[] = {
0130     "unknown or generic",
0131     "data read",
0132     "data write",
0133     "instruction execution",
0134 };
0135 
0136 static const char * const proc_flag_strs[] = {
0137     "restartable",
0138     "precise IP",
0139     "overflow",
0140     "corrected",
0141 };
0142 
0143 static void cper_print_proc_generic(const char *pfx,
0144                     const struct cper_sec_proc_generic *proc)
0145 {
0146     if (proc->validation_bits & CPER_PROC_VALID_TYPE)
0147         printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
0148                proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
0149                proc_type_strs[proc->proc_type] : "unknown");
0150     if (proc->validation_bits & CPER_PROC_VALID_ISA)
0151         printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
0152                proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
0153                proc_isa_strs[proc->proc_isa] : "unknown");
0154     if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
0155         printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
0156         cper_print_bits(pfx, proc->proc_error_type,
0157                 cper_proc_error_type_strs,
0158                 ARRAY_SIZE(cper_proc_error_type_strs));
0159     }
0160     if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
0161         printk("%s""operation: %d, %s\n", pfx, proc->operation,
0162                proc->operation < ARRAY_SIZE(proc_op_strs) ?
0163                proc_op_strs[proc->operation] : "unknown");
0164     if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
0165         printk("%s""flags: 0x%02x\n", pfx, proc->flags);
0166         cper_print_bits(pfx, proc->flags, proc_flag_strs,
0167                 ARRAY_SIZE(proc_flag_strs));
0168     }
0169     if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
0170         printk("%s""level: %d\n", pfx, proc->level);
0171     if (proc->validation_bits & CPER_PROC_VALID_VERSION)
0172         printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
0173     if (proc->validation_bits & CPER_PROC_VALID_ID)
0174         printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
0175     if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
0176         printk("%s""target_address: 0x%016llx\n",
0177                pfx, proc->target_addr);
0178     if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
0179         printk("%s""requestor_id: 0x%016llx\n",
0180                pfx, proc->requestor_id);
0181     if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
0182         printk("%s""responder_id: 0x%016llx\n",
0183                pfx, proc->responder_id);
0184     if (proc->validation_bits & CPER_PROC_VALID_IP)
0185         printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
0186 }
0187 
0188 static const char * const mem_err_type_strs[] = {
0189     "unknown",
0190     "no error",
0191     "single-bit ECC",
0192     "multi-bit ECC",
0193     "single-symbol chipkill ECC",
0194     "multi-symbol chipkill ECC",
0195     "master abort",
0196     "target abort",
0197     "parity error",
0198     "watchdog timeout",
0199     "invalid address",
0200     "mirror Broken",
0201     "memory sparing",
0202     "scrub corrected error",
0203     "scrub uncorrected error",
0204     "physical memory map-out event",
0205 };
0206 
0207 const char *cper_mem_err_type_str(unsigned int etype)
0208 {
0209     return etype < ARRAY_SIZE(mem_err_type_strs) ?
0210         mem_err_type_strs[etype] : "unknown";
0211 }
0212 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
0213 
0214 const char *cper_mem_err_status_str(u64 status)
0215 {
0216     switch ((status >> 8) & 0xff) {
0217     case  1:    return "Error detected internal to the component";
0218     case  4:    return "Storage error in DRAM memory";
0219     case  5:    return "Storage error in TLB";
0220     case  6:    return "Storage error in cache";
0221     case  7:    return "Error in one or more functional units";
0222     case  8:    return "Component failed self test";
0223     case  9:    return "Overflow or undervalue of internal queue";
0224     case 16:    return "Error detected in the bus";
0225     case 17:    return "Virtual address not found on IO-TLB or IO-PDIR";
0226     case 18:    return "Improper access error";
0227     case 19:    return "Access to a memory address which is not mapped to any component";
0228     case 20:    return "Loss of Lockstep";
0229     case 21:    return "Response not associated with a request";
0230     case 22:    return "Bus parity error - must also set the A, C, or D Bits";
0231     case 23:    return "Detection of a protocol error";
0232     case 24:    return "Detection of a PATH_ERROR";
0233     case 25:    return "Bus operation timeout";
0234     case 26:    return "A read was issued to data that has been poisoned";
0235     default:    return "Reserved";
0236     }
0237 }
0238 EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
0239 
0240 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
0241 {
0242     u32 len, n;
0243 
0244     if (!msg)
0245         return 0;
0246 
0247     n = 0;
0248     len = CPER_REC_LEN;
0249     if (mem->validation_bits & CPER_MEM_VALID_NODE)
0250         n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
0251     if (mem->validation_bits & CPER_MEM_VALID_CARD)
0252         n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
0253     if (mem->validation_bits & CPER_MEM_VALID_MODULE)
0254         n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
0255     if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
0256         n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank);
0257     if (mem->validation_bits & CPER_MEM_VALID_BANK)
0258         n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
0259     if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
0260         n += scnprintf(msg + n, len - n, "bank_group:%d ",
0261                    mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
0262     if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
0263         n += scnprintf(msg + n, len - n, "bank_address:%d ",
0264                    mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
0265     if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
0266         n += scnprintf(msg + n, len - n, "device:%d ", mem->device);
0267     if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
0268         u32 row = mem->row;
0269 
0270         row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
0271         n += scnprintf(msg + n, len - n, "row:%d ", row);
0272     }
0273     if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
0274         n += scnprintf(msg + n, len - n, "column:%d ", mem->column);
0275     if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
0276         n += scnprintf(msg + n, len - n, "bit_position:%d ",
0277                    mem->bit_pos);
0278     if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
0279         n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
0280                    mem->requestor_id);
0281     if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
0282         n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
0283                    mem->responder_id);
0284     if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
0285         n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
0286                    mem->target_id);
0287     if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
0288         n += scnprintf(msg + n, len - n, "chip_id:%d ",
0289                    mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
0290 
0291     return n;
0292 }
0293 
0294 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
0295 {
0296     u32 len, n;
0297     const char *bank = NULL, *device = NULL;
0298 
0299     if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
0300         return 0;
0301 
0302     len = CPER_REC_LEN;
0303     dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
0304     if (bank && device)
0305         n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
0306     else
0307         n = snprintf(msg, len,
0308                  "DIMM location: not present. DMI handle: 0x%.4x ",
0309                  mem->mem_dev_handle);
0310 
0311     return n;
0312 }
0313 
0314 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
0315                struct cper_mem_err_compact *cmem)
0316 {
0317     cmem->validation_bits = mem->validation_bits;
0318     cmem->node = mem->node;
0319     cmem->card = mem->card;
0320     cmem->module = mem->module;
0321     cmem->bank = mem->bank;
0322     cmem->device = mem->device;
0323     cmem->row = mem->row;
0324     cmem->column = mem->column;
0325     cmem->bit_pos = mem->bit_pos;
0326     cmem->requestor_id = mem->requestor_id;
0327     cmem->responder_id = mem->responder_id;
0328     cmem->target_id = mem->target_id;
0329     cmem->extended = mem->extended;
0330     cmem->rank = mem->rank;
0331     cmem->mem_array_handle = mem->mem_array_handle;
0332     cmem->mem_dev_handle = mem->mem_dev_handle;
0333 }
0334 
0335 const char *cper_mem_err_unpack(struct trace_seq *p,
0336                 struct cper_mem_err_compact *cmem)
0337 {
0338     const char *ret = trace_seq_buffer_ptr(p);
0339     char rcd_decode_str[CPER_REC_LEN];
0340 
0341     if (cper_mem_err_location(cmem, rcd_decode_str))
0342         trace_seq_printf(p, "%s", rcd_decode_str);
0343     if (cper_dimm_err_location(cmem, rcd_decode_str))
0344         trace_seq_printf(p, "%s", rcd_decode_str);
0345     trace_seq_putc(p, '\0');
0346 
0347     return ret;
0348 }
0349 
0350 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
0351     int len)
0352 {
0353     struct cper_mem_err_compact cmem;
0354     char rcd_decode_str[CPER_REC_LEN];
0355 
0356     /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
0357     if (len == sizeof(struct cper_sec_mem_err_old) &&
0358         (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
0359         pr_err(FW_WARN "valid bits set for fields beyond structure\n");
0360         return;
0361     }
0362     if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
0363         printk("%s error_status: %s (0x%016llx)\n",
0364                pfx, cper_mem_err_status_str(mem->error_status),
0365                mem->error_status);
0366     if (mem->validation_bits & CPER_MEM_VALID_PA)
0367         printk("%s""physical_address: 0x%016llx\n",
0368                pfx, mem->physical_addr);
0369     if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
0370         printk("%s""physical_address_mask: 0x%016llx\n",
0371                pfx, mem->physical_addr_mask);
0372     cper_mem_err_pack(mem, &cmem);
0373     if (cper_mem_err_location(&cmem, rcd_decode_str))
0374         printk("%s%s\n", pfx, rcd_decode_str);
0375     if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
0376         u8 etype = mem->error_type;
0377         printk("%s""error_type: %d, %s\n", pfx, etype,
0378                cper_mem_err_type_str(etype));
0379     }
0380     if (cper_dimm_err_location(&cmem, rcd_decode_str))
0381         printk("%s%s\n", pfx, rcd_decode_str);
0382 }
0383 
0384 static const char * const pcie_port_type_strs[] = {
0385     "PCIe end point",
0386     "legacy PCI end point",
0387     "unknown",
0388     "unknown",
0389     "root port",
0390     "upstream switch port",
0391     "downstream switch port",
0392     "PCIe to PCI/PCI-X bridge",
0393     "PCI/PCI-X to PCIe bridge",
0394     "root complex integrated endpoint device",
0395     "root complex event collector",
0396 };
0397 
0398 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
0399                 const struct acpi_hest_generic_data *gdata)
0400 {
0401     if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
0402         printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
0403                pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
0404                pcie_port_type_strs[pcie->port_type] : "unknown");
0405     if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
0406         printk("%s""version: %d.%d\n", pfx,
0407                pcie->version.major, pcie->version.minor);
0408     if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
0409         printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
0410                pcie->command, pcie->status);
0411     if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
0412         const __u8 *p;
0413         printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
0414                pcie->device_id.segment, pcie->device_id.bus,
0415                pcie->device_id.device, pcie->device_id.function);
0416         printk("%s""slot: %d\n", pfx,
0417                pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
0418         printk("%s""secondary_bus: 0x%02x\n", pfx,
0419                pcie->device_id.secondary_bus);
0420         printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
0421                pcie->device_id.vendor_id, pcie->device_id.device_id);
0422         p = pcie->device_id.class_code;
0423         printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
0424     }
0425     if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
0426         printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
0427                pcie->serial_number.lower, pcie->serial_number.upper);
0428     if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
0429         printk(
0430     "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
0431     pfx, pcie->bridge.secondary_status, pcie->bridge.control);
0432 
0433     /* Fatal errors call __ghes_panic() before AER handler prints this */
0434     if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
0435         (gdata->error_severity & CPER_SEV_FATAL)) {
0436         struct aer_capability_regs *aer;
0437 
0438         aer = (struct aer_capability_regs *)pcie->aer_info;
0439         printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
0440                pfx, aer->uncor_status, aer->uncor_mask);
0441         printk("%saer_uncor_severity: 0x%08x\n",
0442                pfx, aer->uncor_severity);
0443         printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
0444                aer->header_log.dw0, aer->header_log.dw1,
0445                aer->header_log.dw2, aer->header_log.dw3);
0446     }
0447 }
0448 
0449 static const char * const fw_err_rec_type_strs[] = {
0450     "IPF SAL Error Record",
0451     "SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
0452     "SOC Firmware Error Record Type2",
0453 };
0454 
0455 static void cper_print_fw_err(const char *pfx,
0456                   struct acpi_hest_generic_data *gdata,
0457                   const struct cper_sec_fw_err_rec_ref *fw_err)
0458 {
0459     void *buf = acpi_hest_get_payload(gdata);
0460     u32 offset, length = gdata->error_data_length;
0461 
0462     printk("%s""Firmware Error Record Type: %s\n", pfx,
0463            fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
0464            fw_err_rec_type_strs[fw_err->record_type] : "unknown");
0465     printk("%s""Revision: %d\n", pfx, fw_err->revision);
0466 
0467     /* Record Type based on UEFI 2.7 */
0468     if (fw_err->revision == 0) {
0469         printk("%s""Record Identifier: %08llx\n", pfx,
0470                fw_err->record_identifier);
0471     } else if (fw_err->revision == 2) {
0472         printk("%s""Record Identifier: %pUl\n", pfx,
0473                &fw_err->record_identifier_guid);
0474     }
0475 
0476     /*
0477      * The FW error record may contain trailing data beyond the
0478      * structure defined by the specification. As the fields
0479      * defined (and hence the offset of any trailing data) vary
0480      * with the revision, set the offset to account for this
0481      * variation.
0482      */
0483     if (fw_err->revision == 0) {
0484         /* record_identifier_guid not defined */
0485         offset = offsetof(struct cper_sec_fw_err_rec_ref,
0486                   record_identifier_guid);
0487     } else if (fw_err->revision == 1) {
0488         /* record_identifier not defined */
0489         offset = offsetof(struct cper_sec_fw_err_rec_ref,
0490                   record_identifier);
0491     } else {
0492         offset = sizeof(*fw_err);
0493     }
0494 
0495     buf += offset;
0496     length -= offset;
0497 
0498     print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
0499 }
0500 
0501 static void cper_print_tstamp(const char *pfx,
0502                    struct acpi_hest_generic_data_v300 *gdata)
0503 {
0504     __u8 hour, min, sec, day, mon, year, century, *timestamp;
0505 
0506     if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
0507         timestamp = (__u8 *)&(gdata->time_stamp);
0508         sec       = bcd2bin(timestamp[0]);
0509         min       = bcd2bin(timestamp[1]);
0510         hour      = bcd2bin(timestamp[2]);
0511         day       = bcd2bin(timestamp[4]);
0512         mon       = bcd2bin(timestamp[5]);
0513         year      = bcd2bin(timestamp[6]);
0514         century   = bcd2bin(timestamp[7]);
0515 
0516         printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
0517                (timestamp[3] & 0x1 ? "precise " : "imprecise "),
0518                century, year, mon, day, hour, min, sec);
0519     }
0520 }
0521 
0522 static void
0523 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
0524                int sec_no)
0525 {
0526     guid_t *sec_type = (guid_t *)gdata->section_type;
0527     __u16 severity;
0528     char newpfx[64];
0529 
0530     if (acpi_hest_get_version(gdata) >= 3)
0531         cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
0532 
0533     severity = gdata->error_severity;
0534     printk("%s""Error %d, type: %s\n", pfx, sec_no,
0535            cper_severity_str(severity));
0536     if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
0537         printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
0538     if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
0539         printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
0540 
0541     snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
0542     if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
0543         struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
0544 
0545         printk("%s""section_type: general processor error\n", newpfx);
0546         if (gdata->error_data_length >= sizeof(*proc_err))
0547             cper_print_proc_generic(newpfx, proc_err);
0548         else
0549             goto err_section_too_small;
0550     } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
0551         struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
0552 
0553         printk("%s""section_type: memory error\n", newpfx);
0554         if (gdata->error_data_length >=
0555             sizeof(struct cper_sec_mem_err_old))
0556             cper_print_mem(newpfx, mem_err,
0557                        gdata->error_data_length);
0558         else
0559             goto err_section_too_small;
0560     } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
0561         struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
0562 
0563         printk("%s""section_type: PCIe error\n", newpfx);
0564         if (gdata->error_data_length >= sizeof(*pcie))
0565             cper_print_pcie(newpfx, pcie, gdata);
0566         else
0567             goto err_section_too_small;
0568 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
0569     } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
0570         struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
0571 
0572         printk("%ssection_type: ARM processor error\n", newpfx);
0573         if (gdata->error_data_length >= sizeof(*arm_err))
0574             cper_print_proc_arm(newpfx, arm_err);
0575         else
0576             goto err_section_too_small;
0577 #endif
0578 #if defined(CONFIG_UEFI_CPER_X86)
0579     } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
0580         struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
0581 
0582         printk("%ssection_type: IA32/X64 processor error\n", newpfx);
0583         if (gdata->error_data_length >= sizeof(*ia_err))
0584             cper_print_proc_ia(newpfx, ia_err);
0585         else
0586             goto err_section_too_small;
0587 #endif
0588     } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
0589         struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
0590 
0591         printk("%ssection_type: Firmware Error Record Reference\n",
0592                newpfx);
0593         /* The minimal FW Error Record contains 16 bytes */
0594         if (gdata->error_data_length >= SZ_16)
0595             cper_print_fw_err(newpfx, gdata, fw_err);
0596         else
0597             goto err_section_too_small;
0598     } else {
0599         const void *err = acpi_hest_get_payload(gdata);
0600 
0601         printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
0602         printk("%ssection length: %#x\n", newpfx,
0603                gdata->error_data_length);
0604         print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
0605                    gdata->error_data_length, true);
0606     }
0607 
0608     return;
0609 
0610 err_section_too_small:
0611     pr_err(FW_WARN "error section length is too small\n");
0612 }
0613 
0614 void cper_estatus_print(const char *pfx,
0615             const struct acpi_hest_generic_status *estatus)
0616 {
0617     struct acpi_hest_generic_data *gdata;
0618     int sec_no = 0;
0619     char newpfx[64];
0620     __u16 severity;
0621 
0622     severity = estatus->error_severity;
0623     if (severity == CPER_SEV_CORRECTED)
0624         printk("%s%s\n", pfx,
0625                "It has been corrected by h/w "
0626                "and requires no further action");
0627     printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
0628     snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
0629 
0630     apei_estatus_for_each_section(estatus, gdata) {
0631         cper_estatus_print_section(newpfx, gdata, sec_no);
0632         sec_no++;
0633     }
0634 }
0635 EXPORT_SYMBOL_GPL(cper_estatus_print);
0636 
0637 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
0638 {
0639     if (estatus->data_length &&
0640         estatus->data_length < sizeof(struct acpi_hest_generic_data))
0641         return -EINVAL;
0642     if (estatus->raw_data_length &&
0643         estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
0644         return -EINVAL;
0645 
0646     return 0;
0647 }
0648 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
0649 
0650 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
0651 {
0652     struct acpi_hest_generic_data *gdata;
0653     unsigned int data_len, record_size;
0654     int rc;
0655 
0656     rc = cper_estatus_check_header(estatus);
0657     if (rc)
0658         return rc;
0659 
0660     data_len = estatus->data_length;
0661 
0662     apei_estatus_for_each_section(estatus, gdata) {
0663         if (acpi_hest_get_size(gdata) > data_len)
0664             return -EINVAL;
0665 
0666         record_size = acpi_hest_get_record_size(gdata);
0667         if (record_size > data_len)
0668             return -EINVAL;
0669 
0670         data_len -= record_size;
0671     }
0672     if (data_len)
0673         return -EINVAL;
0674 
0675     return 0;
0676 }
0677 EXPORT_SYMBOL_GPL(cper_estatus_check);