1 /* 2 * UEFI Common Platform Error Record (CPER) support 3 * 4 * Copyright (C) 2010, Intel Corp. 5 * Author: Huang Ying <ying.huang@intel.com> 6 * 7 * CPER is the format used to describe platform hardware error by 8 * various tables, such as ERST, BERT and HEST etc. 9 * 10 * For more information about CPER, please refer to Appendix N of UEFI 11 * Specification version 2.4. 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License version 15 * 2 as published by the Free Software Foundation. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27 #include <linux/kernel.h> 28 #include <linux/module.h> 29 #include <linux/time.h> 30 #include <linux/cper.h> 31 #include <linux/dmi.h> 32 #include <linux/acpi.h> 33 #include <linux/pci.h> 34 #include <linux/aer.h> 35 #include <linux/printk.h> 36 #include <linux/bcd.h> 37 #include <acpi/ghes.h> 38 39 #define INDENT_SP " " 40 41 static char rcd_decode_str[CPER_REC_LEN]; 42 43 /* 44 * CPER record ID need to be unique even after reboot, because record 45 * ID is used as index for ERST storage, while CPER records from 46 * multiple boot may co-exist in ERST. 47 */ 48 u64 cper_next_record_id(void) 49 { 50 static atomic64_t seq; 51 52 if (!atomic64_read(&seq)) 53 atomic64_set(&seq, ((u64)get_seconds()) << 32); 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 += snprintf(buf+len, sizeof(buf)-len, ", %s", str); 105 } 106 if (len) 107 printk("%s\n", buf); 108 } 109 110 static const char * const proc_type_strs[] = { 111 "IA32/X64", 112 "IA64", 113 "ARM", 114 }; 115 116 static const char * const proc_isa_strs[] = { 117 "IA32", 118 "IA64", 119 "X64", 120 "ARM A32/T32", 121 "ARM A64", 122 }; 123 124 static const char * const proc_error_type_strs[] = { 125 "cache error", 126 "TLB error", 127 "bus error", 128 "micro-architectural error", 129 }; 130 131 static const char * const proc_op_strs[] = { 132 "unknown or generic", 133 "data read", 134 "data write", 135 "instruction execution", 136 }; 137 138 static const char * const proc_flag_strs[] = { 139 "restartable", 140 "precise IP", 141 "overflow", 142 "corrected", 143 }; 144 145 static void cper_print_proc_generic(const char *pfx, 146 const struct cper_sec_proc_generic *proc) 147 { 148 if (proc->validation_bits & CPER_PROC_VALID_TYPE) 149 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, 150 proc->proc_type < ARRAY_SIZE(proc_type_strs) ? 151 proc_type_strs[proc->proc_type] : "unknown"); 152 if (proc->validation_bits & CPER_PROC_VALID_ISA) 153 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, 154 proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ? 155 proc_isa_strs[proc->proc_isa] : "unknown"); 156 if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { 157 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); 158 cper_print_bits(pfx, proc->proc_error_type, 159 proc_error_type_strs, 160 ARRAY_SIZE(proc_error_type_strs)); 161 } 162 if (proc->validation_bits & CPER_PROC_VALID_OPERATION) 163 printk("%s""operation: %d, %s\n", pfx, proc->operation, 164 proc->operation < ARRAY_SIZE(proc_op_strs) ? 165 proc_op_strs[proc->operation] : "unknown"); 166 if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { 167 printk("%s""flags: 0x%02x\n", pfx, proc->flags); 168 cper_print_bits(pfx, proc->flags, proc_flag_strs, 169 ARRAY_SIZE(proc_flag_strs)); 170 } 171 if (proc->validation_bits & CPER_PROC_VALID_LEVEL) 172 printk("%s""level: %d\n", pfx, proc->level); 173 if (proc->validation_bits & CPER_PROC_VALID_VERSION) 174 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version); 175 if (proc->validation_bits & CPER_PROC_VALID_ID) 176 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id); 177 if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS) 178 printk("%s""target_address: 0x%016llx\n", 179 pfx, proc->target_addr); 180 if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID) 181 printk("%s""requestor_id: 0x%016llx\n", 182 pfx, proc->requestor_id); 183 if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID) 184 printk("%s""responder_id: 0x%016llx\n", 185 pfx, proc->responder_id); 186 if (proc->validation_bits & CPER_PROC_VALID_IP) 187 printk("%s""IP: 0x%016llx\n", pfx, proc->ip); 188 } 189 190 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) 191 static const char * const arm_reg_ctx_strs[] = { 192 "AArch32 general purpose registers", 193 "AArch32 EL1 context registers", 194 "AArch32 EL2 context registers", 195 "AArch32 secure context registers", 196 "AArch64 general purpose registers", 197 "AArch64 EL1 context registers", 198 "AArch64 EL2 context registers", 199 "AArch64 EL3 context registers", 200 "Misc. system register structure", 201 }; 202 203 static void cper_print_proc_arm(const char *pfx, 204 const struct cper_sec_proc_arm *proc) 205 { 206 int i, len, max_ctx_type; 207 struct cper_arm_err_info *err_info; 208 struct cper_arm_ctx_info *ctx_info; 209 char newpfx[64]; 210 211 printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); 212 213 len = proc->section_length - (sizeof(*proc) + 214 proc->err_info_num * (sizeof(*err_info))); 215 if (len < 0) { 216 printk("%ssection length: %d\n", pfx, proc->section_length); 217 printk("%ssection length is too small\n", pfx); 218 printk("%sfirmware-generated error record is incorrect\n", pfx); 219 printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); 220 return; 221 } 222 223 if (proc->validation_bits & CPER_ARM_VALID_MPIDR) 224 printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n", 225 pfx, proc->mpidr); 226 227 if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL) 228 printk("%serror affinity level: %d\n", pfx, 229 proc->affinity_level); 230 231 if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) { 232 printk("%srunning state: 0x%x\n", pfx, proc->running_state); 233 printk("%sPower State Coordination Interface state: %d\n", 234 pfx, proc->psci_state); 235 } 236 237 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); 238 239 err_info = (struct cper_arm_err_info *)(proc + 1); 240 for (i = 0; i < proc->err_info_num; i++) { 241 printk("%sError info structure %d:\n", pfx, i); 242 243 printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1); 244 245 if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) { 246 if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST) 247 printk("%sfirst error captured\n", newpfx); 248 if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST) 249 printk("%slast error captured\n", newpfx); 250 if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED) 251 printk("%spropagated error captured\n", 252 newpfx); 253 if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW) 254 printk("%soverflow occurred, error info is incomplete\n", 255 newpfx); 256 } 257 258 printk("%serror_type: %d, %s\n", newpfx, err_info->type, 259 err_info->type < ARRAY_SIZE(proc_error_type_strs) ? 260 proc_error_type_strs[err_info->type] : "unknown"); 261 if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) 262 printk("%serror_info: 0x%016llx\n", newpfx, 263 err_info->error_info); 264 if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR) 265 printk("%svirtual fault address: 0x%016llx\n", 266 newpfx, err_info->virt_fault_addr); 267 if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR) 268 printk("%sphysical fault address: 0x%016llx\n", 269 newpfx, err_info->physical_fault_addr); 270 err_info += 1; 271 } 272 273 ctx_info = (struct cper_arm_ctx_info *)err_info; 274 max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1; 275 for (i = 0; i < proc->context_info_num; i++) { 276 int size = sizeof(*ctx_info) + ctx_info->size; 277 278 printk("%sContext info structure %d:\n", pfx, i); 279 if (len < size) { 280 printk("%ssection length is too small\n", newpfx); 281 printk("%sfirmware-generated error record is incorrect\n", pfx); 282 return; 283 } 284 if (ctx_info->type > max_ctx_type) { 285 printk("%sInvalid context type: %d (max: %d)\n", 286 newpfx, ctx_info->type, max_ctx_type); 287 return; 288 } 289 printk("%sregister context type: %s\n", newpfx, 290 arm_reg_ctx_strs[ctx_info->type]); 291 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, 292 (ctx_info + 1), ctx_info->size, 0); 293 len -= size; 294 ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size); 295 } 296 297 if (len > 0) { 298 printk("%sVendor specific error info has %u bytes:\n", pfx, 299 len); 300 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info, 301 len, true); 302 } 303 } 304 #endif 305 306 static const char * const mem_err_type_strs[] = { 307 "unknown", 308 "no error", 309 "single-bit ECC", 310 "multi-bit ECC", 311 "single-symbol chipkill ECC", 312 "multi-symbol chipkill ECC", 313 "master abort", 314 "target abort", 315 "parity error", 316 "watchdog timeout", 317 "invalid address", 318 "mirror Broken", 319 "memory sparing", 320 "scrub corrected error", 321 "scrub uncorrected error", 322 "physical memory map-out event", 323 }; 324 325 const char *cper_mem_err_type_str(unsigned int etype) 326 { 327 return etype < ARRAY_SIZE(mem_err_type_strs) ? 328 mem_err_type_strs[etype] : "unknown"; 329 } 330 EXPORT_SYMBOL_GPL(cper_mem_err_type_str); 331 332 static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) 333 { 334 u32 len, n; 335 336 if (!msg) 337 return 0; 338 339 n = 0; 340 len = CPER_REC_LEN - 1; 341 if (mem->validation_bits & CPER_MEM_VALID_NODE) 342 n += scnprintf(msg + n, len - n, "node: %d ", mem->node); 343 if (mem->validation_bits & CPER_MEM_VALID_CARD) 344 n += scnprintf(msg + n, len - n, "card: %d ", mem->card); 345 if (mem->validation_bits & CPER_MEM_VALID_MODULE) 346 n += scnprintf(msg + n, len - n, "module: %d ", mem->module); 347 if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) 348 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank); 349 if (mem->validation_bits & CPER_MEM_VALID_BANK) 350 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank); 351 if (mem->validation_bits & CPER_MEM_VALID_DEVICE) 352 n += scnprintf(msg + n, len - n, "device: %d ", mem->device); 353 if (mem->validation_bits & CPER_MEM_VALID_ROW) 354 n += scnprintf(msg + n, len - n, "row: %d ", mem->row); 355 if (mem->validation_bits & CPER_MEM_VALID_COLUMN) 356 n += scnprintf(msg + n, len - n, "column: %d ", mem->column); 357 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) 358 n += scnprintf(msg + n, len - n, "bit_position: %d ", 359 mem->bit_pos); 360 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) 361 n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ", 362 mem->requestor_id); 363 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) 364 n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ", 365 mem->responder_id); 366 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) 367 scnprintf(msg + n, len - n, "target_id: 0x%016llx ", 368 mem->target_id); 369 370 msg[n] = '\0'; 371 return n; 372 } 373 374 static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg) 375 { 376 u32 len, n; 377 const char *bank = NULL, *device = NULL; 378 379 if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE)) 380 return 0; 381 382 n = 0; 383 len = CPER_REC_LEN - 1; 384 dmi_memdev_name(mem->mem_dev_handle, &bank, &device); 385 if (bank && device) 386 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device); 387 else 388 n = snprintf(msg, len, 389 "DIMM location: not present. DMI handle: 0x%.4x ", 390 mem->mem_dev_handle); 391 392 msg[n] = '\0'; 393 return n; 394 } 395 396 void cper_mem_err_pack(const struct cper_sec_mem_err *mem, 397 struct cper_mem_err_compact *cmem) 398 { 399 cmem->validation_bits = mem->validation_bits; 400 cmem->node = mem->node; 401 cmem->card = mem->card; 402 cmem->module = mem->module; 403 cmem->bank = mem->bank; 404 cmem->device = mem->device; 405 cmem->row = mem->row; 406 cmem->column = mem->column; 407 cmem->bit_pos = mem->bit_pos; 408 cmem->requestor_id = mem->requestor_id; 409 cmem->responder_id = mem->responder_id; 410 cmem->target_id = mem->target_id; 411 cmem->rank = mem->rank; 412 cmem->mem_array_handle = mem->mem_array_handle; 413 cmem->mem_dev_handle = mem->mem_dev_handle; 414 } 415 416 const char *cper_mem_err_unpack(struct trace_seq *p, 417 struct cper_mem_err_compact *cmem) 418 { 419 const char *ret = trace_seq_buffer_ptr(p); 420 421 if (cper_mem_err_location(cmem, rcd_decode_str)) 422 trace_seq_printf(p, "%s", rcd_decode_str); 423 if (cper_dimm_err_location(cmem, rcd_decode_str)) 424 trace_seq_printf(p, "%s", rcd_decode_str); 425 trace_seq_putc(p, '\0'); 426 427 return ret; 428 } 429 430 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem, 431 int len) 432 { 433 struct cper_mem_err_compact cmem; 434 435 /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */ 436 if (len == sizeof(struct cper_sec_mem_err_old) && 437 (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) { 438 pr_err(FW_WARN "valid bits set for fields beyond structure\n"); 439 return; 440 } 441 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) 442 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); 443 if (mem->validation_bits & CPER_MEM_VALID_PA) 444 printk("%s""physical_address: 0x%016llx\n", 445 pfx, mem->physical_addr); 446 if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) 447 printk("%s""physical_address_mask: 0x%016llx\n", 448 pfx, mem->physical_addr_mask); 449 cper_mem_err_pack(mem, &cmem); 450 if (cper_mem_err_location(&cmem, rcd_decode_str)) 451 printk("%s%s\n", pfx, rcd_decode_str); 452 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { 453 u8 etype = mem->error_type; 454 printk("%s""error_type: %d, %s\n", pfx, etype, 455 cper_mem_err_type_str(etype)); 456 } 457 if (cper_dimm_err_location(&cmem, rcd_decode_str)) 458 printk("%s%s\n", pfx, rcd_decode_str); 459 } 460 461 static const char * const pcie_port_type_strs[] = { 462 "PCIe end point", 463 "legacy PCI end point", 464 "unknown", 465 "unknown", 466 "root port", 467 "upstream switch port", 468 "downstream switch port", 469 "PCIe to PCI/PCI-X bridge", 470 "PCI/PCI-X to PCIe bridge", 471 "root complex integrated endpoint device", 472 "root complex event collector", 473 }; 474 475 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, 476 const struct acpi_hest_generic_data *gdata) 477 { 478 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) 479 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, 480 pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ? 481 pcie_port_type_strs[pcie->port_type] : "unknown"); 482 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) 483 printk("%s""version: %d.%d\n", pfx, 484 pcie->version.major, pcie->version.minor); 485 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS) 486 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx, 487 pcie->command, pcie->status); 488 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) { 489 const __u8 *p; 490 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx, 491 pcie->device_id.segment, pcie->device_id.bus, 492 pcie->device_id.device, pcie->device_id.function); 493 printk("%s""slot: %d\n", pfx, 494 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT); 495 printk("%s""secondary_bus: 0x%02x\n", pfx, 496 pcie->device_id.secondary_bus); 497 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx, 498 pcie->device_id.vendor_id, pcie->device_id.device_id); 499 p = pcie->device_id.class_code; 500 printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]); 501 } 502 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER) 503 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx, 504 pcie->serial_number.lower, pcie->serial_number.upper); 505 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS) 506 printk( 507 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 508 pfx, pcie->bridge.secondary_status, pcie->bridge.control); 509 } 510 511 static void cper_print_tstamp(const char *pfx, 512 struct acpi_hest_generic_data_v300 *gdata) 513 { 514 __u8 hour, min, sec, day, mon, year, century, *timestamp; 515 516 if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) { 517 timestamp = (__u8 *)&(gdata->time_stamp); 518 sec = bcd2bin(timestamp[0]); 519 min = bcd2bin(timestamp[1]); 520 hour = bcd2bin(timestamp[2]); 521 day = bcd2bin(timestamp[4]); 522 mon = bcd2bin(timestamp[5]); 523 year = bcd2bin(timestamp[6]); 524 century = bcd2bin(timestamp[7]); 525 526 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx, 527 (timestamp[3] & 0x1 ? "precise " : "imprecise "), 528 century, year, mon, day, hour, min, sec); 529 } 530 } 531 532 static void 533 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata, 534 int sec_no) 535 { 536 uuid_le *sec_type = (uuid_le *)gdata->section_type; 537 __u16 severity; 538 char newpfx[64]; 539 540 if (acpi_hest_get_version(gdata) >= 3) 541 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata); 542 543 severity = gdata->error_severity; 544 printk("%s""Error %d, type: %s\n", pfx, sec_no, 545 cper_severity_str(severity)); 546 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) 547 printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id); 548 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) 549 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); 550 551 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); 552 if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { 553 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); 554 555 printk("%s""section_type: general processor error\n", newpfx); 556 if (gdata->error_data_length >= sizeof(*proc_err)) 557 cper_print_proc_generic(newpfx, proc_err); 558 else 559 goto err_section_too_small; 560 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { 561 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); 562 563 printk("%s""section_type: memory error\n", newpfx); 564 if (gdata->error_data_length >= 565 sizeof(struct cper_sec_mem_err_old)) 566 cper_print_mem(newpfx, mem_err, 567 gdata->error_data_length); 568 else 569 goto err_section_too_small; 570 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { 571 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata); 572 573 printk("%s""section_type: PCIe error\n", newpfx); 574 if (gdata->error_data_length >= sizeof(*pcie)) 575 cper_print_pcie(newpfx, pcie, gdata); 576 else 577 goto err_section_too_small; 578 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) 579 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) { 580 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata); 581 582 printk("%ssection_type: ARM processor error\n", newpfx); 583 if (gdata->error_data_length >= sizeof(*arm_err)) 584 cper_print_proc_arm(newpfx, arm_err); 585 else 586 goto err_section_too_small; 587 #endif 588 } else { 589 const void *err = acpi_hest_get_payload(gdata); 590 591 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type); 592 printk("%ssection length: %#x\n", newpfx, 593 gdata->error_data_length); 594 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err, 595 gdata->error_data_length, true); 596 } 597 598 return; 599 600 err_section_too_small: 601 pr_err(FW_WARN "error section length is too small\n"); 602 } 603 604 void cper_estatus_print(const char *pfx, 605 const struct acpi_hest_generic_status *estatus) 606 { 607 struct acpi_hest_generic_data *gdata; 608 unsigned int data_len; 609 int sec_no = 0; 610 char newpfx[64]; 611 __u16 severity; 612 613 severity = estatus->error_severity; 614 if (severity == CPER_SEV_CORRECTED) 615 printk("%s%s\n", pfx, 616 "It has been corrected by h/w " 617 "and requires no further action"); 618 printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); 619 data_len = estatus->data_length; 620 gdata = (struct acpi_hest_generic_data *)(estatus + 1); 621 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); 622 623 while (data_len >= acpi_hest_get_size(gdata)) { 624 cper_estatus_print_section(newpfx, gdata, sec_no); 625 data_len -= acpi_hest_get_record_size(gdata); 626 gdata = acpi_hest_get_next(gdata); 627 sec_no++; 628 } 629 } 630 EXPORT_SYMBOL_GPL(cper_estatus_print); 631 632 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus) 633 { 634 if (estatus->data_length && 635 estatus->data_length < sizeof(struct acpi_hest_generic_data)) 636 return -EINVAL; 637 if (estatus->raw_data_length && 638 estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) 639 return -EINVAL; 640 641 return 0; 642 } 643 EXPORT_SYMBOL_GPL(cper_estatus_check_header); 644 645 int cper_estatus_check(const struct acpi_hest_generic_status *estatus) 646 { 647 struct acpi_hest_generic_data *gdata; 648 unsigned int data_len, gedata_len; 649 int rc; 650 651 rc = cper_estatus_check_header(estatus); 652 if (rc) 653 return rc; 654 data_len = estatus->data_length; 655 gdata = (struct acpi_hest_generic_data *)(estatus + 1); 656 657 while (data_len >= acpi_hest_get_size(gdata)) { 658 gedata_len = acpi_hest_get_error_length(gdata); 659 if (gedata_len > data_len - acpi_hest_get_size(gdata)) 660 return -EINVAL; 661 662 data_len -= acpi_hest_get_record_size(gdata); 663 gdata = acpi_hest_get_next(gdata); 664 } 665 if (data_len) 666 return -EINVAL; 667 668 return 0; 669 } 670 EXPORT_SYMBOL_GPL(cper_estatus_check); 671