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 <ying.huang@intel.com> 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 28 /* 29 * CPER record ID need to be unique even after reboot, because record 30 * ID is used as index for ERST storage, while CPER records from 31 * multiple boot may co-exist in ERST. 32 */ 33 u64 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 * This code is unlikely to still be needed in year 2106, 42 * but just in case, let's use a few more bits for timestamps 43 * after y2038 to be sure they keep increasing monotonically 44 * for the next few hundred years... 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 } 55 EXPORT_SYMBOL_GPL(cper_next_record_id); 56 57 static const char * const severity_strs[] = { 58 "recoverable", 59 "fatal", 60 "corrected", 61 "info", 62 }; 63 64 const char *cper_severity_str(unsigned int severity) 65 { 66 return severity < ARRAY_SIZE(severity_strs) ? 67 severity_strs[severity] : "unknown"; 68 } 69 EXPORT_SYMBOL_GPL(cper_severity_str); 70 71 /* 72 * cper_print_bits - print strings for set bits 73 * @pfx: prefix for each line, including log level and prefix string 74 * @bits: bit mask 75 * @strs: string array, indexed by bit position 76 * @strs_size: size of the string array: @strs 77 * 78 * For each set bit in @bits, print the corresponding string in @strs. 79 * If the output length is longer than 80, multiple line will be 80 * printed, with @pfx is printed at the beginning of each line. 81 */ 82 void 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 108 static const char * const proc_type_strs[] = { 109 "IA32/X64", 110 "IA64", 111 "ARM", 112 }; 113 114 static const char * const proc_isa_strs[] = { 115 "IA32", 116 "IA64", 117 "X64", 118 "ARM A32/T32", 119 "ARM A64", 120 }; 121 122 const char * const cper_proc_error_type_strs[] = { 123 "cache error", 124 "TLB error", 125 "bus error", 126 "micro-architectural error", 127 }; 128 129 static const char * const proc_op_strs[] = { 130 "unknown or generic", 131 "data read", 132 "data write", 133 "instruction execution", 134 }; 135 136 static const char * const proc_flag_strs[] = { 137 "restartable", 138 "precise IP", 139 "overflow", 140 "corrected", 141 }; 142 143 static 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 188 static 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 207 const 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 } 212 EXPORT_SYMBOL_GPL(cper_mem_err_type_str); 213 214 const char *cper_mem_err_status_str(u64 status) 215 { 216 switch ((status >> 8) & 0xff) { 217 case 1: return "Error detected internal to the component"; 218 case 4: return "Storage error in DRAM memory"; 219 case 5: return "Storage error in TLB"; 220 case 6: return "Storage error in cache"; 221 case 7: return "Error in one or more functional units"; 222 case 8: return "Component failed self test"; 223 case 9: return "Overflow or undervalue of internal queue"; 224 case 16: return "Error detected in the bus"; 225 case 17: return "Virtual address not found on IO-TLB or IO-PDIR"; 226 case 18: return "Improper access error"; 227 case 19: return "Access to a memory address which is not mapped to any component"; 228 case 20: return "Loss of Lockstep"; 229 case 21: return "Response not associated with a request"; 230 case 22: return "Bus parity error - must also set the A, C, or D Bits"; 231 case 23: return "Detection of a protocol error"; 232 case 24: return "Detection of a PATH_ERROR"; 233 case 25: return "Bus operation timeout"; 234 case 26: return "A read was issued to data that has been poisoned"; 235 default: return "Reserved"; 236 } 237 } 238 EXPORT_SYMBOL_GPL(cper_mem_err_status_str); 239 240 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) 241 { 242 u32 len, n; 243 244 if (!msg) 245 return 0; 246 247 n = 0; 248 len = CPER_REC_LEN; 249 if (mem->validation_bits & CPER_MEM_VALID_NODE) 250 n += scnprintf(msg + n, len - n, "node:%d ", mem->node); 251 if (mem->validation_bits & CPER_MEM_VALID_CARD) 252 n += scnprintf(msg + n, len - n, "card:%d ", mem->card); 253 if (mem->validation_bits & CPER_MEM_VALID_MODULE) 254 n += scnprintf(msg + n, len - n, "module:%d ", mem->module); 255 if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) 256 n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank); 257 if (mem->validation_bits & CPER_MEM_VALID_BANK) 258 n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank); 259 if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP) 260 n += scnprintf(msg + n, len - n, "bank_group:%d ", 261 mem->bank >> CPER_MEM_BANK_GROUP_SHIFT); 262 if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS) 263 n += scnprintf(msg + n, len - n, "bank_address:%d ", 264 mem->bank & CPER_MEM_BANK_ADDRESS_MASK); 265 if (mem->validation_bits & CPER_MEM_VALID_DEVICE) 266 n += scnprintf(msg + n, len - n, "device:%d ", mem->device); 267 if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) { 268 u32 row = mem->row; 269 270 row |= cper_get_mem_extension(mem->validation_bits, mem->extended); 271 n += scnprintf(msg + n, len - n, "row:%d ", row); 272 } 273 if (mem->validation_bits & CPER_MEM_VALID_COLUMN) 274 n += scnprintf(msg + n, len - n, "column:%d ", mem->column); 275 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) 276 n += scnprintf(msg + n, len - n, "bit_position:%d ", 277 mem->bit_pos); 278 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) 279 n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ", 280 mem->requestor_id); 281 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) 282 n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ", 283 mem->responder_id); 284 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) 285 n += scnprintf(msg + n, len - n, "target_id:0x%016llx ", 286 mem->target_id); 287 if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID) 288 n += scnprintf(msg + n, len - n, "chip_id:%d ", 289 mem->extended >> CPER_MEM_CHIP_ID_SHIFT); 290 291 return n; 292 } 293 EXPORT_SYMBOL_GPL(cper_mem_err_location); 294 295 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg) 296 { 297 u32 len, n; 298 const char *bank = NULL, *device = NULL; 299 300 if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE)) 301 return 0; 302 303 len = CPER_REC_LEN; 304 dmi_memdev_name(mem->mem_dev_handle, &bank, &device); 305 if (bank && device) 306 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device); 307 else 308 n = snprintf(msg, len, 309 "DIMM location: not present. DMI handle: 0x%.4x ", 310 mem->mem_dev_handle); 311 312 return n; 313 } 314 EXPORT_SYMBOL_GPL(cper_dimm_err_location); 315 316 void cper_mem_err_pack(const struct cper_sec_mem_err *mem, 317 struct cper_mem_err_compact *cmem) 318 { 319 cmem->validation_bits = mem->validation_bits; 320 cmem->node = mem->node; 321 cmem->card = mem->card; 322 cmem->module = mem->module; 323 cmem->bank = mem->bank; 324 cmem->device = mem->device; 325 cmem->row = mem->row; 326 cmem->column = mem->column; 327 cmem->bit_pos = mem->bit_pos; 328 cmem->requestor_id = mem->requestor_id; 329 cmem->responder_id = mem->responder_id; 330 cmem->target_id = mem->target_id; 331 cmem->extended = mem->extended; 332 cmem->rank = mem->rank; 333 cmem->mem_array_handle = mem->mem_array_handle; 334 cmem->mem_dev_handle = mem->mem_dev_handle; 335 } 336 EXPORT_SYMBOL_GPL(cper_mem_err_pack); 337 338 const char *cper_mem_err_unpack(struct trace_seq *p, 339 struct cper_mem_err_compact *cmem) 340 { 341 const char *ret = trace_seq_buffer_ptr(p); 342 char rcd_decode_str[CPER_REC_LEN]; 343 344 if (cper_mem_err_location(cmem, rcd_decode_str)) 345 trace_seq_printf(p, "%s", rcd_decode_str); 346 if (cper_dimm_err_location(cmem, rcd_decode_str)) 347 trace_seq_printf(p, "%s", rcd_decode_str); 348 trace_seq_putc(p, '\0'); 349 350 return ret; 351 } 352 353 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem, 354 int len) 355 { 356 struct cper_mem_err_compact cmem; 357 char rcd_decode_str[CPER_REC_LEN]; 358 359 /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */ 360 if (len == sizeof(struct cper_sec_mem_err_old) && 361 (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) { 362 pr_err(FW_WARN "valid bits set for fields beyond structure\n"); 363 return; 364 } 365 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) 366 printk("%s error_status: %s (0x%016llx)\n", 367 pfx, cper_mem_err_status_str(mem->error_status), 368 mem->error_status); 369 if (mem->validation_bits & CPER_MEM_VALID_PA) 370 printk("%s""physical_address: 0x%016llx\n", 371 pfx, mem->physical_addr); 372 if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) 373 printk("%s""physical_address_mask: 0x%016llx\n", 374 pfx, mem->physical_addr_mask); 375 cper_mem_err_pack(mem, &cmem); 376 if (cper_mem_err_location(&cmem, rcd_decode_str)) 377 printk("%s%s\n", pfx, rcd_decode_str); 378 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { 379 u8 etype = mem->error_type; 380 printk("%s""error_type: %d, %s\n", pfx, etype, 381 cper_mem_err_type_str(etype)); 382 } 383 if (cper_dimm_err_location(&cmem, rcd_decode_str)) 384 printk("%s%s\n", pfx, rcd_decode_str); 385 } 386 387 static const char * const pcie_port_type_strs[] = { 388 "PCIe end point", 389 "legacy PCI end point", 390 "unknown", 391 "unknown", 392 "root port", 393 "upstream switch port", 394 "downstream switch port", 395 "PCIe to PCI/PCI-X bridge", 396 "PCI/PCI-X to PCIe bridge", 397 "root complex integrated endpoint device", 398 "root complex event collector", 399 }; 400 401 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, 402 const struct acpi_hest_generic_data *gdata) 403 { 404 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) 405 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, 406 pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ? 407 pcie_port_type_strs[pcie->port_type] : "unknown"); 408 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) 409 printk("%s""version: %d.%d\n", pfx, 410 pcie->version.major, pcie->version.minor); 411 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS) 412 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx, 413 pcie->command, pcie->status); 414 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) { 415 const __u8 *p; 416 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx, 417 pcie->device_id.segment, pcie->device_id.bus, 418 pcie->device_id.device, pcie->device_id.function); 419 printk("%s""slot: %d\n", pfx, 420 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT); 421 printk("%s""secondary_bus: 0x%02x\n", pfx, 422 pcie->device_id.secondary_bus); 423 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx, 424 pcie->device_id.vendor_id, pcie->device_id.device_id); 425 p = pcie->device_id.class_code; 426 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]); 427 } 428 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER) 429 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx, 430 pcie->serial_number.lower, pcie->serial_number.upper); 431 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS) 432 printk( 433 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 434 pfx, pcie->bridge.secondary_status, pcie->bridge.control); 435 436 /* Fatal errors call __ghes_panic() before AER handler prints this */ 437 if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && 438 (gdata->error_severity & CPER_SEV_FATAL)) { 439 struct aer_capability_regs *aer; 440 441 aer = (struct aer_capability_regs *)pcie->aer_info; 442 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", 443 pfx, aer->uncor_status, aer->uncor_mask); 444 printk("%saer_uncor_severity: 0x%08x\n", 445 pfx, aer->uncor_severity); 446 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx, 447 aer->header_log.dw0, aer->header_log.dw1, 448 aer->header_log.dw2, aer->header_log.dw3); 449 } 450 } 451 452 static const char * const fw_err_rec_type_strs[] = { 453 "IPF SAL Error Record", 454 "SOC Firmware Error Record Type1 (Legacy CrashLog Support)", 455 "SOC Firmware Error Record Type2", 456 }; 457 458 static void cper_print_fw_err(const char *pfx, 459 struct acpi_hest_generic_data *gdata, 460 const struct cper_sec_fw_err_rec_ref *fw_err) 461 { 462 void *buf = acpi_hest_get_payload(gdata); 463 u32 offset, length = gdata->error_data_length; 464 465 printk("%s""Firmware Error Record Type: %s\n", pfx, 466 fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ? 467 fw_err_rec_type_strs[fw_err->record_type] : "unknown"); 468 printk("%s""Revision: %d\n", pfx, fw_err->revision); 469 470 /* Record Type based on UEFI 2.7 */ 471 if (fw_err->revision == 0) { 472 printk("%s""Record Identifier: %08llx\n", pfx, 473 fw_err->record_identifier); 474 } else if (fw_err->revision == 2) { 475 printk("%s""Record Identifier: %pUl\n", pfx, 476 &fw_err->record_identifier_guid); 477 } 478 479 /* 480 * The FW error record may contain trailing data beyond the 481 * structure defined by the specification. As the fields 482 * defined (and hence the offset of any trailing data) vary 483 * with the revision, set the offset to account for this 484 * variation. 485 */ 486 if (fw_err->revision == 0) { 487 /* record_identifier_guid not defined */ 488 offset = offsetof(struct cper_sec_fw_err_rec_ref, 489 record_identifier_guid); 490 } else if (fw_err->revision == 1) { 491 /* record_identifier not defined */ 492 offset = offsetof(struct cper_sec_fw_err_rec_ref, 493 record_identifier); 494 } else { 495 offset = sizeof(*fw_err); 496 } 497 498 buf += offset; 499 length -= offset; 500 501 print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); 502 } 503 504 static void cper_print_tstamp(const char *pfx, 505 struct acpi_hest_generic_data_v300 *gdata) 506 { 507 __u8 hour, min, sec, day, mon, year, century, *timestamp; 508 509 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) { 510 timestamp = (__u8 *)&(gdata->time_stamp); 511 sec = bcd2bin(timestamp[0]); 512 min = bcd2bin(timestamp[1]); 513 hour = bcd2bin(timestamp[2]); 514 day = bcd2bin(timestamp[4]); 515 mon = bcd2bin(timestamp[5]); 516 year = bcd2bin(timestamp[6]); 517 century = bcd2bin(timestamp[7]); 518 519 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx, 520 (timestamp[3] & 0x1 ? "precise " : "imprecise "), 521 century, year, mon, day, hour, min, sec); 522 } 523 } 524 525 static void 526 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata, 527 int sec_no) 528 { 529 guid_t *sec_type = (guid_t *)gdata->section_type; 530 __u16 severity; 531 char newpfx[64]; 532 533 if (acpi_hest_get_version(gdata) >= 3) 534 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata); 535 536 severity = gdata->error_severity; 537 printk("%s""Error %d, type: %s\n", pfx, sec_no, 538 cper_severity_str(severity)); 539 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) 540 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id); 541 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) 542 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); 543 544 snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 545 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) { 546 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); 547 548 printk("%s""section_type: general processor error\n", newpfx); 549 if (gdata->error_data_length >= sizeof(*proc_err)) 550 cper_print_proc_generic(newpfx, proc_err); 551 else 552 goto err_section_too_small; 553 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { 554 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); 555 556 printk("%s""section_type: memory error\n", newpfx); 557 if (gdata->error_data_length >= 558 sizeof(struct cper_sec_mem_err_old)) 559 cper_print_mem(newpfx, mem_err, 560 gdata->error_data_length); 561 else 562 goto err_section_too_small; 563 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { 564 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata); 565 566 printk("%s""section_type: PCIe error\n", newpfx); 567 if (gdata->error_data_length >= sizeof(*pcie)) 568 cper_print_pcie(newpfx, pcie, gdata); 569 else 570 goto err_section_too_small; 571 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) 572 } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { 573 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata); 574 575 printk("%ssection_type: ARM processor error\n", newpfx); 576 if (gdata->error_data_length >= sizeof(*arm_err)) 577 cper_print_proc_arm(newpfx, arm_err); 578 else 579 goto err_section_too_small; 580 #endif 581 #if defined(CONFIG_UEFI_CPER_X86) 582 } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) { 583 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata); 584 585 printk("%ssection_type: IA32/X64 processor error\n", newpfx); 586 if (gdata->error_data_length >= sizeof(*ia_err)) 587 cper_print_proc_ia(newpfx, ia_err); 588 else 589 goto err_section_too_small; 590 #endif 591 } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) { 592 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata); 593 594 printk("%ssection_type: Firmware Error Record Reference\n", 595 newpfx); 596 /* The minimal FW Error Record contains 16 bytes */ 597 if (gdata->error_data_length >= SZ_16) 598 cper_print_fw_err(newpfx, gdata, fw_err); 599 else 600 goto err_section_too_small; 601 } else { 602 const void *err = acpi_hest_get_payload(gdata); 603 604 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type); 605 printk("%ssection length: %#x\n", newpfx, 606 gdata->error_data_length); 607 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err, 608 gdata->error_data_length, true); 609 } 610 611 return; 612 613 err_section_too_small: 614 pr_err(FW_WARN "error section length is too small\n"); 615 } 616 617 void cper_estatus_print(const char *pfx, 618 const struct acpi_hest_generic_status *estatus) 619 { 620 struct acpi_hest_generic_data *gdata; 621 int sec_no = 0; 622 char newpfx[64]; 623 __u16 severity; 624 625 severity = estatus->error_severity; 626 if (severity == CPER_SEV_CORRECTED) 627 printk("%s%s\n", pfx, 628 "It has been corrected by h/w " 629 "and requires no further action"); 630 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); 631 snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 632 633 apei_estatus_for_each_section(estatus, gdata) { 634 cper_estatus_print_section(newpfx, gdata, sec_no); 635 sec_no++; 636 } 637 } 638 EXPORT_SYMBOL_GPL(cper_estatus_print); 639 640 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus) 641 { 642 if (estatus->data_length && 643 estatus->data_length < sizeof(struct acpi_hest_generic_data)) 644 return -EINVAL; 645 if (estatus->raw_data_length && 646 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) 647 return -EINVAL; 648 649 return 0; 650 } 651 EXPORT_SYMBOL_GPL(cper_estatus_check_header); 652 653 int cper_estatus_check(const struct acpi_hest_generic_status *estatus) 654 { 655 struct acpi_hest_generic_data *gdata; 656 unsigned int data_len, record_size; 657 int rc; 658 659 rc = cper_estatus_check_header(estatus); 660 if (rc) 661 return rc; 662 663 data_len = estatus->data_length; 664 665 apei_estatus_for_each_section(estatus, gdata) { 666 if (acpi_hest_get_size(gdata) > data_len) 667 return -EINVAL; 668 669 record_size = acpi_hest_get_record_size(gdata); 670 if (record_size > data_len) 671 return -EINVAL; 672 673 data_len -= record_size; 674 } 675 if (data_len) 676 return -EINVAL; 677 678 return 0; 679 } 680 EXPORT_SYMBOL_GPL(cper_estatus_check); 681