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