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 // This program and the accompanying materials
7 // are licensed and made available under the terms and conditions of the BSD License
8 // which accompanies this distribution. The full text of the license may be found at
9 // http://opensource.org/licenses/bsd-license.php
11 // THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 //------------------------------------------------------------------------------
16 #include <Chipset/AArch64.h>
17 #include <Library/PcdLib.h>
18 #include <AsmMacroIoLibV8.h>
19 #include <Protocol/DebugSupport.h> // for exception type definitions
22 This is the stack constructed by the exception handler (low address to high address).
23 X0 to FAR makes up the EFI_SYSTEM_CONTEXT for AArch64.
54 UINT64 FP; 0x0e8 // x29 - Frame Pointer
55 UINT64 LR; 0x0f0 // x30 - Link Register
56 UINT64 SP; 0x0f8 // x31 - Stack Pointer
58 // FP/SIMD Registers. 128bit if used as Q-regs.
93 UINT64 ELR; 0x300 // Exception Link Register
94 UINT64 SPSR; 0x308 // Saved Processor Status Register
95 UINT64 FPSR; 0x310 // Floating Point Status Register
96 UINT64 ESR; 0x318 // Exception syndrome register
97 UINT64 FAR; 0x320 // Fault Address Register
98 UINT64 Padding;0x328 // Required for stack alignment
101 GCC_ASM_EXPORT(ExceptionHandlersEnd)
102 GCC_ASM_EXPORT(CommonExceptionEntry)
103 GCC_ASM_EXPORT(AsmCommonExceptionEntry)
104 GCC_ASM_EXPORT(CommonCExceptionHandler)
108 #define GP_CONTEXT_SIZE (32 * 8)
109 #define FP_CONTEXT_SIZE (32 * 16)
110 #define SYS_CONTEXT_SIZE ( 6 * 8) // 5 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10)
112 // Cannot str x31 directly
113 #define ALL_GP_REGS \
114 REG_PAIR (x0, x1, 0x000, GP_CONTEXT_SIZE); \
115 REG_PAIR (x2, x3, 0x010, GP_CONTEXT_SIZE); \
116 REG_PAIR (x4, x5, 0x020, GP_CONTEXT_SIZE); \
117 REG_PAIR (x6, x7, 0x030, GP_CONTEXT_SIZE); \
118 REG_PAIR (x8, x9, 0x040, GP_CONTEXT_SIZE); \
119 REG_PAIR (x10, x11, 0x050, GP_CONTEXT_SIZE); \
120 REG_PAIR (x12, x13, 0x060, GP_CONTEXT_SIZE); \
121 REG_PAIR (x14, x15, 0x070, GP_CONTEXT_SIZE); \
122 REG_PAIR (x16, x17, 0x080, GP_CONTEXT_SIZE); \
123 REG_PAIR (x18, x19, 0x090, GP_CONTEXT_SIZE); \
124 REG_PAIR (x20, x21, 0x0a0, GP_CONTEXT_SIZE); \
125 REG_PAIR (x22, x23, 0x0b0, GP_CONTEXT_SIZE); \
126 REG_PAIR (x24, x25, 0x0c0, GP_CONTEXT_SIZE); \
127 REG_PAIR (x26, x27, 0x0d0, GP_CONTEXT_SIZE); \
128 REG_PAIR (x28, x29, 0x0e0, GP_CONTEXT_SIZE); \
129 REG_ONE (x30, 0x0f0, GP_CONTEXT_SIZE);
131 // In order to save the SP we need to put it somewhere else first.
132 // STR only works with XZR/WZR directly
134 add x1, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE); \
135 REG_ONE (x1, 0x0f8, GP_CONTEXT_SIZE);
137 #define ALL_FP_REGS \
138 REG_PAIR (q0, q1, 0x000, FP_CONTEXT_SIZE); \
139 REG_PAIR (q2, q3, 0x020, FP_CONTEXT_SIZE); \
140 REG_PAIR (q4, q5, 0x040, FP_CONTEXT_SIZE); \
141 REG_PAIR (q6, q7, 0x060, FP_CONTEXT_SIZE); \
142 REG_PAIR (q8, q9, 0x080, FP_CONTEXT_SIZE); \
143 REG_PAIR (q10, q11, 0x0a0, FP_CONTEXT_SIZE); \
144 REG_PAIR (q12, q13, 0x0c0, FP_CONTEXT_SIZE); \
145 REG_PAIR (q14, q15, 0x0e0, FP_CONTEXT_SIZE); \
146 REG_PAIR (q16, q17, 0x100, FP_CONTEXT_SIZE); \
147 REG_PAIR (q18, q19, 0x120, FP_CONTEXT_SIZE); \
148 REG_PAIR (q20, q21, 0x140, FP_CONTEXT_SIZE); \
149 REG_PAIR (q22, q23, 0x160, FP_CONTEXT_SIZE); \
150 REG_PAIR (q24, q25, 0x180, FP_CONTEXT_SIZE); \
151 REG_PAIR (q26, q27, 0x1a0, FP_CONTEXT_SIZE); \
152 REG_PAIR (q28, q29, 0x1c0, FP_CONTEXT_SIZE); \
153 REG_PAIR (q30, q31, 0x1e0, FP_CONTEXT_SIZE);
155 #define ALL_SYS_REGS \
156 REG_PAIR (x1, x2, 0x000, SYS_CONTEXT_SIZE); \
157 REG_PAIR (x3, x4, 0x010, SYS_CONTEXT_SIZE); \
158 REG_ONE (x5, 0x020, SYS_CONTEXT_SIZE);
161 // There are two methods for installing AArch64 exception vectors:
162 // 1. Install a copy of the vectors to a location specified by a PCD
163 // 2. Write VBAR directly, requiring that vectors have proper alignment (2K)
164 // The conditional below adjusts the alignment requirement based on which
165 // exception vector initialization method is used.
168 #if defined(ARM_RELOCATE_VECTORS)
169 GCC_ASM_EXPORT(ExceptionHandlersStart)
170 ASM_PFX(ExceptionHandlersStart):
172 VECTOR_BASE(ExceptionHandlersStart)
176 // Current EL with SP0 : 0x0 - 0x180
178 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)
179 ASM_PFX(SynchronousExceptionSP0):
180 b ASM_PFX(SynchronousExceptionEntry)
182 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)
186 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)
190 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)
192 b ASM_PFX(SErrorEntry)
195 // Current EL with SPx: 0x200 - 0x380
197 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)
198 ASM_PFX(SynchronousExceptionSPx):
199 b ASM_PFX(SynchronousExceptionEntry)
201 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)
205 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)
209 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)
211 b ASM_PFX(SErrorEntry)
214 // Lower EL using AArch64 : 0x400 - 0x580
216 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)
217 ASM_PFX(SynchronousExceptionA64):
218 b ASM_PFX(SynchronousExceptionEntry)
220 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)
224 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)
228 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)
230 b ASM_PFX(SErrorEntry)
233 // Lower EL using AArch32 : 0x600 - 0x780
235 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)
236 ASM_PFX(SynchronousExceptionA32):
237 b ASM_PFX(SynchronousExceptionEntry)
239 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)
243 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)
247 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)
249 b ASM_PFX(SErrorEntry)
251 VECTOR_END(ExceptionHandlersStart)
255 #define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) stp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
256 #define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) stur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
258 ASM_PFX(SynchronousExceptionEntry):
259 // Move the stackpointer so we can reach our structure with the str instruction.
260 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
262 // Save all the General regs before touching x0 and x1.
263 // This does not save r31(SP) as it is special. We do that later.
266 // Record the type of exception that occurred.
267 mov x0, #EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
269 // Jump to our general handler to deal with all the common parts and process the exception.
270 ldr x1, ASM_PFX(CommonExceptionEntry)
274 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
276 mov x0, #EXCEPT_AARCH64_IRQ
277 ldr x1, ASM_PFX(CommonExceptionEntry)
281 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
283 mov x0, #EXCEPT_AARCH64_FIQ
284 ldr x1, ASM_PFX(CommonExceptionEntry)
287 ASM_PFX(SErrorEntry):
288 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
290 mov x0, #EXCEPT_AARCH64_SERROR
291 ldr x1, ASM_PFX(CommonExceptionEntry)
296 // This gets patched by the C code that patches in the vector table
299 ASM_PFX(CommonExceptionEntry):
300 .8byte ASM_PFX(AsmCommonExceptionEntry)
302 ASM_PFX(ExceptionHandlersEnd):
307 // This code runs from CpuDxe driver loaded address. It is patched into
308 // CommonExceptionEntry.
310 ASM_PFX(AsmCommonExceptionEntry):
312 We have to break up the save code because the immediate value to be used
313 with the SP is too big to do it all in one step so we need to shuffle the SP
314 along as we go. (we only have 9bits of immediate to work with) */
316 // Save the current Stack pointer before we start modifying it.
319 // Preserve the stack pointer we came in with before we modify it
320 EL1_OR_EL2_OR_EL3(x1)
321 1:mrs x1, elr_el1 // Exception Link Register
322 mrs x2, spsr_el1 // Saved Processor Status Register 32bit
323 mrs x3, fpsr // Floating point Status Register 32bit
324 mrs x4, esr_el1 // EL1 Exception syndrome register 32bit
325 mrs x5, far_el1 // EL1 Fault Address Register
328 2:mrs x1, elr_el2 // Exception Link Register
329 mrs x2, spsr_el2 // Saved Processor Status Register 32bit
330 mrs x3, fpsr // Floating point Status Register 32bit
331 mrs x4, esr_el2 // EL2 Exception syndrome register 32bit
332 mrs x5, far_el2 // EL2 Fault Address Register
335 3:mrs x1, elr_el3 // Exception Link Register
336 mrs x2, spsr_el3 // Saved Processor Status Register 32bit
337 mrs x3, fpsr // Floating point Status Register 32bit
338 mrs x4, esr_el3 // EL3 Exception syndrome register 32bit
339 mrs x5, far_el3 // EL3 Fault Address Register
341 // Adjust SP to save next set
342 4:add sp, sp, #FP_CONTEXT_SIZE
344 // Push FP regs to Stack.
347 // Adjust SP to save next set
348 add sp, sp, #SYS_CONTEXT_SIZE
353 // Point to top of struct after all regs saved
354 sub sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
356 // x0 still holds the exception type.
357 // Set x1 to point to the top of our struct on the Stack
360 // CommonCExceptionHandler (
361 // IN EFI_EXCEPTION_TYPE ExceptionType, R0
362 // IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
365 // Call the handler as defined above
367 // For now we spin in the handler if we received an abort of some kind.
368 // We do not try to recover.
369 bl ASM_PFX(CommonCExceptionHandler) // Call exception handler
372 // Defines for popping from stack
376 #define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) ldp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
377 #define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) ldur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
380 // Disable interrupt(IRQ and FIQ) before restoring context,
381 // or else the context will be corrupted by interrupt reentrance.
382 // Interrupt mask will be restored from spsr by hardware when we call eret
387 // Adjust SP to pop system registers
388 add sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
391 EL1_OR_EL2_OR_EL3(x6)
392 1:msr elr_el1, x1 // Exception Link Register
393 msr spsr_el1,x2 // Saved Processor Status Register 32bit
394 msr fpsr, x3 // Floating point Status Register 32bit
395 msr esr_el1, x4 // EL1 Exception syndrome register 32bit
396 msr far_el1, x5 // EL1 Fault Address Register
398 2:msr elr_el2, x1 // Exception Link Register
399 msr spsr_el2,x2 // Saved Processor Status Register 32bit
400 msr fpsr, x3 // Floating point Status Register 32bit
401 msr esr_el2, x4 // EL2 Exception syndrome register 32bit
402 msr far_el2, x5 // EL2 Fault Address Register
404 3:msr elr_el3, x1 // Exception Link Register
405 msr spsr_el3,x2 // Saved Processor Status Register 32bit
406 msr fpsr, x3 // Floating point Status Register 32bit
407 msr esr_el3, x4 // EL3 Exception syndrome register 32bit
408 msr far_el3, x5 // EL3 Fault Address Register
409 4:// pop all regs and return from exception.
410 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
413 // Adjust SP to pop next set
414 add sp, sp, #FP_CONTEXT_SIZE
415 // Pop FP regs to Stack.
418 // Adjust SP to be where we started from when we came into the handler.
419 // The handler can not change the SP.
420 add sp, sp, #SYS_CONTEXT_SIZE