• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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//
5// This program and the accompanying materials
6// are licensed and made available under the terms and conditions of the BSD License
7// which accompanies this distribution.  The full text of the license may be found at
8// http://opensource.org/licenses/bsd-license.php
9//
10// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12//
13//------------------------------------------------------------------------------
14
15#include <Chipset/AArch64.h>
16#include <Library/PcdLib.h>
17#include <AsmMacroIoLibV8.h>
18
19/*
20  This is the stack constructed by the exception handler (low address to high address).
21  X0 to FAR makes up the EFI_SYSTEM_CONTEXT for AArch64.
22
23  UINT64  X0;     0x000
24  UINT64  X1;     0x008
25  UINT64  X2;     0x010
26  UINT64  X3;     0x018
27  UINT64  X4;     0x020
28  UINT64  X5;     0x028
29  UINT64  X6;     0x030
30  UINT64  X7;     0x038
31  UINT64  X8;     0x040
32  UINT64  X9;     0x048
33  UINT64  X10;    0x050
34  UINT64  X11;    0x058
35  UINT64  X12;    0x060
36  UINT64  X13;    0x068
37  UINT64  X14;    0x070
38  UINT64  X15;    0x078
39  UINT64  X16;    0x080
40  UINT64  X17;    0x088
41  UINT64  X18;    0x090
42  UINT64  X19;    0x098
43  UINT64  X20;    0x0a0
44  UINT64  X21;    0x0a8
45  UINT64  X22;    0x0b0
46  UINT64  X23;    0x0b8
47  UINT64  X24;    0x0c0
48  UINT64  X25;    0x0c8
49  UINT64  X26;    0x0d0
50  UINT64  X27;    0x0d8
51  UINT64  X28;    0x0e0
52  UINT64  FP;     0x0e8   // x29 - Frame Pointer
53  UINT64  LR;     0x0f0   // x30 - Link Register
54  UINT64  SP;     0x0f8   // x31 - Stack Pointer
55
56  // FP/SIMD Registers. 128bit if used as Q-regs.
57  UINT64  V0[2];  0x100
58  UINT64  V1[2];  0x110
59  UINT64  V2[2];  0x120
60  UINT64  V3[2];  0x130
61  UINT64  V4[2];  0x140
62  UINT64  V5[2];  0x150
63  UINT64  V6[2];  0x160
64  UINT64  V7[2];  0x170
65  UINT64  V8[2];  0x180
66  UINT64  V9[2];  0x190
67  UINT64  V10[2]; 0x1a0
68  UINT64  V11[2]; 0x1b0
69  UINT64  V12[2]; 0x1c0
70  UINT64  V13[2]; 0x1d0
71  UINT64  V14[2]; 0x1e0
72  UINT64  V15[2]; 0x1f0
73  UINT64  V16[2]; 0x200
74  UINT64  V17[2]; 0x210
75  UINT64  V18[2]; 0x220
76  UINT64  V19[2]; 0x230
77  UINT64  V20[2]; 0x240
78  UINT64  V21[2]; 0x250
79  UINT64  V22[2]; 0x260
80  UINT64  V23[2]; 0x270
81  UINT64  V24[2]; 0x280
82  UINT64  V25[2]; 0x290
83  UINT64  V26[2]; 0x2a0
84  UINT64  V27[2]; 0x2b0
85  UINT64  V28[2]; 0x2c0
86  UINT64  V29[2]; 0x2d0
87  UINT64  V30[2]; 0x2e0
88  UINT64  V31[2]; 0x2f0
89
90  // System Context
91  UINT64  ELR;    0x300   // Exception Link Register
92  UINT64  SPSR;   0x308   // Saved Processor Status Register
93  UINT64  FPSR;   0x310   // Floating Point Status Register
94  UINT64  ESR;    0x318   // Exception syndrome register
95  UINT64  FAR;    0x320   // Fault Address Register
96  UINT64  Padding;0x328   // Required for stack alignment
97*/
98
99GCC_ASM_EXPORT(ExceptionHandlersEnd)
100GCC_ASM_EXPORT(CommonExceptionEntry)
101GCC_ASM_EXPORT(AsmCommonExceptionEntry)
102GCC_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// This code gets copied to the ARM vector table
160// VectorTableStart - VectorTableEnd gets copied
161//
162VECTOR_BASE(ExceptionHandlersStart)
163
164//
165// Current EL with SP0 : 0x0 - 0x180
166//
167VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)
168ASM_PFX(SynchronousExceptionSP0):
169  b   ASM_PFX(SynchronousExceptionEntry)
170
171VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)
172ASM_PFX(IrqSP0):
173  b   ASM_PFX(IrqEntry)
174
175VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)
176ASM_PFX(FiqSP0):
177  b   ASM_PFX(FiqEntry)
178
179VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)
180ASM_PFX(SErrorSP0):
181  b   ASM_PFX(SErrorEntry)
182
183//
184// Current EL with SPx: 0x200 - 0x380
185//
186VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)
187ASM_PFX(SynchronousExceptionSPx):
188  b   ASM_PFX(SynchronousExceptionEntry)
189
190VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)
191ASM_PFX(IrqSPx):
192  b   ASM_PFX(IrqEntry)
193
194VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)
195ASM_PFX(FiqSPx):
196  b   ASM_PFX(FiqEntry)
197
198VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)
199ASM_PFX(SErrorSPx):
200  b   ASM_PFX(SErrorEntry)
201
202//
203// Lower EL using AArch64 : 0x400 - 0x580
204//
205VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)
206ASM_PFX(SynchronousExceptionA64):
207  b   ASM_PFX(SynchronousExceptionEntry)
208
209VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)
210ASM_PFX(IrqA64):
211  b   ASM_PFX(IrqEntry)
212
213VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)
214ASM_PFX(FiqA64):
215  b   ASM_PFX(FiqEntry)
216
217VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)
218ASM_PFX(SErrorA64):
219  b   ASM_PFX(SErrorEntry)
220
221//
222// Lower EL using AArch32 : 0x600 - 0x780
223//
224VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)
225ASM_PFX(SynchronousExceptionA32):
226  b   ASM_PFX(SynchronousExceptionEntry)
227
228VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)
229ASM_PFX(IrqA32):
230  b   ASM_PFX(IrqEntry)
231
232VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)
233ASM_PFX(FiqA32):
234  b   ASM_PFX(FiqEntry)
235
236VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)
237ASM_PFX(SErrorA32):
238  b   ASM_PFX(SErrorEntry)
239
240VECTOR_END(ExceptionHandlersStart)
241
242#undef  REG_PAIR
243#undef  REG_ONE
244#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE)  stp  REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
245#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE)         stur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
246
247ASM_PFX(SynchronousExceptionEntry):
248  // Move the stackpointer so we can reach our structure with the str instruction.
249  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
250
251  // Save all the General regs before touching x0 and x1.
252  // This does not save r31(SP) as it is special. We do that later.
253  ALL_GP_REGS
254
255  // Record the type of exception that occurred.
256  mov       x0, #EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
257
258  // Jump to our general handler to deal with all the common parts and process the exception.
259  ldr       x1, ASM_PFX(CommonExceptionEntry)
260  br        x1
261
262ASM_PFX(IrqEntry):
263  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
264  ALL_GP_REGS
265  mov       x0, #EXCEPT_AARCH64_IRQ
266  ldr       x1, ASM_PFX(CommonExceptionEntry)
267  br        x1
268
269ASM_PFX(FiqEntry):
270  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
271  ALL_GP_REGS
272  mov       x0, #EXCEPT_AARCH64_FIQ
273  ldr       x1, ASM_PFX(CommonExceptionEntry)
274  br        x1
275
276ASM_PFX(SErrorEntry):
277  sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
278  ALL_GP_REGS
279  mov       x0, #EXCEPT_AARCH64_SERROR
280  ldr       x1, ASM_PFX(CommonExceptionEntry)
281  br        x1
282
283
284//
285// This gets patched by the C code that patches in the vector table
286//
287.align 3
288ASM_PFX(CommonExceptionEntry):
289  .8byte ASM_PFX(AsmCommonExceptionEntry)
290
291ASM_PFX(ExceptionHandlersEnd):
292
293
294
295//
296// This code runs from CpuDxe driver loaded address. It is patched into
297// CommonExceptionEntry.
298//
299ASM_PFX(AsmCommonExceptionEntry):
300  /* NOTE:
301     We have to break up the save code because the immediate value to be used
302     with the SP is too big to do it all in one step so we need to shuffle the SP
303     along as we go. (we only have 9bits of immediate to work with) */
304
305  // Save the current Stack pointer before we start modifying it.
306  SAVE_SP
307
308  // Preserve the stack pointer we came in with before we modify it
309  EL1_OR_EL2(x1)
3101:mrs      x1, elr_el1   // Exception Link Register
311  mrs      x2, spsr_el1  // Saved Processor Status Register 32bit
312  mrs      x3, fpsr      // Floating point Status Register  32bit
313  mrs      x4, esr_el1   // EL1 Exception syndrome register 32bit
314  mrs      x5, far_el1   // EL1 Fault Address Register
315  b        3f
316
3172:mrs      x1, elr_el2   // Exception Link Register
318  mrs      x2, spsr_el2  // Saved Processor Status Register 32bit
319  mrs      x3, fpsr      // Floating point Status Register  32bit
320  mrs      x4, esr_el2   // EL2 Exception syndrome register 32bit
321  mrs      x5, far_el2   // EL2 Fault Address Register
322
323  // Adjust SP to save next set
3243:add      sp, sp, #FP_CONTEXT_SIZE
325
326  // Push FP regs to Stack.
327  ALL_FP_REGS
328
329  // Adjust SP to save next set
330  add      sp, sp, #SYS_CONTEXT_SIZE
331
332  // Save the SYS regs
333  ALL_SYS_REGS
334
335  // Point to top of struct after all regs saved
336  sub      sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
337
338  // x0 still holds the exception type.
339  // Set x1 to point to the top of our struct on the Stack
340  mov      x1, sp
341
342// CommonCExceptionHandler (
343//   IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0
344//   IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1
345//   )
346
347  // Call the handler as defined above
348
349  // For now we spin in the handler if we received an abort of some kind.
350  // We do not try to recover.
351  bl       ASM_PFX(CommonCExceptionHandler) // Call exception handler
352
353
354// Defines for popping from stack
355
356#undef REG_PAIR
357#undef REG_ONE
358#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE)    ldp  REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
359#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE)           ldur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
360
361  //
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
365  //
366  msr   daifset, #3
367  isb
368
369  // Adjust SP to pop system registers
370  add     sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
371  ALL_SYS_REGS
372
373  EL1_OR_EL2(x6)
3741:msr      elr_el1, x1   // Exception Link Register
375  msr      spsr_el1,x2   // Saved Processor Status Register 32bit
376  msr      fpsr, x3      // Floating point Status Register  32bit
377  msr      esr_el1, x4   // EL1 Exception syndrome register 32bit
378  msr      far_el1, x5   // EL1 Fault Address Register
379  b        3f
3802:msr      elr_el2, x1   // Exception Link Register
381  msr      spsr_el2,x2   // Saved Processor Status Register 32bit
382  msr      fpsr, x3      // Floating point Status Register  32bit
383  msr      esr_el2, x4   // EL2 Exception syndrome register 32bit
384  msr      far_el2, x5   // EL2 Fault Address Register
385
3863:// pop all regs and return from exception.
387  sub     sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
388  ALL_GP_REGS
389
390  // Adjust SP to pop next set
391  add      sp, sp, #FP_CONTEXT_SIZE
392  // Pop FP regs to Stack.
393  ALL_FP_REGS
394
395  // Adjust SP to be where we started from when we came into the handler.
396  // The handler can not change the SP.
397  add      sp, sp, #SYS_CONTEXT_SIZE
398
399  eret
400
401#undef REG_PAIR
402#undef REG_ONE
403