1#------------------------------------------------------------------------------
2#
3# Use ARMv6 instruction to operate on a single stack
4#
5# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
6# Copyright (c) 2014, ARM Limited. All rights reserved.<BR>
7# Copyright (c) 2016 HP Development Company, L.P.<BR>
8#
9# SPDX-License-Identifier: BSD-2-Clause-Patent
10#
11#------------------------------------------------------------------------------
12
13#include <Library/PcdLib.h>
14
15/*
16
17This is the stack constructed by the exception handler (low address to high address)
18                # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
19  Reg   Offset
20  ===   ======
21  R0    0x00    # stmfd     SP!,{R0-R12}
22  R1    0x04
23  R2    0x08
24  R3    0x0c
25  R4    0x10
26  R5    0x14
27  R6    0x18
28  R7    0x1c
29  R8    0x20
30  R9    0x24
31  R10   0x28
32  R11   0x2c
33  R12   0x30
34  SP    0x34    # reserved via subtraction 0x20 (32) from SP
35  LR    0x38
36  PC    0x3c
37  CPSR  0x40
38  DFSR  0x44
39  DFAR  0x48
40  IFSR  0x4c
41  IFAR  0x50
42
43  LR    0x54    # SVC Link register (we need to restore it)
44
45  LR    0x58    # pushed by srsfd
46  CPSR  0x5c
47
48 */
49
50
51GCC_ASM_EXPORT(ExceptionHandlersStart)
52GCC_ASM_EXPORT(ExceptionHandlersEnd)
53GCC_ASM_EXPORT(CommonExceptionEntry)
54GCC_ASM_EXPORT(AsmCommonExceptionEntry)
55GCC_ASM_EXPORT(CommonCExceptionHandler)
56
57.text
58.syntax unified
59#if !defined(__APPLE__)
60.fpu neon    @ makes vpush/vpop assemble
61#endif
62.align 5
63
64
65//
66// This code gets copied to the ARM vector table
67// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
68//
69ASM_PFX(ExceptionHandlersStart):
70
71ASM_PFX(Reset):
72  b ASM_PFX(ResetEntry)
73
74ASM_PFX(UndefinedInstruction):
75  b ASM_PFX(UndefinedInstructionEntry)
76
77ASM_PFX(SoftwareInterrupt):
78  b ASM_PFX(SoftwareInterruptEntry)
79
80ASM_PFX(PrefetchAbort):
81  b ASM_PFX(PrefetchAbortEntry)
82
83ASM_PFX(DataAbort):
84  b ASM_PFX(DataAbortEntry)
85
86ASM_PFX(ReservedException):
87  b ASM_PFX(ReservedExceptionEntry)
88
89ASM_PFX(Irq):
90  b ASM_PFX(IrqEntry)
91
92ASM_PFX(Fiq):
93  b ASM_PFX(FiqEntry)
94
95ASM_PFX(ResetEntry):
96  srsdb     #0x13!                    @ Store return state on SVC stack
97                                      @ We are already in SVC mode
98
99  stmfd     SP!,{LR}                  @ Store the link register for the current mode
100  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
101  stmfd     SP!,{R0-R12}              @ Store the register state
102
103  mov       R0,#0                     @ ExceptionType
104  ldr       R1,ASM_PFX(CommonExceptionEntry)
105  bx        R1
106
107ASM_PFX(UndefinedInstructionEntry):
108  sub       LR, LR, #4                @ Only -2 for Thumb, adjust in CommonExceptionEntry
109  srsdb     #0x13!                    @ Store return state on SVC stack
110  cps       #0x13                     @ Switch to SVC for common stack
111  stmfd     SP!,{LR}                  @ Store the link register for the current mode
112  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
113  stmfd     SP!,{R0-R12}              @ Store the register state
114
115  mov       R0,#1                     @ ExceptionType
116  ldr       R1,ASM_PFX(CommonExceptionEntry)
117  bx        R1
118
119ASM_PFX(SoftwareInterruptEntry):
120  srsdb     #0x13!                    @ Store return state on SVC stack
121                                      @ We are already in SVC mode
122  stmfd     SP!,{LR}                  @ Store the link register for the current mode
123  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
124  stmfd     SP!,{R0-R12}              @ Store the register state
125
126  mov       R0,#2                     @ ExceptionType
127  ldr       R1,ASM_PFX(CommonExceptionEntry)
128  bx        R1
129
130ASM_PFX(PrefetchAbortEntry):
131  sub       LR,LR,#4
132  srsdb     #0x13!                    @ Store return state on SVC stack
133  cps       #0x13                     @ Switch to SVC for common stack
134  stmfd     SP!,{LR}                  @ Store the link register for the current mode
135  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
136  stmfd     SP!,{R0-R12}              @ Store the register state
137
138  mov       R0,#3                     @ ExceptionType
139  ldr       R1,ASM_PFX(CommonExceptionEntry)
140  bx        R1
141
142ASM_PFX(DataAbortEntry):
143  sub       LR,LR,#8
144  srsdb     #0x13!                    @ Store return state on SVC stack
145  cps       #0x13                     @ Switch to SVC for common stack
146  stmfd     SP!,{LR}                  @ Store the link register for the current mode
147  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
148  stmfd     SP!,{R0-R12}              @ Store the register state
149
150  mov       R0,#4
151  ldr       R1,ASM_PFX(CommonExceptionEntry)
152  bx        R1
153
154ASM_PFX(ReservedExceptionEntry):
155  srsdb     #0x13!                    @ Store return state on SVC stack
156  cps       #0x13                     @ Switch to SVC for common stack
157  stmfd     SP!,{LR}                  @ Store the link register for the current mode
158  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
159  stmfd     SP!,{R0-R12}              @ Store the register state
160
161  mov       R0,#5
162  ldr       R1,ASM_PFX(CommonExceptionEntry)
163  bx        R1
164
165ASM_PFX(IrqEntry):
166  sub       LR,LR,#4
167  srsdb     #0x13!                    @ Store return state on SVC stack
168  cps       #0x13                     @ Switch to SVC for common stack
169  stmfd     SP!,{LR}                  @ Store the link register for the current mode
170  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
171  stmfd     SP!,{R0-R12}              @ Store the register state
172
173  mov       R0,#6                     @ ExceptionType
174  ldr       R1,ASM_PFX(CommonExceptionEntry)
175  bx        R1
176
177ASM_PFX(FiqEntry):
178  sub       LR,LR,#4
179  srsdb     #0x13!                    @ Store return state on SVC stack
180  cps       #0x13                     @ Switch to SVC for common stack
181  stmfd     SP!,{LR}                  @ Store the link register for the current mode
182  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
183  stmfd     SP!,{R0-R12}              @ Store the register state
184                                      @ Since we have already switch to SVC R8_fiq - R12_fiq
185                                      @ never get used or saved
186  mov       R0,#7                     @ ExceptionType
187  ldr       R1,ASM_PFX(CommonExceptionEntry)
188  bx        R1
189
190//
191// This gets patched by the C code that patches in the vector table
192//
193ASM_PFX(CommonExceptionEntry):
194  .word       ASM_PFX(AsmCommonExceptionEntry)
195
196ASM_PFX(ExceptionHandlersEnd):
197
198//
199// This code runs from CpuDxe driver loaded address. It is patched into
200// CommonExceptionEntry.
201//
202ASM_PFX(AsmCommonExceptionEntry):
203  mrc       p15, 0, R1, c6, c0, 2   @ Read IFAR
204  str       R1, [SP, #0x50]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
205
206  mrc       p15, 0, R1, c5, c0, 1   @ Read IFSR
207  str       R1, [SP, #0x4c]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
208
209  mrc       p15, 0, R1, c6, c0, 0   @ Read DFAR
210  str       R1, [SP, #0x48]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
211
212  mrc       p15, 0, R1, c5, c0, 0   @ Read DFSR
213  str       R1, [SP, #0x44]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
214
215  ldr       R1, [SP, #0x5c]         @ srsdb saved pre-exception CPSR on the stack
216  str       R1, [SP, #0x40]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
217
218  add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
219  and       R3, R1, #0x1f           @ Check CPSR to see if User or System Mode
220  cmp       R3, #0x1f               @ if ((CPSR == 0x10) || (CPSR == 0x1f))
221  cmpne     R3, #0x10               @
222  stmdaeq   R2, {lr}^               @   save unbanked lr
223                                    @ else
224  stmdane   R2, {lr}                @   save SVC lr
225
226
227  ldr       R5, [SP, #0x58]         @ PC is the LR pushed by srsfd
228                                    @ Check to see if we have to adjust for Thumb entry
229  sub       r4, r0, #1              @ if (ExceptionType == 1 || ExceptionType == 2)) {
230  cmp       r4, #1                  @   // UND & SVC have different LR adjust for Thumb
231  bhi       NoAdjustNeeded
232
233  tst       r1, #0x20               @   if ((CPSR & T)) == T) {  // Thumb Mode on entry
234  addne     R5, R5, #2              @     PC += 2;
235  strne     R5,[SP,#0x58]           @ Update LR value pushed by srsfd
236
237NoAdjustNeeded:
238
239  str       R5, [SP, #0x3c]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC
240
241  add       R1, SP, #0x60           @ We pushed 0x60 bytes on the stack
242  str       R1, [SP, #0x34]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP
243
244                                    @ R0 is ExceptionType
245  mov       R1,SP                   @ R1 is SystemContext
246
247#if (FixedPcdGet32(PcdVFPEnabled))
248  vpush     {d0-d15}                @ save vstm registers in case they are used in optimizations
249#endif
250
251  mov       R4, SP                  @ Save current SP
252  tst       R4, #4
253  subne     SP, SP, #4              @ Adjust SP if not 8-byte aligned
254
255/*
256VOID
257EFIAPI
258CommonCExceptionHandler (
259  IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0
260  IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1
261  )
262
263*/
264  blx       ASM_PFX(CommonCExceptionHandler)  @ Call exception handler
265
266  mov       SP, R4                  @ Restore SP
267
268#if (FixedPcdGet32(PcdVFPEnabled))
269  vpop      {d0-d15}
270#endif
271
272  ldr       R1, [SP, #0x4c]         @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR
273  mcr       p15, 0, R1, c5, c0, 1   @ Write IFSR
274
275  ldr       R1, [SP, #0x44]         @ Restore EFI_SYSTEM_CONTEXT_ARM.DFSR
276  mcr       p15, 0, R1, c5, c0, 0   @ Write DFSR
277
278  ldr       R1,[SP,#0x3c]           @ EFI_SYSTEM_CONTEXT_ARM.PC
279  str       R1,[SP,#0x58]           @ Store it back to srsfd stack slot so it can be restored
280
281  ldr       R1,[SP,#0x40]           @ EFI_SYSTEM_CONTEXT_ARM.CPSR
282  str       R1,[SP,#0x5c]           @ Store it back to srsfd stack slot so it can be restored
283
284  add       R3, SP, #0x54           @ Make R3 point to SVC LR saved on entry
285  add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
286  and       R1, R1, #0x1f           @ Check to see if User or System Mode
287  cmp       R1, #0x1f               @ if ((CPSR == 0x10) || (CPSR == 0x1f))
288  cmpne     R1, #0x10               @
289  ldmibeq   R2, {lr}^               @   restore unbanked lr
290                                    @ else
291  ldmibne   R3, {lr}                @   restore SVC lr, via ldmfd SP!, {LR}
292
293  ldmfd     SP!,{R0-R12}            @ Restore general purpose registers
294                                    @ Exception handler can not change SP
295
296  add       SP,SP,#0x20             @ Clear out the remaining stack space
297  ldmfd     SP!,{LR}                @ restore the link register for this context
298  rfefd     SP!                     @ return from exception via srsfd stack slot
299
300