1/*
2 * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7
8#include <assert_macros.S>
9#include <asm_macros.S>
10#include <assert_macros.S>
11#include <bl31/ea_handle.h>
12#include <context.h>
13#include <lib/extensions/ras_arch.h>
14#include <cpu_macros.S>
15#include <context.h>
16
17	.globl	handle_lower_el_ea_esb
18	.globl  handle_lower_el_async_ea
19	.globl	enter_lower_el_sync_ea
20	.globl	enter_lower_el_async_ea
21
22
23/*
24 * Function to delegate External Aborts synchronized by ESB instruction at EL3
25 * vector entry. This function assumes GP registers x0-x29 have been saved, and
26 * are available for use. It delegates the handling of the EA to platform
27 * handler, and returns only upon successfully handling the EA; otherwise
28 * panics. On return from this function, the original exception handler is
29 * expected to resume.
30 */
31func handle_lower_el_ea_esb
32	mov	x0, #ERROR_EA_ESB
33	mrs	x1, DISR_EL1
34	b	ea_proceed
35endfunc handle_lower_el_ea_esb
36
37
38/*
39 * This function forms the tail end of Synchronous Exception entry from lower
40 * EL, and expects to handle Synchronous External Aborts from lower EL and CPU
41 * Implementation Defined Exceptions. If any other kind of exception is detected,
42 * then this function reports unhandled exception.
43 *
44 * Since it's part of exception vector, this function doesn't expect any GP
45 * registers to have been saved. It delegates the handling of the EA to platform
46 * handler, and upon successfully handling the EA, exits EL3; otherwise panics.
47 */
48func enter_lower_el_sync_ea
49	/*
50	 * Explicitly save x30 so as to free up a register and to enable
51	 * branching.
52	 */
53	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
54
55	mrs	x30, esr_el3
56	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
57
58	/* Check for I/D aborts from lower EL */
59	cmp	x30, #EC_IABORT_LOWER_EL
60	b.eq	1f
61
62	cmp	x30, #EC_DABORT_LOWER_EL
63	b.eq	1f
64
65	/* Save GP registers */
66	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
67	stp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
68	stp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
69
70	/* Get the cpu_ops pointer */
71	bl	get_cpu_ops_ptr
72
73	/* Get the cpu_ops exception handler */
74	ldr	x0, [x0, #CPU_E_HANDLER_FUNC]
75
76	/*
77	 * If the reserved function pointer is NULL, this CPU does not have an
78	 * implementation defined exception handler function
79	 */
80	cbz	x0, 2f
81	mrs	x1, esr_el3
82	ubfx	x1, x1, #ESR_EC_SHIFT, #ESR_EC_LENGTH
83	blr	x0
84	b	2f
85
861:
87	/* Test for EA bit in the instruction syndrome */
88	mrs	x30, esr_el3
89	tbz	x30, #ESR_ISS_EABORT_EA_BIT, 3f
90
91	/*
92	 * Save general purpose and ARMv8.3-PAuth registers (if enabled).
93	 * If Secure Cycle Counter is not disabled in MDCR_EL3 when
94	 * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
95	 */
96	bl	save_gp_pmcr_pauth_regs
97
98#if ENABLE_PAUTH
99	/* Load and program APIAKey firmware key */
100	bl	pauth_load_bl31_apiakey
101#endif
102
103	/* Setup exception class and syndrome arguments for platform handler */
104	mov	x0, #ERROR_EA_SYNC
105	mrs	x1, esr_el3
106	bl	delegate_sync_ea
107
108	/* el3_exit assumes SP_EL0 on entry */
109	msr	spsel, #MODE_SP_EL0
110	b	el3_exit
1112:
112	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
113	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
114	ldp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
115
1163:
117	/* Synchronous exceptions other than the above are assumed to be EA */
118	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
119	no_ret	report_unhandled_exception
120endfunc enter_lower_el_sync_ea
121
122
123/*
124 * This function handles SErrors from lower ELs.
125 *
126 * Since it's part of exception vector, this function doesn't expect any GP
127 * registers to have been saved. It delegates the handling of the EA to platform
128 * handler, and upon successfully handling the EA, exits EL3; otherwise panics.
129 */
130func enter_lower_el_async_ea
131	/*
132	 * Explicitly save x30 so as to free up a register and to enable
133	 * branching
134	 */
135	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
136
137handle_lower_el_async_ea:
138	/*
139	 * Save general purpose and ARMv8.3-PAuth registers (if enabled).
140	 * If Secure Cycle Counter is not disabled in MDCR_EL3 when
141	 * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
142	 */
143	bl	save_gp_pmcr_pauth_regs
144
145#if ENABLE_PAUTH
146	/* Load and program APIAKey firmware key */
147	bl	pauth_load_bl31_apiakey
148#endif
149
150	/* Setup exception class and syndrome arguments for platform handler */
151	mov	x0, #ERROR_EA_ASYNC
152	mrs	x1, esr_el3
153	bl	delegate_async_ea
154
155	/* el3_exit assumes SP_EL0 on entry */
156	msr	spsel, #MODE_SP_EL0
157	b	el3_exit
158endfunc enter_lower_el_async_ea
159
160
161/*
162 * Prelude for Synchronous External Abort handling. This function assumes that
163 * all GP registers have been saved by the caller.
164 *
165 * x0: EA reason
166 * x1: EA syndrome
167 */
168func delegate_sync_ea
169#if RAS_EXTENSION
170	/*
171	 * Check for Uncontainable error type. If so, route to the platform
172	 * fatal error handler rather than the generic EA one.
173	 */
174	ubfx    x2, x1, #EABORT_SET_SHIFT, #EABORT_SET_WIDTH
175	cmp     x2, #ERROR_STATUS_SET_UC
176	b.ne    1f
177
178	/* Check fault status code */
179	ubfx    x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
180	cmp     x3, #SYNC_EA_FSC
181	b.ne    1f
182
183	no_ret  plat_handle_uncontainable_ea
1841:
185#endif
186
187	b       ea_proceed
188endfunc delegate_sync_ea
189
190
191/*
192 * Prelude for Asynchronous External Abort handling. This function assumes that
193 * all GP registers have been saved by the caller.
194 *
195 * x0: EA reason
196 * x1: EA syndrome
197 */
198func delegate_async_ea
199#if RAS_EXTENSION
200	/*
201	 * Check for Implementation Defined Syndrome. If so, skip checking
202	 * Uncontainable error type from the syndrome as the format is unknown.
203	 */
204	tbnz	x1, #SERROR_IDS_BIT, 1f
205
206	/*
207	 * Check for Uncontainable error type. If so, route to the platform
208	 * fatal error handler rather than the generic EA one.
209	 */
210	ubfx	x2, x1, #EABORT_AET_SHIFT, #EABORT_AET_WIDTH
211	cmp	x2, #ERROR_STATUS_UET_UC
212	b.ne	1f
213
214	/* Check DFSC for SError type */
215	ubfx	x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
216	cmp	x3, #DFSC_SERROR
217	b.ne	1f
218
219	no_ret	plat_handle_uncontainable_ea
2201:
221#endif
222
223	b	ea_proceed
224endfunc delegate_async_ea
225
226
227/*
228 * Delegate External Abort handling to platform's EA handler. This function
229 * assumes that all GP registers have been saved by the caller.
230 *
231 * x0: EA reason
232 * x1: EA syndrome
233 */
234func ea_proceed
235	/*
236	 * If the ESR loaded earlier is not zero, we were processing an EA
237	 * already, and this is a double fault.
238	 */
239	ldr	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
240	cbz	x5, 1f
241	no_ret	plat_handle_double_fault
242
2431:
244	/* Save EL3 state */
245	mrs	x2, spsr_el3
246	mrs	x3, elr_el3
247	stp	x2, x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
248
249	/*
250	 * Save ESR as handling might involve lower ELs, and returning back to
251	 * EL3 from there would trample the original ESR.
252	 */
253	mrs	x4, scr_el3
254	mrs	x5, esr_el3
255	stp	x4, x5, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
256
257	/*
258	 * Setup rest of arguments, and call platform External Abort handler.
259	 *
260	 * x0: EA reason (already in place)
261	 * x1: Exception syndrome (already in place).
262	 * x2: Cookie (unused for now).
263	 * x3: Context pointer.
264	 * x4: Flags (security state from SCR for now).
265	 */
266	mov	x2, xzr
267	mov	x3, sp
268	ubfx	x4, x4, #0, #1
269
270	/* Switch to runtime stack */
271	ldr	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
272	msr	spsel, #MODE_SP_EL0
273	mov	sp, x5
274
275	mov	x29, x30
276#if ENABLE_ASSERTIONS
277	/* Stash the stack pointer */
278	mov	x28, sp
279#endif
280	bl	plat_ea_handler
281
282#if ENABLE_ASSERTIONS
283	/*
284	 * Error handling flows might involve long jumps; so upon returning from
285	 * the platform error handler, validate that the we've completely
286	 * unwound the stack.
287	 */
288	mov	x27, sp
289	cmp	x28, x27
290	ASM_ASSERT(eq)
291#endif
292
293	/* Make SP point to context */
294	msr	spsel, #MODE_SP_ELX
295
296	/* Restore EL3 state and ESR */
297	ldp	x1, x2, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
298	msr	spsr_el3, x1
299	msr	elr_el3, x2
300
301	/* Restore ESR_EL3 and SCR_EL3 */
302	ldp	x3, x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
303	msr	scr_el3, x3
304	msr	esr_el3, x4
305
306#if ENABLE_ASSERTIONS
307	cmp	x4, xzr
308	ASM_ASSERT(ne)
309#endif
310
311	/* Clear ESR storage */
312	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
313
314	ret	x29
315endfunc ea_proceed
316