Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * UEFI Common Platform Error Record (CPER) support
0004  *
0005  * Copyright (C) 2017, The Linux Foundation. All rights reserved.
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/time.h>
0011 #include <linux/cper.h>
0012 #include <linux/dmi.h>
0013 #include <linux/acpi.h>
0014 #include <linux/pci.h>
0015 #include <linux/aer.h>
0016 #include <linux/printk.h>
0017 #include <linux/bcd.h>
0018 #include <acpi/ghes.h>
0019 #include <ras/ras_event.h>
0020 
0021 static const char * const arm_reg_ctx_strs[] = {
0022     "AArch32 general purpose registers",
0023     "AArch32 EL1 context registers",
0024     "AArch32 EL2 context registers",
0025     "AArch32 secure context registers",
0026     "AArch64 general purpose registers",
0027     "AArch64 EL1 context registers",
0028     "AArch64 EL2 context registers",
0029     "AArch64 EL3 context registers",
0030     "Misc. system register structure",
0031 };
0032 
0033 static const char * const arm_err_trans_type_strs[] = {
0034     "Instruction",
0035     "Data Access",
0036     "Generic",
0037 };
0038 
0039 static const char * const arm_bus_err_op_strs[] = {
0040     "Generic error (type cannot be determined)",
0041     "Generic read (type of instruction or data request cannot be determined)",
0042     "Generic write (type of instruction of data request cannot be determined)",
0043     "Data read",
0044     "Data write",
0045     "Instruction fetch",
0046     "Prefetch",
0047 };
0048 
0049 static const char * const arm_cache_err_op_strs[] = {
0050     "Generic error (type cannot be determined)",
0051     "Generic read (type of instruction or data request cannot be determined)",
0052     "Generic write (type of instruction of data request cannot be determined)",
0053     "Data read",
0054     "Data write",
0055     "Instruction fetch",
0056     "Prefetch",
0057     "Eviction",
0058     "Snooping (processor initiated a cache snoop that resulted in an error)",
0059     "Snooped (processor raised a cache error caused by another processor or device snooping its cache)",
0060     "Management",
0061 };
0062 
0063 static const char * const arm_tlb_err_op_strs[] = {
0064     "Generic error (type cannot be determined)",
0065     "Generic read (type of instruction or data request cannot be determined)",
0066     "Generic write (type of instruction of data request cannot be determined)",
0067     "Data read",
0068     "Data write",
0069     "Instruction fetch",
0070     "Prefetch",
0071     "Local management operation (processor initiated a TLB management operation that resulted in an error)",
0072     "External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)",
0073 };
0074 
0075 static const char * const arm_bus_err_part_type_strs[] = {
0076     "Local processor originated request",
0077     "Local processor responded to request",
0078     "Local processor observed",
0079     "Generic",
0080 };
0081 
0082 static const char * const arm_bus_err_addr_space_strs[] = {
0083     "External Memory Access",
0084     "Internal Memory Access",
0085     "Unknown",
0086     "Device Memory Access",
0087 };
0088 
0089 static void cper_print_arm_err_info(const char *pfx, u32 type,
0090                     u64 error_info)
0091 {
0092     u8 trans_type, op_type, level, participation_type, address_space;
0093     u16 mem_attributes;
0094     bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
0095     bool time_out, access_mode;
0096 
0097     /* If the type is unknown, bail. */
0098     if (type > CPER_ARM_MAX_TYPE)
0099         return;
0100 
0101     /*
0102      * Vendor type errors have error information values that are vendor
0103      * specific.
0104      */
0105     if (type == CPER_ARM_VENDOR_ERROR)
0106         return;
0107 
0108     if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
0109         trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
0110                   & CPER_ARM_ERR_TRANSACTION_MASK);
0111         if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
0112             printk("%stransaction type: %s\n", pfx,
0113                    arm_err_trans_type_strs[trans_type]);
0114         }
0115     }
0116 
0117     if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
0118         op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
0119                & CPER_ARM_ERR_OPERATION_MASK);
0120         switch (type) {
0121         case CPER_ARM_CACHE_ERROR:
0122             if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
0123                 printk("%soperation type: %s\n", pfx,
0124                        arm_cache_err_op_strs[op_type]);
0125             }
0126             break;
0127         case CPER_ARM_TLB_ERROR:
0128             if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
0129                 printk("%soperation type: %s\n", pfx,
0130                        arm_tlb_err_op_strs[op_type]);
0131             }
0132             break;
0133         case CPER_ARM_BUS_ERROR:
0134             if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
0135                 printk("%soperation type: %s\n", pfx,
0136                        arm_bus_err_op_strs[op_type]);
0137             }
0138             break;
0139         }
0140     }
0141 
0142     if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
0143         level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
0144              & CPER_ARM_ERR_LEVEL_MASK);
0145         switch (type) {
0146         case CPER_ARM_CACHE_ERROR:
0147             printk("%scache level: %d\n", pfx, level);
0148             break;
0149         case CPER_ARM_TLB_ERROR:
0150             printk("%sTLB level: %d\n", pfx, level);
0151             break;
0152         case CPER_ARM_BUS_ERROR:
0153             printk("%saffinity level at which the bus error occurred: %d\n",
0154                    pfx, level);
0155             break;
0156         }
0157     }
0158 
0159     if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
0160         proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
0161                     & CPER_ARM_ERR_PC_CORRUPT_MASK);
0162         if (proc_context_corrupt)
0163             printk("%sprocessor context corrupted\n", pfx);
0164         else
0165             printk("%sprocessor context not corrupted\n", pfx);
0166     }
0167 
0168     if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
0169         corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
0170                  & CPER_ARM_ERR_CORRECTED_MASK);
0171         if (corrected)
0172             printk("%sthe error has been corrected\n", pfx);
0173         else
0174             printk("%sthe error has not been corrected\n", pfx);
0175     }
0176 
0177     if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
0178         precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
0179                   & CPER_ARM_ERR_PRECISE_PC_MASK);
0180         if (precise_pc)
0181             printk("%sPC is precise\n", pfx);
0182         else
0183             printk("%sPC is imprecise\n", pfx);
0184     }
0185 
0186     if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
0187         restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
0188                   & CPER_ARM_ERR_RESTARTABLE_PC_MASK);
0189         if (restartable_pc)
0190             printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
0191     }
0192 
0193     /* The rest of the fields are specific to bus errors */
0194     if (type != CPER_ARM_BUS_ERROR)
0195         return;
0196 
0197     if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
0198         participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
0199                       & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
0200         if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
0201             printk("%sparticipation type: %s\n", pfx,
0202                    arm_bus_err_part_type_strs[participation_type]);
0203         }
0204     }
0205 
0206     if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
0207         time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
0208                 & CPER_ARM_ERR_TIME_OUT_MASK);
0209         if (time_out)
0210             printk("%srequest timed out\n", pfx);
0211     }
0212 
0213     if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
0214         address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
0215                  & CPER_ARM_ERR_ADDRESS_SPACE_MASK);
0216         if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
0217             printk("%saddress space: %s\n", pfx,
0218                    arm_bus_err_addr_space_strs[address_space]);
0219         }
0220     }
0221 
0222     if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
0223         mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
0224                   & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
0225         printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
0226     }
0227 
0228     if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
0229         access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
0230                    & CPER_ARM_ERR_ACCESS_MODE_MASK);
0231         if (access_mode)
0232             printk("%saccess mode: normal\n", pfx);
0233         else
0234             printk("%saccess mode: secure\n", pfx);
0235     }
0236 }
0237 
0238 void cper_print_proc_arm(const char *pfx,
0239              const struct cper_sec_proc_arm *proc)
0240 {
0241     int i, len, max_ctx_type;
0242     struct cper_arm_err_info *err_info;
0243     struct cper_arm_ctx_info *ctx_info;
0244     char newpfx[64], infopfx[64];
0245 
0246     printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
0247 
0248     len = proc->section_length - (sizeof(*proc) +
0249         proc->err_info_num * (sizeof(*err_info)));
0250     if (len < 0) {
0251         printk("%ssection length: %d\n", pfx, proc->section_length);
0252         printk("%ssection length is too small\n", pfx);
0253         printk("%sfirmware-generated error record is incorrect\n", pfx);
0254         printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
0255         return;
0256     }
0257 
0258     if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
0259         printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
0260             pfx, proc->mpidr);
0261 
0262     if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
0263         printk("%serror affinity level: %d\n", pfx,
0264             proc->affinity_level);
0265 
0266     if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
0267         printk("%srunning state: 0x%x\n", pfx, proc->running_state);
0268         printk("%sPower State Coordination Interface state: %d\n",
0269             pfx, proc->psci_state);
0270     }
0271 
0272     snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
0273 
0274     err_info = (struct cper_arm_err_info *)(proc + 1);
0275     for (i = 0; i < proc->err_info_num; i++) {
0276         printk("%sError info structure %d:\n", pfx, i);
0277 
0278         printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
0279 
0280         if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
0281             if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
0282                 printk("%sfirst error captured\n", newpfx);
0283             if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
0284                 printk("%slast error captured\n", newpfx);
0285             if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
0286                 printk("%spropagated error captured\n",
0287                        newpfx);
0288             if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
0289                 printk("%soverflow occurred, error info is incomplete\n",
0290                        newpfx);
0291         }
0292 
0293         printk("%serror_type: %d, %s\n", newpfx, err_info->type,
0294             err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
0295             cper_proc_error_type_strs[err_info->type] : "unknown");
0296         if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
0297             printk("%serror_info: 0x%016llx\n", newpfx,
0298                    err_info->error_info);
0299             snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
0300             cper_print_arm_err_info(infopfx, err_info->type,
0301                         err_info->error_info);
0302         }
0303         if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
0304             printk("%svirtual fault address: 0x%016llx\n",
0305                 newpfx, err_info->virt_fault_addr);
0306         if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
0307             printk("%sphysical fault address: 0x%016llx\n",
0308                 newpfx, err_info->physical_fault_addr);
0309         err_info += 1;
0310     }
0311 
0312     ctx_info = (struct cper_arm_ctx_info *)err_info;
0313     max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
0314     for (i = 0; i < proc->context_info_num; i++) {
0315         int size = sizeof(*ctx_info) + ctx_info->size;
0316 
0317         printk("%sContext info structure %d:\n", pfx, i);
0318         if (len < size) {
0319             printk("%ssection length is too small\n", newpfx);
0320             printk("%sfirmware-generated error record is incorrect\n", pfx);
0321             return;
0322         }
0323         if (ctx_info->type > max_ctx_type) {
0324             printk("%sInvalid context type: %d (max: %d)\n",
0325                 newpfx, ctx_info->type, max_ctx_type);
0326             return;
0327         }
0328         printk("%sregister context type: %s\n", newpfx,
0329             arm_reg_ctx_strs[ctx_info->type]);
0330         print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
0331                 (ctx_info + 1), ctx_info->size, 0);
0332         len -= size;
0333         ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
0334     }
0335 
0336     if (len > 0) {
0337         printk("%sVendor specific error info has %u bytes:\n", pfx,
0338                len);
0339         print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
0340                 len, true);
0341     }
0342 }