1 /*
2  * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
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 
17 #include <nrd_ras.h>
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  */
populate_cpu_err_data(cpu_err_info * cpu_info,uint64_t security_state)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
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 */
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 */
nrd_ras_cpu_intr_handler(const struct err_record_info * err_rec,int probe_data,const struct err_handler_data * const data)146 int nrd_ras_cpu_intr_handler(const struct err_record_info *err_rec,
147 				int probe_data,
148 				const struct err_handler_data *const data)
149 {
150 	struct nrd_ras_ev_map *ras_map;
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 	 */
189 	ras_map = nrd_find_ras_event_map_by_intr(intr);
190 	if (ras_map == NULL) {
191 		ERROR("NRD: RAS error info for interrupt id: %d not found\n",
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 }
212