xref: /arm-trusted-firmware/plat/arm/css/sgi/ras/sgi_ras_cpu.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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