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/bitmap.h> 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/time.h> 19 #include <linux/cper.h> 20 #include <linux/dmi.h> 21 #include <linux/acpi.h> 22 #include <linux/pci.h> 23 #include <linux/aer.h> 24 #include <linux/printk.h> 25 #include <linux/bcd.h> 26 #include <acpi/ghes.h> 27 #include <ras/ras_event.h> 28 #include <cxl/event.h> 29 30 /* 31 * CPER record ID need to be unique even after reboot, because record 32 * ID is used as index for ERST storage, while CPER records from 33 * multiple boot may co-exist in ERST. 34 */ 35 u64 cper_next_record_id(void) 36 { 37 static atomic64_t seq; 38 39 if (!atomic64_read(&seq)) { 40 time64_t time = ktime_get_real_seconds(); 41 42 /* 43 * This code is unlikely to still be needed in year 2106, 44 * but just in case, let's use a few more bits for timestamps 45 * after y2038 to be sure they keep increasing monotonically 46 * for the next few hundred years... 47 */ 48 if (time < 0x80000000) 49 atomic64_set(&seq, (ktime_get_real_seconds()) << 32); 50 else 51 atomic64_set(&seq, 0x8000000000000000ull | 52 ktime_get_real_seconds() << 24); 53 } 54 55 return atomic64_inc_return(&seq); 56 } 57 EXPORT_SYMBOL_GPL(cper_next_record_id); 58 59 static const char * const severity_strs[] = { 60 "recoverable", 61 "fatal", 62 "corrected", 63 "info", 64 }; 65 66 const char *cper_severity_str(unsigned int severity) 67 { 68 return severity < ARRAY_SIZE(severity_strs) ? 69 severity_strs[severity] : "unknown"; 70 } 71 EXPORT_SYMBOL_GPL(cper_severity_str); 72 73 /** 74 * cper_print_bits - print strings for set bits 75 * @pfx: prefix for each line, including log level and prefix string 76 * @bits: bit mask 77 * @strs: string array, indexed by bit position 78 * @strs_size: size of the string array: @strs 79 * 80 * For each set bit in @bits, print the corresponding string in @strs. 81 * If the output length is longer than 80, multiple line will be 82 * printed, with @pfx is printed at the beginning of each line. 83 */ 84 void cper_print_bits(const char *pfx, unsigned int bits, 85 const char * const strs[], unsigned int strs_size) 86 { 87 int i, len = 0; 88 const char *str; 89 char buf[84]; 90 91 for (i = 0; i < strs_size; i++) { 92 if (!(bits & (1U << i))) 93 continue; 94 str = strs[i]; 95 if (!str) 96 continue; 97 if (len && len + strlen(str) + 2 > 80) { 98 printk("%s\n", buf); 99 len = 0; 100 } 101 if (!len) 102 len = snprintf(buf, sizeof(buf), "%s%s", pfx, str); 103 else 104 len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str); 105 } 106 if (len) 107 printk("%s\n", buf); 108 } 109 110 /** 111 * cper_bits_to_str - return a string for set bits 112 * @buf: buffer to store the output string 113 * @buf_size: size of the output string buffer 114 * @bits: bit mask 115 * @strs: string array, indexed by bit position 116 * @strs_size: size of the string array: @strs 117 * 118 * Add to @buf the bitmask in hexadecimal. Then, for each set bit in @bits, 119 * add the corresponding string describing the bit in @strs to @buf. 120 * 121 * A typical example is:: 122 * 123 * const char * const bits[] = { 124 * "bit 3 name", 125 * "bit 4 name", 126 * "bit 5 name", 127 * }; 128 * char str[120]; 129 * unsigned int bitmask = BIT(3) | BIT(5); 130 * #define MASK GENMASK(5,3) 131 * 132 * cper_bits_to_str(str, sizeof(str), FIELD_GET(MASK, bitmask), 133 * bits, ARRAY_SIZE(bits)); 134 * 135 * The above code fills the string ``str`` with ``bit 3 name|bit 5 name``. 136 * 137 * Return: number of bytes stored or an error code if lower than zero. 138 */ 139 int cper_bits_to_str(char *buf, int buf_size, unsigned long bits, 140 const char * const strs[], unsigned int strs_size) 141 { 142 int len = buf_size; 143 char *str = buf; 144 int i, size; 145 146 *buf = '\0'; 147 148 for_each_set_bit(i, &bits, strs_size) { 149 if (!(bits & BIT_ULL(i))) 150 continue; 151 152 if (*buf && len > 0) { 153 *str = '|'; 154 len--; 155 str++; 156 } 157 158 size = strscpy(str, strs[i], len); 159 if (size < 0) 160 return size; 161 162 len -= size; 163 str += size; 164 } 165 return len - buf_size; 166 } 167 EXPORT_SYMBOL_GPL(cper_bits_to_str); 168 169 static const char * const proc_type_strs[] = { 170 "IA32/X64", 171 "IA64", 172 "ARM", 173 }; 174 175 static const char * const proc_isa_strs[] = { 176 "IA32", 177 "IA64", 178 "X64", 179 "ARM A32/T32", 180 "ARM A64", 181 }; 182 183 const char * const cper_proc_error_type_strs[] = { 184 "cache error", 185 "TLB error", 186 "bus error", 187 "micro-architectural error", 188 }; 189 190 static const char * const proc_op_strs[] = { 191 "unknown or generic", 192 "data read", 193 "data write", 194 "instruction execution", 195 }; 196 197 static const char * const proc_flag_strs[] = { 198 "restartable", 199 "precise IP", 200 "overflow", 201 "corrected", 202 }; 203 204 static void cper_print_proc_generic(const char *pfx, 205 const struct cper_sec_proc_generic *proc) 206 { 207 if (proc->validation_bits & CPER_PROC_VALID_TYPE) 208 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, 209 proc->proc_type < ARRAY_SIZE(proc_type_strs) ? 210 proc_type_strs[proc->proc_type] : "unknown"); 211 if (proc->validation_bits & CPER_PROC_VALID_ISA) 212 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, 213 proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ? 214 proc_isa_strs[proc->proc_isa] : "unknown"); 215 if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { 216 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); 217 cper_print_bits(pfx, proc->proc_error_type, 218 cper_proc_error_type_strs, 219 ARRAY_SIZE(cper_proc_error_type_strs)); 220 } 221 if (proc->validation_bits & CPER_PROC_VALID_OPERATION) 222 printk("%s""operation: %d, %s\n", pfx, proc->operation, 223 proc->operation < ARRAY_SIZE(proc_op_strs) ? 224 proc_op_strs[proc->operation] : "unknown"); 225 if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { 226 printk("%s""flags: 0x%02x\n", pfx, proc->flags); 227 cper_print_bits(pfx, proc->flags, proc_flag_strs, 228 ARRAY_SIZE(proc_flag_strs)); 229 } 230 if (proc->validation_bits & CPER_PROC_VALID_LEVEL) 231 printk("%s""level: %d\n", pfx, proc->level); 232 if (proc->validation_bits & CPER_PROC_VALID_VERSION) 233 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version); 234 if (proc->validation_bits & CPER_PROC_VALID_ID) 235 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id); 236 if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS) 237 printk("%s""target_address: 0x%016llx\n", 238 pfx, proc->target_addr); 239 if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID) 240 printk("%s""requestor_id: 0x%016llx\n", 241 pfx, proc->requestor_id); 242 if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID) 243 printk("%s""responder_id: 0x%016llx\n", 244 pfx, proc->responder_id); 245 if (proc->validation_bits & CPER_PROC_VALID_IP) 246 printk("%s""IP: 0x%016llx\n", pfx, proc->ip); 247 } 248 249 static const char * const mem_err_type_strs[] = { 250 "unknown", 251 "no error", 252 "single-bit ECC", 253 "multi-bit ECC", 254 "single-symbol chipkill ECC", 255 "multi-symbol chipkill ECC", 256 "master abort", 257 "target abort", 258 "parity error", 259 "watchdog timeout", 260 "invalid address", 261 "mirror Broken", 262 "memory sparing", 263 "scrub corrected error", 264 "scrub uncorrected error", 265 "physical memory map-out event", 266 }; 267 268 const char *cper_mem_err_type_str(unsigned int etype) 269 { 270 return etype < ARRAY_SIZE(mem_err_type_strs) ? 271 mem_err_type_strs[etype] : "unknown"; 272 } 273 EXPORT_SYMBOL_GPL(cper_mem_err_type_str); 274 275 const char *cper_mem_err_status_str(u64 status) 276 { 277 switch ((status >> 8) & 0xff) { 278 case 1: return "Error detected internal to the component"; 279 case 4: return "Storage error in DRAM memory"; 280 case 5: return "Storage error in TLB"; 281 case 6: return "Storage error in cache"; 282 case 7: return "Error in one or more functional units"; 283 case 8: return "Component failed self test"; 284 case 9: return "Overflow or undervalue of internal queue"; 285 case 16: return "Error detected in the bus"; 286 case 17: return "Virtual address not found on IO-TLB or IO-PDIR"; 287 case 18: return "Improper access error"; 288 case 19: return "Access to a memory address which is not mapped to any component"; 289 case 20: return "Loss of Lockstep"; 290 case 21: return "Response not associated with a request"; 291 case 22: return "Bus parity error - must also set the A, C, or D Bits"; 292 case 23: return "Detection of a protocol error"; 293 case 24: return "Detection of a PATH_ERROR"; 294 case 25: return "Bus operation timeout"; 295 case 26: return "A read was issued to data that has been poisoned"; 296 default: return "Reserved"; 297 } 298 } 299 EXPORT_SYMBOL_GPL(cper_mem_err_status_str); 300 301 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) 302 { 303 u32 len, n; 304 305 if (!msg) 306 return 0; 307 308 n = 0; 309 len = CPER_REC_LEN; 310 if (mem->validation_bits & CPER_MEM_VALID_NODE) 311 n += scnprintf(msg + n, len - n, "node:%d ", mem->node); 312 if (mem->validation_bits & CPER_MEM_VALID_CARD) 313 n += scnprintf(msg + n, len - n, "card:%d ", mem->card); 314 if (mem->validation_bits & CPER_MEM_VALID_MODULE) 315 n += scnprintf(msg + n, len - n, "module:%d ", mem->module); 316 if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) 317 n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank); 318 if (mem->validation_bits & CPER_MEM_VALID_BANK) 319 n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank); 320 if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP) 321 n += scnprintf(msg + n, len - n, "bank_group:%d ", 322 mem->bank >> CPER_MEM_BANK_GROUP_SHIFT); 323 if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS) 324 n += scnprintf(msg + n, len - n, "bank_address:%d ", 325 mem->bank & CPER_MEM_BANK_ADDRESS_MASK); 326 if (mem->validation_bits & CPER_MEM_VALID_DEVICE) 327 n += scnprintf(msg + n, len - n, "device:%d ", mem->device); 328 if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) { 329 u32 row = mem->row; 330 331 row |= cper_get_mem_extension(mem->validation_bits, mem->extended); 332 n += scnprintf(msg + n, len - n, "row:%d ", row); 333 } 334 if (mem->validation_bits & CPER_MEM_VALID_COLUMN) 335 n += scnprintf(msg + n, len - n, "column:%d ", mem->column); 336 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) 337 n += scnprintf(msg + n, len - n, "bit_position:%d ", 338 mem->bit_pos); 339 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) 340 n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ", 341 mem->requestor_id); 342 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) 343 n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ", 344 mem->responder_id); 345 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) 346 n += scnprintf(msg + n, len - n, "target_id:0x%016llx ", 347 mem->target_id); 348 if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID) 349 n += scnprintf(msg + n, len - n, "chip_id:%d ", 350 mem->extended >> CPER_MEM_CHIP_ID_SHIFT); 351 352 return n; 353 } 354 EXPORT_SYMBOL_GPL(cper_mem_err_location); 355 356 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg) 357 { 358 u32 len, n; 359 const char *bank = NULL, *device = NULL; 360 361 if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE)) 362 return 0; 363 364 len = CPER_REC_LEN; 365 dmi_memdev_name(mem->mem_dev_handle, &bank, &device); 366 if (bank && device) 367 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device); 368 else 369 n = snprintf(msg, len, 370 "DIMM location: not present. DMI handle: 0x%.4x ", 371 mem->mem_dev_handle); 372 373 return n; 374 } 375 EXPORT_SYMBOL_GPL(cper_dimm_err_location); 376 377 void cper_mem_err_pack(const struct cper_sec_mem_err *mem, 378 struct cper_mem_err_compact *cmem) 379 { 380 cmem->validation_bits = mem->validation_bits; 381 cmem->node = mem->node; 382 cmem->card = mem->card; 383 cmem->module = mem->module; 384 cmem->bank = mem->bank; 385 cmem->device = mem->device; 386 cmem->row = mem->row; 387 cmem->column = mem->column; 388 cmem->bit_pos = mem->bit_pos; 389 cmem->requestor_id = mem->requestor_id; 390 cmem->responder_id = mem->responder_id; 391 cmem->target_id = mem->target_id; 392 cmem->extended = mem->extended; 393 cmem->rank = mem->rank; 394 cmem->mem_array_handle = mem->mem_array_handle; 395 cmem->mem_dev_handle = mem->mem_dev_handle; 396 } 397 EXPORT_SYMBOL_GPL(cper_mem_err_pack); 398 399 const char *cper_mem_err_unpack(struct trace_seq *p, 400 struct cper_mem_err_compact *cmem) 401 { 402 const char *ret = trace_seq_buffer_ptr(p); 403 char rcd_decode_str[CPER_REC_LEN]; 404 405 if (cper_mem_err_location(cmem, rcd_decode_str)) 406 trace_seq_printf(p, "%s", rcd_decode_str); 407 if (cper_dimm_err_location(cmem, rcd_decode_str)) 408 trace_seq_printf(p, "%s", rcd_decode_str); 409 trace_seq_putc(p, '\0'); 410 411 return ret; 412 } 413 414 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem, 415 int len) 416 { 417 struct cper_mem_err_compact cmem; 418 char rcd_decode_str[CPER_REC_LEN]; 419 420 /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */ 421 if (len == sizeof(struct cper_sec_mem_err_old) && 422 (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) { 423 pr_err(FW_WARN "valid bits set for fields beyond structure\n"); 424 return; 425 } 426 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) 427 printk("%s error_status: %s (0x%016llx)\n", 428 pfx, cper_mem_err_status_str(mem->error_status), 429 mem->error_status); 430 if (mem->validation_bits & CPER_MEM_VALID_PA) 431 printk("%s""physical_address: 0x%016llx\n", 432 pfx, mem->physical_addr); 433 if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) 434 printk("%s""physical_address_mask: 0x%016llx\n", 435 pfx, mem->physical_addr_mask); 436 cper_mem_err_pack(mem, &cmem); 437 if (cper_mem_err_location(&cmem, rcd_decode_str)) 438 printk("%s%s\n", pfx, rcd_decode_str); 439 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { 440 u8 etype = mem->error_type; 441 printk("%s""error_type: %d, %s\n", pfx, etype, 442 cper_mem_err_type_str(etype)); 443 } 444 if (cper_dimm_err_location(&cmem, rcd_decode_str)) 445 printk("%s%s\n", pfx, rcd_decode_str); 446 } 447 448 static const char * const pcie_port_type_strs[] = { 449 "PCIe end point", 450 "legacy PCI end point", 451 "unknown", 452 "unknown", 453 "root port", 454 "upstream switch port", 455 "downstream switch port", 456 "PCIe to PCI/PCI-X bridge", 457 "PCI/PCI-X to PCIe bridge", 458 "root complex integrated endpoint device", 459 "root complex event collector", 460 }; 461 462 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, 463 const struct acpi_hest_generic_data *gdata) 464 { 465 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) 466 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, 467 pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ? 468 pcie_port_type_strs[pcie->port_type] : "unknown"); 469 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) 470 printk("%s""version: %d.%d\n", pfx, 471 pcie->version.major, pcie->version.minor); 472 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS) 473 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx, 474 pcie->command, pcie->status); 475 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) { 476 const __u8 *p; 477 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx, 478 pcie->device_id.segment, pcie->device_id.bus, 479 pcie->device_id.device, pcie->device_id.function); 480 printk("%s""slot: %d\n", pfx, 481 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT); 482 printk("%s""secondary_bus: 0x%02x\n", pfx, 483 pcie->device_id.secondary_bus); 484 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx, 485 pcie->device_id.vendor_id, pcie->device_id.device_id); 486 p = pcie->device_id.class_code; 487 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]); 488 } 489 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER) 490 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx, 491 pcie->serial_number.lower, pcie->serial_number.upper); 492 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS) 493 printk( 494 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 495 pfx, pcie->bridge.secondary_status, pcie->bridge.control); 496 497 /* 498 * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time). 499 * 500 * Fatal errors call __ghes_panic() before AER handler prints this. 501 */ 502 if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { 503 struct aer_capability_regs *aer; 504 505 aer = (struct aer_capability_regs *)pcie->aer_info; 506 printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n", 507 pfx, aer->cor_status, aer->cor_mask); 508 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", 509 pfx, aer->uncor_status, aer->uncor_mask); 510 printk("%saer_uncor_severity: 0x%08x\n", 511 pfx, aer->uncor_severity); 512 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx, 513 aer->header_log.dw[0], aer->header_log.dw[1], 514 aer->header_log.dw[2], aer->header_log.dw[3]); 515 } 516 } 517 518 static const char * const fw_err_rec_type_strs[] = { 519 "IPF SAL Error Record", 520 "SOC Firmware Error Record Type1 (Legacy CrashLog Support)", 521 "SOC Firmware Error Record Type2", 522 }; 523 524 static void cper_print_fw_err(const char *pfx, 525 struct acpi_hest_generic_data *gdata, 526 const struct cper_sec_fw_err_rec_ref *fw_err) 527 { 528 void *buf = acpi_hest_get_payload(gdata); 529 u32 offset, length = gdata->error_data_length; 530 531 printk("%s""Firmware Error Record Type: %s\n", pfx, 532 fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ? 533 fw_err_rec_type_strs[fw_err->record_type] : "unknown"); 534 printk("%s""Revision: %d\n", pfx, fw_err->revision); 535 536 /* Record Type based on UEFI 2.7 */ 537 if (fw_err->revision == 0) { 538 printk("%s""Record Identifier: %08llx\n", pfx, 539 fw_err->record_identifier); 540 } else if (fw_err->revision == 2) { 541 printk("%s""Record Identifier: %pUl\n", pfx, 542 &fw_err->record_identifier_guid); 543 } 544 545 /* 546 * The FW error record may contain trailing data beyond the 547 * structure defined by the specification. As the fields 548 * defined (and hence the offset of any trailing data) vary 549 * with the revision, set the offset to account for this 550 * variation. 551 */ 552 if (fw_err->revision == 0) { 553 /* record_identifier_guid not defined */ 554 offset = offsetof(struct cper_sec_fw_err_rec_ref, 555 record_identifier_guid); 556 } else if (fw_err->revision == 1) { 557 /* record_identifier not defined */ 558 offset = offsetof(struct cper_sec_fw_err_rec_ref, 559 record_identifier); 560 } else { 561 offset = sizeof(*fw_err); 562 } 563 564 buf += offset; 565 length -= offset; 566 567 print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); 568 } 569 570 static void cper_print_tstamp(const char *pfx, 571 struct acpi_hest_generic_data_v300 *gdata) 572 { 573 __u8 hour, min, sec, day, mon, year, century, *timestamp; 574 575 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) { 576 timestamp = (__u8 *)&(gdata->time_stamp); 577 sec = bcd2bin(timestamp[0]); 578 min = bcd2bin(timestamp[1]); 579 hour = bcd2bin(timestamp[2]); 580 day = bcd2bin(timestamp[4]); 581 mon = bcd2bin(timestamp[5]); 582 year = bcd2bin(timestamp[6]); 583 century = bcd2bin(timestamp[7]); 584 585 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx, 586 (timestamp[3] & 0x1 ? "precise " : "imprecise "), 587 century, year, mon, day, hour, min, sec); 588 } 589 } 590 591 struct ignore_section { 592 guid_t guid; 593 const char *name; 594 }; 595 596 static const struct ignore_section ignore_sections[] = { 597 { .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" }, 598 { .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" }, 599 { .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" }, 600 }; 601 602 static void 603 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata, 604 int sec_no) 605 { 606 guid_t *sec_type = (guid_t *)gdata->section_type; 607 __u16 severity; 608 char newpfx[64]; 609 610 if (acpi_hest_get_version(gdata) >= 3) 611 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata); 612 613 severity = gdata->error_severity; 614 printk("%s""Error %d, type: %s\n", pfx, sec_no, 615 cper_severity_str(severity)); 616 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) 617 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id); 618 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) 619 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); 620 621 snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 622 623 for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) { 624 if (guid_equal(sec_type, &ignore_sections[i].guid)) { 625 printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name); 626 return; 627 } 628 } 629 630 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) { 631 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); 632 633 printk("%s""section_type: general processor error\n", newpfx); 634 if (gdata->error_data_length >= sizeof(*proc_err)) 635 cper_print_proc_generic(newpfx, proc_err); 636 else 637 goto err_section_too_small; 638 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { 639 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); 640 641 printk("%s""section_type: memory error\n", newpfx); 642 if (gdata->error_data_length >= 643 sizeof(struct cper_sec_mem_err_old)) 644 cper_print_mem(newpfx, mem_err, 645 gdata->error_data_length); 646 else 647 goto err_section_too_small; 648 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { 649 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata); 650 651 printk("%s""section_type: PCIe error\n", newpfx); 652 if (gdata->error_data_length >= sizeof(*pcie)) 653 cper_print_pcie(newpfx, pcie, gdata); 654 else 655 goto err_section_too_small; 656 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) 657 } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { 658 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata); 659 660 printk("%ssection_type: ARM processor error\n", newpfx); 661 if (gdata->error_data_length >= sizeof(*arm_err)) 662 cper_print_proc_arm(newpfx, arm_err); 663 else 664 goto err_section_too_small; 665 #endif 666 #if defined(CONFIG_UEFI_CPER_X86) 667 } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) { 668 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata); 669 670 printk("%ssection_type: IA32/X64 processor error\n", newpfx); 671 if (gdata->error_data_length >= sizeof(*ia_err)) 672 cper_print_proc_ia(newpfx, ia_err); 673 else 674 goto err_section_too_small; 675 #endif 676 } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) { 677 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata); 678 679 printk("%ssection_type: Firmware Error Record Reference\n", 680 newpfx); 681 /* The minimal FW Error Record contains 16 bytes */ 682 if (gdata->error_data_length >= SZ_16) 683 cper_print_fw_err(newpfx, gdata, fw_err); 684 else 685 goto err_section_too_small; 686 } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) { 687 struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata); 688 689 printk("%ssection_type: CXL Protocol Error\n", newpfx); 690 if (gdata->error_data_length >= sizeof(*prot_err)) 691 cxl_cper_print_prot_err(newpfx, prot_err); 692 else 693 goto err_section_too_small; 694 } else { 695 const void *err = acpi_hest_get_payload(gdata); 696 697 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type); 698 printk("%ssection length: %#x\n", newpfx, 699 gdata->error_data_length); 700 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err, 701 gdata->error_data_length, true); 702 } 703 704 return; 705 706 err_section_too_small: 707 pr_err(FW_WARN "error section length is too small\n"); 708 } 709 710 void cper_estatus_print(const char *pfx, 711 const struct acpi_hest_generic_status *estatus) 712 { 713 struct acpi_hest_generic_data *gdata; 714 int sec_no = 0; 715 char newpfx[64]; 716 __u16 severity; 717 718 severity = estatus->error_severity; 719 if (severity == CPER_SEV_CORRECTED) 720 printk("%s%s\n", pfx, 721 "It has been corrected by h/w " 722 "and requires no further action"); 723 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); 724 snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 725 726 apei_estatus_for_each_section(estatus, gdata) { 727 cper_estatus_print_section(newpfx, gdata, sec_no); 728 sec_no++; 729 } 730 } 731 EXPORT_SYMBOL_GPL(cper_estatus_print); 732 733 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus) 734 { 735 if (estatus->data_length && 736 estatus->data_length < sizeof(struct acpi_hest_generic_data)) 737 return -EINVAL; 738 if (estatus->raw_data_length && 739 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) 740 return -EINVAL; 741 742 return 0; 743 } 744 EXPORT_SYMBOL_GPL(cper_estatus_check_header); 745 746 int cper_estatus_check(const struct acpi_hest_generic_status *estatus) 747 { 748 struct acpi_hest_generic_data *gdata; 749 unsigned int data_len, record_size; 750 int rc; 751 752 rc = cper_estatus_check_header(estatus); 753 if (rc) 754 return rc; 755 756 data_len = estatus->data_length; 757 758 apei_estatus_for_each_section(estatus, gdata) { 759 if (acpi_hest_get_size(gdata) > data_len) 760 return -EINVAL; 761 762 record_size = acpi_hest_get_record_size(gdata); 763 if (record_size > data_len) 764 return -EINVAL; 765 766 data_len -= record_size; 767 } 768 if (data_len) 769 return -EINVAL; 770 771 return 0; 772 } 773 EXPORT_SYMBOL_GPL(cper_estatus_check); 774