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(CommonCExceptionHandler)
106 #define GP_CONTEXT_SIZE (32 * 8)
107 #define FP_CONTEXT_SIZE (32 * 16)
108 #define SYS_CONTEXT_SIZE ( 6 * 8) // 5 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10)
110 // Cannot str x31 directly
111 #define ALL_GP_REGS \
112 REG_PAIR (x0, x1, 0x000, GP_CONTEXT_SIZE); \
113 REG_PAIR (x2, x3, 0x010, GP_CONTEXT_SIZE); \
114 REG_PAIR (x4, x5, 0x020, GP_CONTEXT_SIZE); \
115 REG_PAIR (x6, x7, 0x030, GP_CONTEXT_SIZE); \
116 REG_PAIR (x8, x9, 0x040, GP_CONTEXT_SIZE); \
117 REG_PAIR (x10, x11, 0x050, GP_CONTEXT_SIZE); \
118 REG_PAIR (x12, x13, 0x060, GP_CONTEXT_SIZE); \
119 REG_PAIR (x14, x15, 0x070, GP_CONTEXT_SIZE); \
120 REG_PAIR (x16, x17, 0x080, GP_CONTEXT_SIZE); \
121 REG_PAIR (x18, x19, 0x090, GP_CONTEXT_SIZE); \
122 REG_PAIR (x20, x21, 0x0a0, GP_CONTEXT_SIZE); \
123 REG_PAIR (x22, x23, 0x0b0, GP_CONTEXT_SIZE); \
124 REG_PAIR (x24, x25, 0x0c0, GP_CONTEXT_SIZE); \
125 REG_PAIR (x26, x27, 0x0d0, GP_CONTEXT_SIZE); \
126 REG_PAIR (x28, x29, 0x0e0, GP_CONTEXT_SIZE); \
127 REG_ONE (x30, 0x0f0, GP_CONTEXT_SIZE);
129 // In order to save the SP we need to put it somewhere else first.
130 // STR only works with XZR/WZR directly
132 add x1, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE); \
133 REG_ONE (x1, 0x0f8, GP_CONTEXT_SIZE);
135 #define ALL_FP_REGS \
136 REG_PAIR (q0, q1, 0x000, FP_CONTEXT_SIZE); \
137 REG_PAIR (q2, q3, 0x020, FP_CONTEXT_SIZE); \
138 REG_PAIR (q4, q5, 0x040, FP_CONTEXT_SIZE); \
139 REG_PAIR (q6, q7, 0x060, FP_CONTEXT_SIZE); \
140 REG_PAIR (q8, q9, 0x080, FP_CONTEXT_SIZE); \
141 REG_PAIR (q10, q11, 0x0a0, FP_CONTEXT_SIZE); \
142 REG_PAIR (q12, q13, 0x0c0, FP_CONTEXT_SIZE); \
143 REG_PAIR (q14, q15, 0x0e0, FP_CONTEXT_SIZE); \
144 REG_PAIR (q16, q17, 0x100, FP_CONTEXT_SIZE); \
145 REG_PAIR (q18, q19, 0x120, FP_CONTEXT_SIZE); \
146 REG_PAIR (q20, q21, 0x140, FP_CONTEXT_SIZE); \
147 REG_PAIR (q22, q23, 0x160, FP_CONTEXT_SIZE); \
148 REG_PAIR (q24, q25, 0x180, FP_CONTEXT_SIZE); \
149 REG_PAIR (q26, q27, 0x1a0, FP_CONTEXT_SIZE); \
150 REG_PAIR (q28, q29, 0x1c0, FP_CONTEXT_SIZE); \
151 REG_PAIR (q30, q31, 0x1e0, FP_CONTEXT_SIZE);
153 #define ALL_SYS_REGS \
154 REG_PAIR (x1, x2, 0x000, SYS_CONTEXT_SIZE); \
155 REG_PAIR (x3, x4, 0x010, SYS_CONTEXT_SIZE); \
156 REG_ONE (x5, 0x020, SYS_CONTEXT_SIZE);
159 // There are two methods for installing AArch64 exception vectors:
160 // 1. Install a copy of the vectors to a location specified by a PCD
161 // 2. Write VBAR directly, requiring that vectors have proper alignment (2K)
162 // The conditional below adjusts the alignment requirement based on which
163 // exception vector initialization method is used.
166 #if defined(ARM_RELOCATE_VECTORS)
167 GCC_ASM_EXPORT(ExceptionHandlersStart)
168 ASM_PFX(ExceptionHandlersStart):
170 VECTOR_BASE(ExceptionHandlersStart)
175 #define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) stp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
176 #define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) stur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
178 .macro ExceptionEntry, val
179 // Move the stackpointer so we can reach our structure with the str instruction.
180 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
182 // Save all the General regs before touching x0 and x1.
183 // This does not save r31(SP) as it is special. We do that later.
186 // Record the type of exception that occurred.
189 // Jump to our general handler to deal with all the common parts and process the exception.
190 ldr x1, =ASM_PFX(CommonExceptionEntry)
196 // Current EL with SP0 : 0x0 - 0x180
198 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)
199 ASM_PFX(SynchronousExceptionSP0):
200 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
202 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)
204 ExceptionEntry EXCEPT_AARCH64_IRQ
206 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)
208 ExceptionEntry EXCEPT_AARCH64_FIQ
210 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)
212 ExceptionEntry EXCEPT_AARCH64_SERROR
215 // Current EL with SPx: 0x200 - 0x380
217 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)
218 ASM_PFX(SynchronousExceptionSPx):
219 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
221 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)
223 ExceptionEntry EXCEPT_AARCH64_IRQ
225 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)
227 ExceptionEntry EXCEPT_AARCH64_FIQ
229 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)
231 ExceptionEntry EXCEPT_AARCH64_SERROR
234 // Lower EL using AArch64 : 0x400 - 0x580
236 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)
237 ASM_PFX(SynchronousExceptionA64):
238 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
240 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)
242 ExceptionEntry EXCEPT_AARCH64_IRQ
244 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)
246 ExceptionEntry EXCEPT_AARCH64_FIQ
248 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)
250 ExceptionEntry EXCEPT_AARCH64_SERROR
253 // Lower EL using AArch32 : 0x600 - 0x780
255 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)
256 ASM_PFX(SynchronousExceptionA32):
257 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
259 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)
261 ExceptionEntry EXCEPT_AARCH64_IRQ
263 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)
265 ExceptionEntry EXCEPT_AARCH64_FIQ
267 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)
269 ExceptionEntry EXCEPT_AARCH64_SERROR
271 VECTOR_END(ExceptionHandlersStart)
273 ASM_PFX(ExceptionHandlersEnd):
276 ASM_PFX(CommonExceptionEntry):
278 We have to break up the save code because the immediate value to be used
279 with the SP is too big to do it all in one step so we need to shuffle the SP
280 along as we go. (we only have 9bits of immediate to work with) */
282 // Save the current Stack pointer before we start modifying it.
285 // Preserve the stack pointer we came in with before we modify it
286 EL1_OR_EL2_OR_EL3(x1)
287 1:mrs x1, elr_el1 // Exception Link Register
288 mrs x2, spsr_el1 // Saved Processor Status Register 32bit
289 mrs x4, esr_el1 // EL1 Exception syndrome register 32bit
290 mrs x5, far_el1 // EL1 Fault Address Register
293 2:mrs x1, elr_el2 // Exception Link Register
294 mrs x2, spsr_el2 // Saved Processor Status Register 32bit
295 mrs x4, esr_el2 // EL2 Exception syndrome register 32bit
296 mrs x5, far_el2 // EL2 Fault Address Register
299 3:mrs x1, elr_el3 // Exception Link Register
300 mrs x2, spsr_el3 // Saved Processor Status Register 32bit
301 mrs x4, esr_el3 // EL3 Exception syndrome register 32bit
302 mrs x5, far_el3 // EL3 Fault Address Register
304 4:mrs x3, fpsr // Floating point Status Register 32bit
306 // Adjust SP to save next set
307 add sp, sp, #FP_CONTEXT_SIZE
309 // Push FP regs to Stack.
312 // Adjust SP to save next set
313 add sp, sp, #SYS_CONTEXT_SIZE
318 // Point to top of struct after all regs saved
319 sub sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
321 // x0 still holds the exception type.
322 // Set x1 to point to the top of our struct on the Stack
325 // CommonCExceptionHandler (
326 // IN EFI_EXCEPTION_TYPE ExceptionType, R0
327 // IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
330 // Call the handler as defined above
332 // For now we spin in the handler if we received an abort of some kind.
333 // We do not try to recover.
334 bl ASM_PFX(CommonCExceptionHandler) // Call exception handler
337 // Defines for popping from stack
341 #define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) ldp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
342 #define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) ldur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
345 // Disable interrupt(IRQ and FIQ) before restoring context,
346 // or else the context will be corrupted by interrupt reentrance.
347 // Interrupt mask will be restored from spsr by hardware when we call eret
352 // Adjust SP to pop system registers
353 add sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
356 EL1_OR_EL2_OR_EL3(x6)
357 1:msr elr_el1, x1 // Exception Link Register
358 msr spsr_el1,x2 // Saved Processor Status Register 32bit
360 2:msr elr_el2, x1 // Exception Link Register
361 msr spsr_el2,x2 // Saved Processor Status Register 32bit
363 3:msr elr_el3, x1 // Exception Link Register
364 msr spsr_el3,x2 // Saved Processor Status Register 32bit
365 4:msr fpsr, x3 // Floating point Status Register 32bit
367 // pop all regs and return from exception.
368 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
371 // Adjust SP to pop next set
372 add sp, sp, #FP_CONTEXT_SIZE
373 // Pop FP regs to Stack.
376 // Adjust SP to be where we started from when we came into the handler.
377 // The handler can not change the SP.
378 add sp, sp, #SYS_CONTEXT_SIZE