2 // Copyright (c) 2011 - 2014 ARM LTD. All rights reserved.<BR>
3 // Portion of Copyright (c) 2014 NVIDIA Corporation. All rights reserved.<BR>
4 // Copyright (c) 2016 HP Development Company, L.P.
6 // SPDX-License-Identifier: BSD-2-Clause-Patent
8 //------------------------------------------------------------------------------
10 #include <Chipset/AArch64.h>
11 #include <Library/PcdLib.h>
12 #include <AsmMacroIoLibV8.h>
13 #include <Protocol/DebugSupport.h> // for exception type definitions
16 This is the stack constructed by the exception handler (low address to high address).
17 X0 to FAR makes up the EFI_SYSTEM_CONTEXT for AArch64.
48 UINT64 FP; 0x0e8 // x29 - Frame Pointer
49 UINT64 LR; 0x0f0 // x30 - Link Register
50 UINT64 SP; 0x0f8 // x31 - Stack Pointer
52 // FP/SIMD Registers. 128bit if used as Q-regs.
87 UINT64 ELR; 0x300 // Exception Link Register
88 UINT64 SPSR; 0x308 // Saved Processor Status Register
89 UINT64 FPSR; 0x310 // Floating Point Status Register
90 UINT64 ESR; 0x318 // Exception syndrome register
91 UINT64 FAR; 0x320 // Fault Address Register
92 UINT64 Padding;0x328 // Required for stack alignment
95 GCC_ASM_EXPORT(ExceptionHandlersEnd)
96 GCC_ASM_EXPORT(CommonCExceptionHandler)
97 GCC_ASM_EXPORT(RegisterEl0Stack)
101 #define GP_CONTEXT_SIZE (32 * 8)
102 #define FP_CONTEXT_SIZE (32 * 16)
103 #define SYS_CONTEXT_SIZE ( 6 * 8) // 5 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10)
106 // There are two methods for installing AArch64 exception vectors:
107 // 1. Install a copy of the vectors to a location specified by a PCD
108 // 2. Write VBAR directly, requiring that vectors have proper alignment (2K)
109 // The conditional below adjusts the alignment requirement based on which
110 // exception vector initialization method is used.
113 #if defined(ARM_RELOCATE_VECTORS)
114 GCC_ASM_EXPORT(ExceptionHandlersStart)
115 ASM_PFX(ExceptionHandlersStart):
117 VECTOR_BASE(ExceptionHandlersStart)
120 .macro ExceptionEntry, val, sp=SPx
122 // Our backtrace and register dump code is written in C and so it requires
123 // a stack. This makes it difficult to produce meaningful diagnostics when
124 // the stack pointer has been corrupted. So in such cases (i.e., when taking
125 // synchronous exceptions), this macro is expanded with \sp set to SP0, in
126 // which case we switch to the SP_EL0 stack pointer, which has been
127 // initialized to point to a buffer that has been set aside for this purpose.
129 // Since 'sp' may no longer refer to the stack frame that was active when
130 // the exception was taken, we may have to switch back and forth between
131 // SP_EL0 and SP_ELx to record the correct value for SP in the context struct.
137 // Move the stackpointer so we can reach our structure with the str instruction.
138 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
140 // Push the GP registers so we can record the exception context
141 stp x0, x1, [sp, #-GP_CONTEXT_SIZE]!
142 stp x2, x3, [sp, #0x10]
143 stp x4, x5, [sp, #0x20]
144 stp x6, x7, [sp, #0x30]
145 stp x8, x9, [sp, #0x40]
146 stp x10, x11, [sp, #0x50]
147 stp x12, x13, [sp, #0x60]
148 stp x14, x15, [sp, #0x70]
149 stp x16, x17, [sp, #0x80]
150 stp x18, x19, [sp, #0x90]
151 stp x20, x21, [sp, #0xa0]
152 stp x22, x23, [sp, #0xb0]
153 stp x24, x25, [sp, #0xc0]
154 stp x26, x27, [sp, #0xd0]
155 stp x28, x29, [sp, #0xe0]
156 add x28, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
166 stp x30, x7, [sp, #0xf0]
168 // Record the type of exception that occurred.
171 // Jump to our general handler to deal with all the common parts and process the exception.
172 #if defined(ARM_RELOCATE_VECTORS)
173 ldr x1, =ASM_PFX(CommonExceptionEntry)
177 b ASM_PFX(CommonExceptionEntry)
182 // Current EL with SP0 : 0x0 - 0x180
184 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)
185 ASM_PFX(SynchronousExceptionSP0):
186 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
188 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)
190 ExceptionEntry EXCEPT_AARCH64_IRQ
192 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)
194 ExceptionEntry EXCEPT_AARCH64_FIQ
196 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)
198 ExceptionEntry EXCEPT_AARCH64_SERROR
201 // Current EL with SPx: 0x200 - 0x380
203 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)
204 ASM_PFX(SynchronousExceptionSPx):
205 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS, SP0
207 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)
209 ExceptionEntry EXCEPT_AARCH64_IRQ
211 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)
213 ExceptionEntry EXCEPT_AARCH64_FIQ
215 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)
217 ExceptionEntry EXCEPT_AARCH64_SERROR
220 // Lower EL using AArch64 : 0x400 - 0x580
222 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)
223 ASM_PFX(SynchronousExceptionA64):
224 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
226 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)
228 ExceptionEntry EXCEPT_AARCH64_IRQ
230 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)
232 ExceptionEntry EXCEPT_AARCH64_FIQ
234 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)
236 ExceptionEntry EXCEPT_AARCH64_SERROR
239 // Lower EL using AArch32 : 0x600 - 0x780
241 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)
242 ASM_PFX(SynchronousExceptionA32):
243 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
245 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)
247 ExceptionEntry EXCEPT_AARCH64_IRQ
249 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)
251 ExceptionEntry EXCEPT_AARCH64_FIQ
253 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)
255 ExceptionEntry EXCEPT_AARCH64_SERROR
257 VECTOR_END(ExceptionHandlersStart)
259 ASM_PFX(ExceptionHandlersEnd):
262 ASM_PFX(CommonExceptionEntry):
264 EL1_OR_EL2_OR_EL3(x1)
265 1:mrs x2, elr_el1 // Exception Link Register
266 mrs x3, spsr_el1 // Saved Processor Status Register 32bit
267 mrs x5, esr_el1 // EL1 Exception syndrome register 32bit
268 mrs x6, far_el1 // EL1 Fault Address Register
271 2:mrs x2, elr_el2 // Exception Link Register
272 mrs x3, spsr_el2 // Saved Processor Status Register 32bit
273 mrs x5, esr_el2 // EL2 Exception syndrome register 32bit
274 mrs x6, far_el2 // EL2 Fault Address Register
277 3:mrs x2, elr_el3 // Exception Link Register
278 mrs x3, spsr_el3 // Saved Processor Status Register 32bit
279 mrs x5, esr_el3 // EL3 Exception syndrome register 32bit
280 mrs x6, far_el3 // EL3 Fault Address Register
282 4:mrs x4, fpsr // Floating point Status Register 32bit
285 stp x2, x3, [x28, #-SYS_CONTEXT_SIZE]!
286 stp x4, x5, [x28, #0x10]
289 // Push FP regs to Stack.
290 stp q0, q1, [x28, #-FP_CONTEXT_SIZE]!
291 stp q2, q3, [x28, #0x20]
292 stp q4, q5, [x28, #0x40]
293 stp q6, q7, [x28, #0x60]
294 stp q8, q9, [x28, #0x80]
295 stp q10, q11, [x28, #0xa0]
296 stp q12, q13, [x28, #0xc0]
297 stp q14, q15, [x28, #0xe0]
298 stp q16, q17, [x28, #0x100]
299 stp q18, q19, [x28, #0x120]
300 stp q20, q21, [x28, #0x140]
301 stp q22, q23, [x28, #0x160]
302 stp q24, q25, [x28, #0x180]
303 stp q26, q27, [x28, #0x1a0]
304 stp q28, q29, [x28, #0x1c0]
305 stp q30, q31, [x28, #0x1e0]
307 // x0 still holds the exception type.
308 // Set x1 to point to the top of our struct on the Stack
311 // CommonCExceptionHandler (
312 // IN EFI_EXCEPTION_TYPE ExceptionType, R0
313 // IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
316 // Call the handler as defined above
318 // For now we spin in the handler if we received an abort of some kind.
319 // We do not try to recover.
320 bl ASM_PFX(CommonCExceptionHandler) // Call exception handler
322 // Pop as many GP regs as we can before entering the critical section below
323 ldp x2, x3, [sp, #0x10]
324 ldp x4, x5, [sp, #0x20]
325 ldp x6, x7, [sp, #0x30]
326 ldp x8, x9, [sp, #0x40]
327 ldp x10, x11, [sp, #0x50]
328 ldp x12, x13, [sp, #0x60]
329 ldp x14, x15, [sp, #0x70]
330 ldp x16, x17, [sp, #0x80]
331 ldp x18, x19, [sp, #0x90]
332 ldp x20, x21, [sp, #0xa0]
333 ldp x22, x23, [sp, #0xb0]
334 ldp x24, x25, [sp, #0xc0]
335 ldp x26, x27, [sp, #0xd0]
336 ldp x0, x1, [sp], #0xe0
338 // Pop FP regs from Stack.
339 ldp q2, q3, [x28, #0x20]
340 ldp q4, q5, [x28, #0x40]
341 ldp q6, q7, [x28, #0x60]
342 ldp q8, q9, [x28, #0x80]
343 ldp q10, q11, [x28, #0xa0]
344 ldp q12, q13, [x28, #0xc0]
345 ldp q14, q15, [x28, #0xe0]
346 ldp q16, q17, [x28, #0x100]
347 ldp q18, q19, [x28, #0x120]
348 ldp q20, q21, [x28, #0x140]
349 ldp q22, q23, [x28, #0x160]
350 ldp q24, q25, [x28, #0x180]
351 ldp q26, q27, [x28, #0x1a0]
352 ldp q28, q29, [x28, #0x1c0]
353 ldp q30, q31, [x28, #0x1e0]
354 ldp q0, q1, [x28], #FP_CONTEXT_SIZE
356 // Pop the SYS regs we need
358 ldr x28, [x28, #0x10]
362 // Disable interrupt(IRQ and FIQ) before restoring context,
363 // or else the context will be corrupted by interrupt reentrance.
364 // Interrupt mask will be restored from spsr by hardware when we call eret
369 EL1_OR_EL2_OR_EL3(x28)
370 1:msr elr_el1, x29 // Exception Link Register
371 msr spsr_el1, x30 // Saved Processor Status Register 32bit
373 2:msr elr_el2, x29 // Exception Link Register
374 msr spsr_el2, x30 // Saved Processor Status Register 32bit
376 3:msr elr_el3, x29 // Exception Link Register
377 msr spsr_el3, x30 // Saved Processor Status Register 32bit
380 // pop remaining GP regs and return from exception.
381 ldr x30, [sp, #0xf0 - 0xe0]
382 ldp x28, x29, [sp], #GP_CONTEXT_SIZE - 0xe0
384 // Adjust SP to be where we started from when we came into the handler.
385 // The handler can not change the SP.
386 add sp, sp, #FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
390 ASM_PFX(RegisterEl0Stack):