1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <string.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h> 11*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h> 12*91f16700Schasinglulu #include <lib/extensions/ras.h> 13*91f16700Schasinglulu #include <plat/common/platform.h> 14*91f16700Schasinglulu #include <services/sdei.h> 15*91f16700Schasinglulu #include <services/spm_mm_svc.h> 16*91f16700Schasinglulu 17*91f16700Schasinglulu #include <sgi_ras.h> 18*91f16700Schasinglulu 19*91f16700Schasinglulu #define CPU_CONTEXT_REG_GPR_ARR_SIZE 32 20*91f16700Schasinglulu #define CPU_CONTEXT_REG_EL1_ARR_SIZE 17 21*91f16700Schasinglulu #define CPU_CONTEXT_REG_EL2_ARR_SIZE 16 22*91f16700Schasinglulu #define CPU_CONTEXT_REG_EL3_ARR_SIZE 10 23*91f16700Schasinglulu 24*91f16700Schasinglulu /* 25*91f16700Schasinglulu * MM Communicate message header GUID to indicate the payload is intended for 26*91f16700Schasinglulu * CPU MM driver. 27*91f16700Schasinglulu */ 28*91f16700Schasinglulu struct efi_guid cpu_ecc_event_guid = { 29*91f16700Schasinglulu 0x2c1b3bfc, 0x42cd, 0x4a66, 30*91f16700Schasinglulu {0xac, 0xd1, 0xa4, 0xd1, 0x63, 0xe9, 0x90, 0xf6} 31*91f16700Schasinglulu }; 32*91f16700Schasinglulu 33*91f16700Schasinglulu /* 34*91f16700Schasinglulu * CPU error information data structure communicated as part of MM 35*91f16700Schasinglulu * Communication data payload. 36*91f16700Schasinglulu */ 37*91f16700Schasinglulu typedef struct { 38*91f16700Schasinglulu uint64_t ErrStatus; 39*91f16700Schasinglulu uint64_t ErrMisc0; 40*91f16700Schasinglulu uint64_t ErrAddr; 41*91f16700Schasinglulu uint64_t SecurityState; 42*91f16700Schasinglulu uint64_t ErrCtxGpr[CPU_CONTEXT_REG_GPR_ARR_SIZE]; 43*91f16700Schasinglulu uint64_t ErrCtxEl1Reg[CPU_CONTEXT_REG_EL1_ARR_SIZE]; 44*91f16700Schasinglulu uint64_t ErrCtxEl2Reg[CPU_CONTEXT_REG_EL2_ARR_SIZE]; 45*91f16700Schasinglulu uint64_t ErrCtxEl3Reg[CPU_CONTEXT_REG_EL3_ARR_SIZE]; 46*91f16700Schasinglulu } cpu_err_info; 47*91f16700Schasinglulu 48*91f16700Schasinglulu /* 49*91f16700Schasinglulu * Reads the CPU context and error information from the relevant registers and 50*91f16700Schasinglulu * populates the CPU error information data structure. 51*91f16700Schasinglulu */ 52*91f16700Schasinglulu static void populate_cpu_err_data(cpu_err_info *cpu_info, 53*91f16700Schasinglulu uint64_t security_state) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu void *ctx; 56*91f16700Schasinglulu 57*91f16700Schasinglulu ctx = cm_get_context(security_state); 58*91f16700Schasinglulu 59*91f16700Schasinglulu cpu_info->ErrStatus = read_erxstatus_el1(); 60*91f16700Schasinglulu cpu_info->ErrMisc0 = read_erxmisc0_el1(); 61*91f16700Schasinglulu cpu_info->ErrAddr = read_erxaddr_el1(); 62*91f16700Schasinglulu cpu_info->SecurityState = security_state; 63*91f16700Schasinglulu 64*91f16700Schasinglulu /* populate CPU EL1 context information. */ 65*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[0] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 66*91f16700Schasinglulu CTX_ELR_EL1); 67*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[1] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 68*91f16700Schasinglulu CTX_ESR_EL1); 69*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[2] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 70*91f16700Schasinglulu CTX_FAR_EL1); 71*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[3] = read_isr_el1(); 72*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[4] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 73*91f16700Schasinglulu CTX_MAIR_EL1); 74*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[5] = read_midr_el1(); 75*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[6] = read_mpidr_el1(); 76*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[7] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 77*91f16700Schasinglulu CTX_SCTLR_EL1); 78*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[8] = read_ctx_reg(get_gpregs_ctx(ctx), 79*91f16700Schasinglulu CTX_GPREG_SP_EL0); 80*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[9] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 81*91f16700Schasinglulu CTX_SP_EL1); 82*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[10] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 83*91f16700Schasinglulu CTX_SPSR_EL1); 84*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[11] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 85*91f16700Schasinglulu CTX_TCR_EL1); 86*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[12] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 87*91f16700Schasinglulu CTX_TPIDR_EL0); 88*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[13] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 89*91f16700Schasinglulu CTX_TPIDR_EL1); 90*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[14] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 91*91f16700Schasinglulu CTX_TPIDRRO_EL0); 92*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[15] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 93*91f16700Schasinglulu CTX_TTBR0_EL1); 94*91f16700Schasinglulu cpu_info->ErrCtxEl1Reg[16] = read_ctx_reg(get_el1_sysregs_ctx(ctx), 95*91f16700Schasinglulu CTX_TTBR1_EL1); 96*91f16700Schasinglulu 97*91f16700Schasinglulu #if CTX_INCLUDE_EL2_REGS 98*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[0] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 99*91f16700Schasinglulu CTX_ELR_EL2); 100*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[1] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 101*91f16700Schasinglulu CTX_ESR_EL2); 102*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[2] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 103*91f16700Schasinglulu CTX_FAR_EL2); 104*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[3] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 105*91f16700Schasinglulu CTX_HACR_EL2); 106*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[4] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 107*91f16700Schasinglulu CTX_HCR_EL2); 108*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[5] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 109*91f16700Schasinglulu CTX_HPFAR_EL2); 110*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[6] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 111*91f16700Schasinglulu CTX_MAIR_EL2); 112*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[7] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 113*91f16700Schasinglulu CTX_SCTLR_EL2); 114*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[8] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 115*91f16700Schasinglulu CTX_SP_EL2); 116*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[9] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 117*91f16700Schasinglulu CTX_SPSR_EL2); 118*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[10] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 119*91f16700Schasinglulu CTX_TCR_EL2); 120*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[11] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 121*91f16700Schasinglulu CTX_TPIDR_EL2); 122*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[12] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 123*91f16700Schasinglulu CTX_TTBR0_EL2); 124*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[13] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 125*91f16700Schasinglulu CTX_VTCR_EL2); 126*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[14] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 127*91f16700Schasinglulu CTX_VTTBR_EL2); 128*91f16700Schasinglulu cpu_info->ErrCtxEl2Reg[15] = read_ctx_reg(get_el2_sysregs_ctx(ctx), 129*91f16700Schasinglulu CTX_ESR_EL2); 130*91f16700Schasinglulu #endif 131*91f16700Schasinglulu 132*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[0] = read_ctx_reg(get_el3state_ctx(ctx), 133*91f16700Schasinglulu CTX_ELR_EL3); 134*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[1] = read_ctx_reg(get_el3state_ctx(ctx), 135*91f16700Schasinglulu CTX_ESR_EL3); 136*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[2] = read_far_el3(); 137*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[4] = read_mair_el3(); 138*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[5] = read_sctlr_el3(); 139*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[6] = 0; /* sp_el3 */ 140*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[7] = read_tcr_el3(); 141*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[8] = read_tpidr_el3(); 142*91f16700Schasinglulu cpu_info->ErrCtxEl3Reg[9] = read_ttbr0_el3(); 143*91f16700Schasinglulu } 144*91f16700Schasinglulu 145*91f16700Schasinglulu /* CPU RAS interrupt handler */ 146*91f16700Schasinglulu int sgi_ras_cpu_intr_handler(const struct err_record_info *err_rec, 147*91f16700Schasinglulu int probe_data, 148*91f16700Schasinglulu const struct err_handler_data *const data) 149*91f16700Schasinglulu { 150*91f16700Schasinglulu struct sgi_ras_ev_map *ras_map; 151*91f16700Schasinglulu mm_communicate_header_t *header; 152*91f16700Schasinglulu cpu_err_info cpu_info = {0}; 153*91f16700Schasinglulu uint64_t clear_status; 154*91f16700Schasinglulu uint32_t intr; 155*91f16700Schasinglulu int ret; 156*91f16700Schasinglulu 157*91f16700Schasinglulu cm_el1_sysregs_context_save(NON_SECURE); 158*91f16700Schasinglulu intr = data->interrupt; 159*91f16700Schasinglulu 160*91f16700Schasinglulu INFO("[CPU RAS] CPU intr received = %d on cpu_id = %d\n", 161*91f16700Schasinglulu intr, plat_my_core_pos()); 162*91f16700Schasinglulu 163*91f16700Schasinglulu INFO("[CPU RAS] ERXMISC0_EL1 = 0x%lx\n", read_erxmisc0_el1()); 164*91f16700Schasinglulu INFO("[CPU RAS] ERXSTATUS_EL1 = 0x%lx\n", read_erxstatus_el1()); 165*91f16700Schasinglulu INFO("[CPU RAS] ERXADDR_EL1 = 0x%lx\n", read_erxaddr_el1()); 166*91f16700Schasinglulu 167*91f16700Schasinglulu /* Populate CPU Error Source Information. */ 168*91f16700Schasinglulu populate_cpu_err_data(&cpu_info, get_interrupt_src_ss(data->flags)); 169*91f16700Schasinglulu 170*91f16700Schasinglulu /* Clear the interrupt. */ 171*91f16700Schasinglulu clear_status = read_erxstatus_el1(); 172*91f16700Schasinglulu write_erxstatus_el1(clear_status); 173*91f16700Schasinglulu plat_ic_end_of_interrupt(intr); 174*91f16700Schasinglulu 175*91f16700Schasinglulu header = (void *) PLAT_SPM_BUF_BASE; 176*91f16700Schasinglulu memset(header, 0, sizeof(*header)); 177*91f16700Schasinglulu memcpy(&header->data, &cpu_info, sizeof(cpu_info)); 178*91f16700Schasinglulu header->message_len = sizeof(cpu_info); 179*91f16700Schasinglulu memcpy(&header->header_guid, (void *) &cpu_ecc_event_guid, 180*91f16700Schasinglulu sizeof(struct efi_guid)); 181*91f16700Schasinglulu 182*91f16700Schasinglulu spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0, 183*91f16700Schasinglulu plat_my_core_pos()); 184*91f16700Schasinglulu 185*91f16700Schasinglulu /* 186*91f16700Schasinglulu * Find if this is a RAS interrupt. There must be an event against 187*91f16700Schasinglulu * this interrupt 188*91f16700Schasinglulu */ 189*91f16700Schasinglulu ras_map = sgi_find_ras_event_map_by_intr(intr); 190*91f16700Schasinglulu if (ras_map == NULL) { 191*91f16700Schasinglulu ERROR("SGI: RAS error info for interrupt id: %d not found\n", 192*91f16700Schasinglulu intr); 193*91f16700Schasinglulu return -1; 194*91f16700Schasinglulu } 195*91f16700Schasinglulu 196*91f16700Schasinglulu /* Dispatch the event to the SDEI client */ 197*91f16700Schasinglulu ret = sdei_dispatch_event(ras_map->sdei_ev_num); 198*91f16700Schasinglulu if (ret != 0) { 199*91f16700Schasinglulu /* 200*91f16700Schasinglulu * sdei_dispatch_event() may return failing result in some 201*91f16700Schasinglulu * cases, for example kernel may not have registered a handler 202*91f16700Schasinglulu * or RAS event may happen early during boot. We restore the NS 203*91f16700Schasinglulu * context when sdei_dispatch_event() returns failing result. 204*91f16700Schasinglulu */ 205*91f16700Schasinglulu ERROR("SDEI dispatch failed: %d", ret); 206*91f16700Schasinglulu cm_el1_sysregs_context_restore(NON_SECURE); 207*91f16700Schasinglulu cm_set_next_eret_context(NON_SECURE); 208*91f16700Schasinglulu } 209*91f16700Schasinglulu 210*91f16700Schasinglulu return ret; 211*91f16700Schasinglulu } 212