linux/drivers/firmware/efi/cper-arm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * UEFI Common Platform Error Record (CPER) support
   4 *
   5 * Copyright (C) 2017, The Linux Foundation. All rights reserved.
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/time.h>
  11#include <linux/cper.h>
  12#include <linux/dmi.h>
  13#include <linux/acpi.h>
  14#include <linux/pci.h>
  15#include <linux/aer.h>
  16#include <linux/printk.h>
  17#include <linux/bcd.h>
  18#include <acpi/ghes.h>
  19#include <ras/ras_event.h>
  20
  21static const char * const arm_reg_ctx_strs[] = {
  22        "AArch32 general purpose registers",
  23        "AArch32 EL1 context registers",
  24        "AArch32 EL2 context registers",
  25        "AArch32 secure context registers",
  26        "AArch64 general purpose registers",
  27        "AArch64 EL1 context registers",
  28        "AArch64 EL2 context registers",
  29        "AArch64 EL3 context registers",
  30        "Misc. system register structure",
  31};
  32
  33static const char * const arm_err_trans_type_strs[] = {
  34        "Instruction",
  35        "Data Access",
  36        "Generic",
  37};
  38
  39static const char * const arm_bus_err_op_strs[] = {
  40        "Generic error (type cannot be determined)",
  41        "Generic read (type of instruction or data request cannot be determined)",
  42        "Generic write (type of instruction of data request cannot be determined)",
  43        "Data read",
  44        "Data write",
  45        "Instruction fetch",
  46        "Prefetch",
  47};
  48
  49static const char * const arm_cache_err_op_strs[] = {
  50        "Generic error (type cannot be determined)",
  51        "Generic read (type of instruction or data request cannot be determined)",
  52        "Generic write (type of instruction of data request cannot be determined)",
  53        "Data read",
  54        "Data write",
  55        "Instruction fetch",
  56        "Prefetch",
  57        "Eviction",
  58        "Snooping (processor initiated a cache snoop that resulted in an error)",
  59        "Snooped (processor raised a cache error caused by another processor or device snooping its cache)",
  60        "Management",
  61};
  62
  63static const char * const arm_tlb_err_op_strs[] = {
  64        "Generic error (type cannot be determined)",
  65        "Generic read (type of instruction or data request cannot be determined)",
  66        "Generic write (type of instruction of data request cannot be determined)",
  67        "Data read",
  68        "Data write",
  69        "Instruction fetch",
  70        "Prefetch",
  71        "Local management operation (processor initiated a TLB management operation that resulted in an error)",
  72        "External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)",
  73};
  74
  75static const char * const arm_bus_err_part_type_strs[] = {
  76        "Local processor originated request",
  77        "Local processor responded to request",
  78        "Local processor observed",
  79        "Generic",
  80};
  81
  82static const char * const arm_bus_err_addr_space_strs[] = {
  83        "External Memory Access",
  84        "Internal Memory Access",
  85        "Unknown",
  86        "Device Memory Access",
  87};
  88
  89static void cper_print_arm_err_info(const char *pfx, u32 type,
  90                                    u64 error_info)
  91{
  92        u8 trans_type, op_type, level, participation_type, address_space;
  93        u16 mem_attributes;
  94        bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
  95        bool time_out, access_mode;
  96
  97        /* If the type is unknown, bail. */
  98        if (type > CPER_ARM_MAX_TYPE)
  99                return;
 100
 101        /*
 102         * Vendor type errors have error information values that are vendor
 103         * specific.
 104         */
 105        if (type == CPER_ARM_VENDOR_ERROR)
 106                return;
 107
 108        if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
 109                trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
 110                              & CPER_ARM_ERR_TRANSACTION_MASK);
 111                if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
 112                        printk("%stransaction type: %s\n", pfx,
 113                               arm_err_trans_type_strs[trans_type]);
 114                }
 115        }
 116
 117        if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
 118                op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
 119                           & CPER_ARM_ERR_OPERATION_MASK);
 120                switch (type) {
 121                case CPER_ARM_CACHE_ERROR:
 122                        if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
 123                                printk("%soperation type: %s\n", pfx,
 124                                       arm_cache_err_op_strs[op_type]);
 125                        }
 126                        break;
 127                case CPER_ARM_TLB_ERROR:
 128                        if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
 129                                printk("%soperation type: %s\n", pfx,
 130                                       arm_tlb_err_op_strs[op_type]);
 131                        }
 132                        break;
 133                case CPER_ARM_BUS_ERROR:
 134                        if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
 135                                printk("%soperation type: %s\n", pfx,
 136                                       arm_bus_err_op_strs[op_type]);
 137                        }
 138                        break;
 139                }
 140        }
 141
 142        if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
 143                level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
 144                         & CPER_ARM_ERR_LEVEL_MASK);
 145                switch (type) {
 146                case CPER_ARM_CACHE_ERROR:
 147                        printk("%scache level: %d\n", pfx, level);
 148                        break;
 149                case CPER_ARM_TLB_ERROR:
 150                        printk("%sTLB level: %d\n", pfx, level);
 151                        break;
 152                case CPER_ARM_BUS_ERROR:
 153                        printk("%saffinity level at which the bus error occurred: %d\n",
 154                               pfx, level);
 155                        break;
 156                }
 157        }
 158
 159        if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
 160                proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
 161                                        & CPER_ARM_ERR_PC_CORRUPT_MASK);
 162                if (proc_context_corrupt)
 163                        printk("%sprocessor context corrupted\n", pfx);
 164                else
 165                        printk("%sprocessor context not corrupted\n", pfx);
 166        }
 167
 168        if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
 169                corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
 170                             & CPER_ARM_ERR_CORRECTED_MASK);
 171                if (corrected)
 172                        printk("%sthe error has been corrected\n", pfx);
 173                else
 174                        printk("%sthe error has not been corrected\n", pfx);
 175        }
 176
 177        if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
 178                precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
 179                              & CPER_ARM_ERR_PRECISE_PC_MASK);
 180                if (precise_pc)
 181                        printk("%sPC is precise\n", pfx);
 182                else
 183                        printk("%sPC is imprecise\n", pfx);
 184        }
 185
 186        if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
 187                restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
 188                                  & CPER_ARM_ERR_RESTARTABLE_PC_MASK);
 189                if (restartable_pc)
 190                        printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
 191        }
 192
 193        /* The rest of the fields are specific to bus errors */
 194        if (type != CPER_ARM_BUS_ERROR)
 195                return;
 196
 197        if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
 198                participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
 199                                      & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
 200                if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
 201                        printk("%sparticipation type: %s\n", pfx,
 202                               arm_bus_err_part_type_strs[participation_type]);
 203                }
 204        }
 205
 206        if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
 207                time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
 208                            & CPER_ARM_ERR_TIME_OUT_MASK);
 209                if (time_out)
 210                        printk("%srequest timed out\n", pfx);
 211        }
 212
 213        if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
 214                address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
 215                                 & CPER_ARM_ERR_ADDRESS_SPACE_MASK);
 216                if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
 217                        printk("%saddress space: %s\n", pfx,
 218                               arm_bus_err_addr_space_strs[address_space]);
 219                }
 220        }
 221
 222        if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
 223                mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
 224                                  & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
 225                printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
 226        }
 227
 228        if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
 229                access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
 230                               & CPER_ARM_ERR_ACCESS_MODE_MASK);
 231                if (access_mode)
 232                        printk("%saccess mode: normal\n", pfx);
 233                else
 234                        printk("%saccess mode: secure\n", pfx);
 235        }
 236}
 237
 238void cper_print_proc_arm(const char *pfx,
 239                         const struct cper_sec_proc_arm *proc)
 240{
 241        int i, len, max_ctx_type;
 242        struct cper_arm_err_info *err_info;
 243        struct cper_arm_ctx_info *ctx_info;
 244        char newpfx[64], infopfx[64];
 245
 246        printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
 247
 248        len = proc->section_length - (sizeof(*proc) +
 249                proc->err_info_num * (sizeof(*err_info)));
 250        if (len < 0) {
 251                printk("%ssection length: %d\n", pfx, proc->section_length);
 252                printk("%ssection length is too small\n", pfx);
 253                printk("%sfirmware-generated error record is incorrect\n", pfx);
 254                printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
 255                return;
 256        }
 257
 258        if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
 259                printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
 260                        pfx, proc->mpidr);
 261
 262        if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
 263                printk("%serror affinity level: %d\n", pfx,
 264                        proc->affinity_level);
 265
 266        if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
 267                printk("%srunning state: 0x%x\n", pfx, proc->running_state);
 268                printk("%sPower State Coordination Interface state: %d\n",
 269                        pfx, proc->psci_state);
 270        }
 271
 272        snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
 273
 274        err_info = (struct cper_arm_err_info *)(proc + 1);
 275        for (i = 0; i < proc->err_info_num; i++) {
 276                printk("%sError info structure %d:\n", pfx, i);
 277
 278                printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
 279
 280                if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
 281                        if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
 282                                printk("%sfirst error captured\n", newpfx);
 283                        if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
 284                                printk("%slast error captured\n", newpfx);
 285                        if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
 286                                printk("%spropagated error captured\n",
 287                                       newpfx);
 288                        if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
 289                                printk("%soverflow occurred, error info is incomplete\n",
 290                                       newpfx);
 291                }
 292
 293                printk("%serror_type: %d, %s\n", newpfx, err_info->type,
 294                        err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
 295                        cper_proc_error_type_strs[err_info->type] : "unknown");
 296                if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
 297                        printk("%serror_info: 0x%016llx\n", newpfx,
 298                               err_info->error_info);
 299                        snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
 300                        cper_print_arm_err_info(infopfx, err_info->type,
 301                                                err_info->error_info);
 302                }
 303                if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
 304                        printk("%svirtual fault address: 0x%016llx\n",
 305                                newpfx, err_info->virt_fault_addr);
 306                if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
 307                        printk("%sphysical fault address: 0x%016llx\n",
 308                                newpfx, err_info->physical_fault_addr);
 309                err_info += 1;
 310        }
 311
 312        ctx_info = (struct cper_arm_ctx_info *)err_info;
 313        max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
 314        for (i = 0; i < proc->context_info_num; i++) {
 315                int size = sizeof(*ctx_info) + ctx_info->size;
 316
 317                printk("%sContext info structure %d:\n", pfx, i);
 318                if (len < size) {
 319                        printk("%ssection length is too small\n", newpfx);
 320                        printk("%sfirmware-generated error record is incorrect\n", pfx);
 321                        return;
 322                }
 323                if (ctx_info->type > max_ctx_type) {
 324                        printk("%sInvalid context type: %d (max: %d)\n",
 325                                newpfx, ctx_info->type, max_ctx_type);
 326                        return;
 327                }
 328                printk("%sregister context type: %s\n", newpfx,
 329                        arm_reg_ctx_strs[ctx_info->type]);
 330                print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
 331                                (ctx_info + 1), ctx_info->size, 0);
 332                len -= size;
 333                ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
 334        }
 335
 336        if (len > 0) {
 337                printk("%sVendor specific error info has %u bytes:\n", pfx,
 338                       len);
 339                print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
 340                                len, true);
 341        }
 342}
 343