]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S
ArmPkg/ArmExceptionLib: don't restore ESR and FAR upon exception return
[mirror_edk2.git] / ArmPkg / Library / ArmExceptionLib / AArch64 / ExceptionSupport.S
1 //
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.
5 //
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
10 //
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.
13 //
14 //------------------------------------------------------------------------------
15
16 #include <Chipset/AArch64.h>
17 #include <Library/PcdLib.h>
18 #include <AsmMacroIoLibV8.h>
19 #include <Protocol/DebugSupport.h> // for exception type definitions
20
21 /*
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.
24
25 UINT64 X0; 0x000
26 UINT64 X1; 0x008
27 UINT64 X2; 0x010
28 UINT64 X3; 0x018
29 UINT64 X4; 0x020
30 UINT64 X5; 0x028
31 UINT64 X6; 0x030
32 UINT64 X7; 0x038
33 UINT64 X8; 0x040
34 UINT64 X9; 0x048
35 UINT64 X10; 0x050
36 UINT64 X11; 0x058
37 UINT64 X12; 0x060
38 UINT64 X13; 0x068
39 UINT64 X14; 0x070
40 UINT64 X15; 0x078
41 UINT64 X16; 0x080
42 UINT64 X17; 0x088
43 UINT64 X18; 0x090
44 UINT64 X19; 0x098
45 UINT64 X20; 0x0a0
46 UINT64 X21; 0x0a8
47 UINT64 X22; 0x0b0
48 UINT64 X23; 0x0b8
49 UINT64 X24; 0x0c0
50 UINT64 X25; 0x0c8
51 UINT64 X26; 0x0d0
52 UINT64 X27; 0x0d8
53 UINT64 X28; 0x0e0
54 UINT64 FP; 0x0e8 // x29 - Frame Pointer
55 UINT64 LR; 0x0f0 // x30 - Link Register
56 UINT64 SP; 0x0f8 // x31 - Stack Pointer
57
58 // FP/SIMD Registers. 128bit if used as Q-regs.
59 UINT64 V0[2]; 0x100
60 UINT64 V1[2]; 0x110
61 UINT64 V2[2]; 0x120
62 UINT64 V3[2]; 0x130
63 UINT64 V4[2]; 0x140
64 UINT64 V5[2]; 0x150
65 UINT64 V6[2]; 0x160
66 UINT64 V7[2]; 0x170
67 UINT64 V8[2]; 0x180
68 UINT64 V9[2]; 0x190
69 UINT64 V10[2]; 0x1a0
70 UINT64 V11[2]; 0x1b0
71 UINT64 V12[2]; 0x1c0
72 UINT64 V13[2]; 0x1d0
73 UINT64 V14[2]; 0x1e0
74 UINT64 V15[2]; 0x1f0
75 UINT64 V16[2]; 0x200
76 UINT64 V17[2]; 0x210
77 UINT64 V18[2]; 0x220
78 UINT64 V19[2]; 0x230
79 UINT64 V20[2]; 0x240
80 UINT64 V21[2]; 0x250
81 UINT64 V22[2]; 0x260
82 UINT64 V23[2]; 0x270
83 UINT64 V24[2]; 0x280
84 UINT64 V25[2]; 0x290
85 UINT64 V26[2]; 0x2a0
86 UINT64 V27[2]; 0x2b0
87 UINT64 V28[2]; 0x2c0
88 UINT64 V29[2]; 0x2d0
89 UINT64 V30[2]; 0x2e0
90 UINT64 V31[2]; 0x2f0
91
92 // System Context
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
99 */
100
101 GCC_ASM_EXPORT(ExceptionHandlersEnd)
102 GCC_ASM_EXPORT(CommonCExceptionHandler)
103
104 .text
105
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)
109
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);
128
129 // In order to save the SP we need to put it somewhere else first.
130 // STR only works with XZR/WZR directly
131 #define SAVE_SP \
132 add x1, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE); \
133 REG_ONE (x1, 0x0f8, GP_CONTEXT_SIZE);
134
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);
152
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);
157
158 //
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.
164 //
165
166 #if defined(ARM_RELOCATE_VECTORS)
167 GCC_ASM_EXPORT(ExceptionHandlersStart)
168 ASM_PFX(ExceptionHandlersStart):
169 #else
170 VECTOR_BASE(ExceptionHandlersStart)
171 #endif
172
173 #undef REG_PAIR
174 #undef REG_ONE
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)]
177
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)
181
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.
184 ALL_GP_REGS
185
186 // Record the type of exception that occurred.
187 mov x0, #\val
188
189 // Jump to our general handler to deal with all the common parts and process the exception.
190 ldr x1, =ASM_PFX(CommonExceptionEntry)
191 br x1
192 .ltorg
193 .endm
194
195 //
196 // Current EL with SP0 : 0x0 - 0x180
197 //
198 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)
199 ASM_PFX(SynchronousExceptionSP0):
200 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
201
202 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)
203 ASM_PFX(IrqSP0):
204 ExceptionEntry EXCEPT_AARCH64_IRQ
205
206 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)
207 ASM_PFX(FiqSP0):
208 ExceptionEntry EXCEPT_AARCH64_FIQ
209
210 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)
211 ASM_PFX(SErrorSP0):
212 ExceptionEntry EXCEPT_AARCH64_SERROR
213
214 //
215 // Current EL with SPx: 0x200 - 0x380
216 //
217 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)
218 ASM_PFX(SynchronousExceptionSPx):
219 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
220
221 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)
222 ASM_PFX(IrqSPx):
223 ExceptionEntry EXCEPT_AARCH64_IRQ
224
225 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)
226 ASM_PFX(FiqSPx):
227 ExceptionEntry EXCEPT_AARCH64_FIQ
228
229 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)
230 ASM_PFX(SErrorSPx):
231 ExceptionEntry EXCEPT_AARCH64_SERROR
232
233 //
234 // Lower EL using AArch64 : 0x400 - 0x580
235 //
236 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)
237 ASM_PFX(SynchronousExceptionA64):
238 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
239
240 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)
241 ASM_PFX(IrqA64):
242 ExceptionEntry EXCEPT_AARCH64_IRQ
243
244 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)
245 ASM_PFX(FiqA64):
246 ExceptionEntry EXCEPT_AARCH64_FIQ
247
248 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)
249 ASM_PFX(SErrorA64):
250 ExceptionEntry EXCEPT_AARCH64_SERROR
251
252 //
253 // Lower EL using AArch32 : 0x600 - 0x780
254 //
255 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)
256 ASM_PFX(SynchronousExceptionA32):
257 ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
258
259 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)
260 ASM_PFX(IrqA32):
261 ExceptionEntry EXCEPT_AARCH64_IRQ
262
263 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)
264 ASM_PFX(FiqA32):
265 ExceptionEntry EXCEPT_AARCH64_FIQ
266
267 VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)
268 ASM_PFX(SErrorA32):
269 ExceptionEntry EXCEPT_AARCH64_SERROR
270
271 VECTOR_END(ExceptionHandlersStart)
272
273 ASM_PFX(ExceptionHandlersEnd):
274
275
276 ASM_PFX(CommonExceptionEntry):
277 /* NOTE:
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) */
281
282 // Save the current Stack pointer before we start modifying it.
283 SAVE_SP
284
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
291 b 4f
292
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
297 b 4f
298
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
303
304 4:mrs x3, fpsr // Floating point Status Register 32bit
305
306 // Adjust SP to save next set
307 add sp, sp, #FP_CONTEXT_SIZE
308
309 // Push FP regs to Stack.
310 ALL_FP_REGS
311
312 // Adjust SP to save next set
313 add sp, sp, #SYS_CONTEXT_SIZE
314
315 // Save the SYS regs
316 ALL_SYS_REGS
317
318 // Point to top of struct after all regs saved
319 sub sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
320
321 // x0 still holds the exception type.
322 // Set x1 to point to the top of our struct on the Stack
323 mov x1, sp
324
325 // CommonCExceptionHandler (
326 // IN EFI_EXCEPTION_TYPE ExceptionType, R0
327 // IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
328 // )
329
330 // Call the handler as defined above
331
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
335
336
337 // Defines for popping from stack
338
339 #undef REG_PAIR
340 #undef REG_ONE
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)]
343
344 //
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
348 //
349 msr daifset, #3
350 isb
351
352 // Adjust SP to pop system registers
353 add sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
354 ALL_SYS_REGS
355
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
359 b 4f
360 2:msr elr_el2, x1 // Exception Link Register
361 msr spsr_el2,x2 // Saved Processor Status Register 32bit
362 b 4f
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
366
367 // pop all regs and return from exception.
368 sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
369 ALL_GP_REGS
370
371 // Adjust SP to pop next set
372 add sp, sp, #FP_CONTEXT_SIZE
373 // Pop FP regs to Stack.
374 ALL_FP_REGS
375
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
379
380 eret
381
382 #undef REG_PAIR
383 #undef REG_ONE