// SPDX-License-Identifier: GPL-2.0 /* * UEFI Common Platform Error Record (CPER) support * * Copyright (C) 2010, Intel Corp. * Author: Huang Ying <ying.huang@intel.com> * * CPER is the format used to describe platform hardware error by * various tables, such as ERST, BERT and HEST etc. * * For more information about CPER, please refer to Appendix N of UEFI * Specification version 2.4.
*/
/* * CPER record ID need to be unique even after reboot, because record * ID is used as index for ERST storage, while CPER records from * multiple boot may co-exist in ERST.
*/
u64 cper_next_record_id(void)
{ static atomic64_t seq;
if (!atomic64_read(&seq)) {
time64_t time = ktime_get_real_seconds();
/* * This code is unlikely to still be needed in year 2106, * but just in case, let's use a few more bits for timestamps * after y2038 to be sure they keep increasing monotonically * for the next few hundred years...
*/ if (time < 0x80000000)
atomic64_set(&seq, (ktime_get_real_seconds()) << 32); else
atomic64_set(&seq, 0x8000000000000000ull |
ktime_get_real_seconds() << 24);
}
/* * cper_print_bits - print strings for set bits * @pfx: prefix for each line, including log level and prefix string * @bits: bit mask * @strs: string array, indexed by bit position * @strs_size: size of the string array: @strs * * For each set bit in @bits, print the corresponding string in @strs. * If the output length is longer than 80, multiple line will be * printed, with @pfx is printed at the beginning of each line.
*/ void cper_print_bits(constchar *pfx, unsignedint bits, constchar * const strs[], unsignedint strs_size)
{ int i, len = 0; constchar *str; char buf[84];
for (i = 0; i < strs_size; i++) { if (!(bits & (1U << i))) continue;
str = strs[i]; if (!str) continue; if (len && len + strlen(str) + 2 > 80) {
printk("%s\n", buf);
len = 0;
} if (!len)
len = snprintf(buf, sizeof(buf), "%s%s", pfx, str); else
len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
} if (len)
printk("%s\n", buf);
}
constchar *cper_mem_err_status_str(u64 status)
{ switch ((status >> 8) & 0xff) { case 1: return"Error detected internal to the component"; case 4: return"Storage error in DRAM memory"; case 5: return"Storage error in TLB"; case 6: return"Storage error in cache"; case 7: return"Error in one or more functional units"; case 8: return"Component failed self test"; case 9: return"Overflow or undervalue of internal queue"; case 16: return"Error detected in the bus"; case 17: return"Virtual address not found on IO-TLB or IO-PDIR"; case 18: return"Improper access error"; case 19: return"Access to a memory address which is not mapped to any component"; case 20: return"Loss of Lockstep"; case 21: return"Response not associated with a request"; case 22: return"Bus parity error - must also set the A, C, or D Bits"; case 23: return"Detection of a protocol error"; case 24: return"Detection of a PATH_ERROR"; case 25: return"Bus operation timeout"; case 26: return"A read was issued to data that has been poisoned"; default: return"Reserved";
}
}
EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
{
u32 len, n;
if (!msg) return 0;
n = 0;
len = CPER_REC_LEN; if (mem->validation_bits & CPER_MEM_VALID_NODE)
n += scnprintf(msg + n, len - n, "node:%d ", mem->node); if (mem->validation_bits & CPER_MEM_VALID_CARD)
n += scnprintf(msg + n, len - n, "card:%d ", mem->card); if (mem->validation_bits & CPER_MEM_VALID_MODULE)
n += scnprintf(msg + n, len - n, "module:%d ", mem->module); if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank); if (mem->validation_bits & CPER_MEM_VALID_BANK)
n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank); if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
n += scnprintf(msg + n, len - n, "bank_group:%d ",
mem->bank >> CPER_MEM_BANK_GROUP_SHIFT); if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
n += scnprintf(msg + n, len - n, "bank_address:%d ",
mem->bank & CPER_MEM_BANK_ADDRESS_MASK); if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
n += scnprintf(msg + n, len - n, "device:%d ", mem->device); if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
u32 row = mem->row;
row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
n += scnprintf(msg + n, len - n, "row:%d ", row);
} if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
n += scnprintf(msg + n, len - n, "column:%d ", mem->column); if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
n += scnprintf(msg + n, len - n, "bit_position:%d ",
mem->bit_pos); if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
mem->requestor_id); if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
mem->responder_id); if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
mem->target_id); if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
n += scnprintf(msg + n, len - n, "chip_id:%d ",
mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
/* * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time). * * Fatal errors call __ghes_panic() before AER handler prints this.
*/ if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { struct aer_capability_regs *aer;
/* Record Type based on UEFI 2.7 */ if (fw_err->revision == 0) {
printk("%s""Record Identifier: %08llx\n", pfx,
fw_err->record_identifier);
} elseif (fw_err->revision == 2) {
printk("%s""Record Identifier: %pUl\n", pfx,
&fw_err->record_identifier_guid);
}
/* * The FW error record may contain trailing data beyond the * structure defined by the specification. As the fields * defined (and hence the offset of any trailing data) vary * with the revision, set the offset to account for this * variation.
*/ if (fw_err->revision == 0) { /* record_identifier_guid not defined */
offset = offsetof(struct cper_sec_fw_err_rec_ref,
record_identifier_guid);
} elseif (fw_err->revision == 1) { /* record_identifier not defined */
offset = offsetof(struct cper_sec_fw_err_rec_ref,
record_identifier);
} else {
offset = sizeof(*fw_err);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.