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 buf_size - len; 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 if (offset > length) { 564 printk("%s""error section length is too small: offset=%d, length=%d\n", 565 pfx, offset, length); 566 return; 567 } 568 569 buf += offset; 570 length -= offset; 571 572 print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); 573 } 574 575 static void cper_print_tstamp(const char *pfx, 576 struct acpi_hest_generic_data_v300 *gdata) 577 { 578 __u8 hour, min, sec, day, mon, year, century, *timestamp; 579 580 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) { 581 timestamp = (__u8 *)&(gdata->time_stamp); 582 sec = bcd2bin(timestamp[0]); 583 min = bcd2bin(timestamp[1]); 584 hour = bcd2bin(timestamp[2]); 585 day = bcd2bin(timestamp[4]); 586 mon = bcd2bin(timestamp[5]); 587 year = bcd2bin(timestamp[6]); 588 century = bcd2bin(timestamp[7]); 589 590 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx, 591 (timestamp[3] & 0x1 ? "precise " : "imprecise "), 592 century, year, mon, day, hour, min, sec); 593 } 594 } 595 596 struct ignore_section { 597 guid_t guid; 598 const char *name; 599 }; 600 601 static const struct ignore_section ignore_sections[] = { 602 { .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" }, 603 { .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" }, 604 { .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" }, 605 }; 606 607 static void 608 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata, 609 int sec_no) 610 { 611 guid_t *sec_type = (guid_t *)gdata->section_type; 612 __u16 severity; 613 char newpfx[64]; 614 615 if (acpi_hest_get_version(gdata) >= 3) 616 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata); 617 618 severity = gdata->error_severity; 619 printk("%s""Error %d, type: %s\n", pfx, sec_no, 620 cper_severity_str(severity)); 621 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) 622 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id); 623 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) 624 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); 625 626 snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 627 628 for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) { 629 if (guid_equal(sec_type, &ignore_sections[i].guid)) { 630 printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name); 631 return; 632 } 633 } 634 635 if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) { 636 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); 637 638 printk("%s""section_type: general processor error\n", newpfx); 639 if (gdata->error_data_length >= sizeof(*proc_err)) 640 cper_print_proc_generic(newpfx, proc_err); 641 else 642 goto err_section_too_small; 643 } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { 644 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); 645 646 printk("%s""section_type: memory error\n", newpfx); 647 if (gdata->error_data_length >= 648 sizeof(struct cper_sec_mem_err_old)) 649 cper_print_mem(newpfx, mem_err, 650 gdata->error_data_length); 651 else 652 goto err_section_too_small; 653 } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { 654 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata); 655 656 printk("%s""section_type: PCIe error\n", newpfx); 657 if (gdata->error_data_length >= sizeof(*pcie)) 658 cper_print_pcie(newpfx, pcie, gdata); 659 else 660 goto err_section_too_small; 661 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) 662 } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { 663 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata); 664 665 printk("%ssection_type: ARM processor error\n", newpfx); 666 if (gdata->error_data_length >= sizeof(*arm_err)) 667 cper_print_proc_arm(newpfx, arm_err, 668 gdata->error_data_length); 669 else 670 goto err_section_too_small; 671 #endif 672 #if defined(CONFIG_UEFI_CPER_X86) 673 } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) { 674 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata); 675 676 printk("%ssection_type: IA32/X64 processor error\n", newpfx); 677 if (gdata->error_data_length >= sizeof(*ia_err)) 678 cper_print_proc_ia(newpfx, ia_err); 679 else 680 goto err_section_too_small; 681 #endif 682 } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) { 683 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata); 684 685 printk("%ssection_type: Firmware Error Record Reference\n", 686 newpfx); 687 /* The minimal FW Error Record contains 16 bytes */ 688 if (gdata->error_data_length >= SZ_16) 689 cper_print_fw_err(newpfx, gdata, fw_err); 690 else 691 goto err_section_too_small; 692 } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) { 693 struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata); 694 695 printk("%ssection_type: CXL Protocol Error\n", newpfx); 696 if (gdata->error_data_length >= sizeof(*prot_err)) 697 cxl_cper_print_prot_err(newpfx, prot_err); 698 else 699 goto err_section_too_small; 700 } else { 701 const void *err = acpi_hest_get_payload(gdata); 702 703 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type); 704 printk("%ssection length: %#x\n", newpfx, 705 gdata->error_data_length); 706 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err, 707 gdata->error_data_length, true); 708 } 709 710 return; 711 712 err_section_too_small: 713 pr_err(FW_WARN "error section length is too small\n"); 714 } 715 716 void cper_estatus_print(const char *pfx, 717 const struct acpi_hest_generic_status *estatus) 718 { 719 struct acpi_hest_generic_data *gdata; 720 int sec_no = 0; 721 char newpfx[64]; 722 __u16 severity; 723 724 severity = estatus->error_severity; 725 if (severity == CPER_SEV_CORRECTED) 726 printk("%s%s\n", pfx, 727 "It has been corrected by h/w " 728 "and requires no further action"); 729 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); 730 snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 731 732 apei_estatus_for_each_section(estatus, gdata) { 733 cper_estatus_print_section(newpfx, gdata, sec_no); 734 sec_no++; 735 } 736 } 737 EXPORT_SYMBOL_GPL(cper_estatus_print); 738 739 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus) 740 { 741 if (estatus->data_length && 742 estatus->data_length < sizeof(struct acpi_hest_generic_data)) 743 return -EINVAL; 744 if (estatus->raw_data_length && 745 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) 746 return -EINVAL; 747 748 return 0; 749 } 750 EXPORT_SYMBOL_GPL(cper_estatus_check_header); 751 752 int cper_estatus_check(const struct acpi_hest_generic_status *estatus) 753 { 754 struct acpi_hest_generic_data *gdata; 755 unsigned int data_len, record_size; 756 int rc; 757 758 rc = cper_estatus_check_header(estatus); 759 if (rc) 760 return rc; 761 762 data_len = estatus->data_length; 763 764 apei_estatus_for_each_section(estatus, gdata) { 765 if (acpi_hest_get_size(gdata) > data_len) 766 return -EINVAL; 767 768 record_size = acpi_hest_get_record_size(gdata); 769 if (record_size > data_len) 770 return -EINVAL; 771 772 data_len -= record_size; 773 } 774 if (data_len) 775 return -EINVAL; 776 777 return 0; 778 } 779 EXPORT_SYMBOL_GPL(cper_estatus_check); 780