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