0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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
0030
0031
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
0042
0043
0044
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
0073
0074
0075
0076
0077
0078
0079
0080
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
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
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
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
0478
0479
0480
0481
0482
0483 if (fw_err->revision == 0) {
0484
0485 offset = offsetof(struct cper_sec_fw_err_rec_ref,
0486 record_identifier_guid);
0487 } else if (fw_err->revision == 1) {
0488
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
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);