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
51  EXPORT  ExceptionHandlersStart
52  EXPORT  ExceptionHandlersEnd
53  EXPORT  CommonExceptionEntry
54  EXPORT  AsmCommonExceptionEntry
55  IMPORT  CommonCExceptionHandler
56
57  PRESERVE8
58  AREA  DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5
59
60//
61// This code gets copied to the ARM vector table
62// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
63//
64ExceptionHandlersStart
65
66Reset
67  b   ResetEntry
68
69UndefinedInstruction
70  b   UndefinedInstructionEntry
71
72SoftwareInterrupt
73  b   SoftwareInterruptEntry
74
75PrefetchAbort
76  b   PrefetchAbortEntry
77
78DataAbort
79  b   DataAbortEntry
80
81ReservedException
82  b   ReservedExceptionEntry
83
84Irq
85  b   IrqEntry
86
87Fiq
88  b   FiqEntry
89
90ResetEntry
91  srsfd     #0x13!                    ; Store return state on SVC stack
92                                      ; We are already in SVC mode
93  stmfd     SP!,{LR}                  ; Store the link register for the current mode
94  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
95  stmfd     SP!,{R0-R12}              ; Store the register state
96
97  mov       R0,#0                     ; ExceptionType
98  ldr       R1,CommonExceptionEntry
99  bx        R1
100
101UndefinedInstructionEntry
102  sub       LR, LR, #4                ; Only -2 for Thumb, adjust in CommonExceptionEntry
103  srsfd     #0x13!                    ; Store return state on SVC stack
104  cps       #0x13                     ; Switch to SVC for common stack
105  stmfd     SP!,{LR}                  ; Store the link register for the current mode
106  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
107  stmfd     SP!,{R0-R12}              ; Store the register state
108
109  mov       R0,#1                     ; ExceptionType
110  ldr       R1,CommonExceptionEntry;
111  bx        R1
112
113SoftwareInterruptEntry
114  srsfd     #0x13!                    ; Store return state on SVC stack
115                                      ; We are already in SVC mode
116  stmfd     SP!,{LR}                  ; Store the link register for the current mode
117  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
118  stmfd     SP!,{R0-R12}              ; Store the register state
119
120  mov       R0,#2                     ; ExceptionType
121  ldr       R1,CommonExceptionEntry
122  bx        R1
123
124PrefetchAbortEntry
125  sub       LR,LR,#4
126  srsfd     #0x13!                    ; Store return state on SVC stack
127  cps       #0x13                     ; Switch to SVC for common stack
128  stmfd     SP!,{LR}                  ; Store the link register for the current mode
129  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
130  stmfd     SP!,{R0-R12}              ; Store the register state
131
132  mov       R0,#3                     ; ExceptionType
133  ldr       R1,CommonExceptionEntry
134  bx        R1
135
136DataAbortEntry
137  sub       LR,LR,#8
138  srsfd     #0x13!                    ; Store return state on SVC stack
139  cps       #0x13                     ; Switch to SVC for common stack
140  stmfd     SP!,{LR}                  ; Store the link register for the current mode
141  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
142  stmfd     SP!,{R0-R12}              ; Store the register state
143
144  mov       R0,#4                     ; ExceptionType
145  ldr       R1,CommonExceptionEntry
146  bx        R1
147
148ReservedExceptionEntry
149  srsfd     #0x13!                    ; Store return state on SVC stack
150  cps       #0x13                     ; Switch to SVC for common stack
151  stmfd     SP!,{LR}                  ; Store the link register for the current mode
152  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
153  stmfd     SP!,{R0-R12}              ; Store the register state
154
155  mov       R0,#5                     ; ExceptionType
156  ldr       R1,CommonExceptionEntry
157  bx        R1
158
159IrqEntry
160  sub       LR,LR,#4
161  srsfd     #0x13!                    ; Store return state on SVC stack
162  cps       #0x13                     ; Switch to SVC for common stack
163  stmfd     SP!,{LR}                  ; Store the link register for the current mode
164  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
165  stmfd     SP!,{R0-R12}              ; Store the register state
166
167  mov       R0,#6                     ; ExceptionType
168  ldr       R1,CommonExceptionEntry
169  bx        R1
170
171FiqEntry
172  sub       LR,LR,#4
173  srsfd     #0x13!                    ; Store return state on SVC stack
174  cps       #0x13                     ; Switch to SVC for common stack
175  stmfd     SP!,{LR}                  ; Store the link register for the current mode
176  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
177  stmfd     SP!,{R0-R12}              ; Store the register state
178                                      ; Since we have already switch to SVC R8_fiq - R12_fiq
179                                      ; never get used or saved
180  mov       R0,#7                     ; ExceptionType
181  ldr       R1,CommonExceptionEntry
182  bx        R1
183
184//
185// This gets patched by the C code that patches in the vector table
186//
187CommonExceptionEntry
188  dcd       AsmCommonExceptionEntry
189
190ExceptionHandlersEnd
191
192//
193// This code runs from CpuDxe driver loaded address. It is patched into
194// CommonExceptionEntry.
195//
196AsmCommonExceptionEntry
197  mrc       p15, 0, R1, c6, c0, 2   ; Read IFAR
198  str       R1, [SP, #0x50]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
199
200  mrc       p15, 0, R1, c5, c0, 1   ; Read IFSR
201  str       R1, [SP, #0x4c]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
202
203  mrc       p15, 0, R1, c6, c0, 0   ; Read DFAR
204  str       R1, [SP, #0x48]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
205
206  mrc       p15, 0, R1, c5, c0, 0   ; Read DFSR
207  str       R1, [SP, #0x44]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
208
209  ldr       R1, [SP, #0x5c]         ; srsfd saved pre-exception CPSR on the stack
210  str       R1, [SP, #0x40]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
211
212  add       R2, SP, #0x38           ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
213  and       R3, R1, #0x1f           ; Check CPSR to see if User or System Mode
214  cmp       R3, #0x1f               ; if ((CPSR == 0x10) || (CPSR == 0x1f))
215  cmpne     R3, #0x10               ;
216  stmeqed   R2, {lr}^               ;   save unbanked lr
217                                    ; else
218  stmneed   R2, {lr}                ;   save SVC lr
219
220
221  ldr       R5, [SP, #0x58]         ; PC is the LR pushed by srsfd
222                                    ; Check to see if we have to adjust for Thumb entry
223  sub       r4, r0, #1              ; if (ExceptionType == 1 || ExceptionType == 2)) {
224  cmp       r4, #1                  ;   // UND & SVC have different LR adjust for Thumb
225  bhi       NoAdjustNeeded
226
227  tst       r1, #0x20               ;   if ((CPSR & T)) == T) {  // Thumb Mode on entry
228  addne     R5, R5, #2              ;     PC += 2;
229  strne     R5,[SP,#0x58]           ; Update LR value pushed by srsfd
230
231NoAdjustNeeded
232
233  str       R5, [SP, #0x3c]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC
234
235  add       R1, SP, #0x60           ; We pushed 0x60 bytes on the stack
236  str       R1, [SP, #0x34]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP
237
238                                    ; R0 is ExceptionType
239  mov       R1,SP                   ; R1 is SystemContext
240
241#if (FixedPcdGet32(PcdVFPEnabled))
242  vpush    {d0-d15}                 ; save vstm registers in case they are used in optimizations
243#endif
244
245  mov       R4, SP                  ; Save current SP
246  tst       R4, #4
247  subne     SP, SP, #4              ; Adjust SP if not 8-byte aligned
248
249/*
250VOID
251EFIAPI
252CommonCExceptionHandler (
253  IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0
254  IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1
255  )
256
257*/
258  blx       CommonCExceptionHandler ; Call exception handler
259
260  mov       SP, R4                  ; Restore SP
261
262#if (FixedPcdGet32(PcdVFPEnabled))
263  vpop      {d0-d15}
264#endif
265
266  ldr       R1, [SP, #0x4c]         ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR
267  mcr       p15, 0, R1, c5, c0, 1   ; Write IFSR
268
269  ldr       R1, [SP, #0x44]         ; Restore EFI_SYSTEM_CONTEXT_ARM.DFSR
270  mcr       p15, 0, R1, c5, c0, 0   ; Write DFSR
271
272  ldr       R1,[SP,#0x3c]           ; EFI_SYSTEM_CONTEXT_ARM.PC
273  str       R1,[SP,#0x58]           ; Store it back to srsfd stack slot so it can be restored
274
275  ldr       R1,[SP,#0x40]           ; EFI_SYSTEM_CONTEXT_ARM.CPSR
276  str       R1,[SP,#0x5c]           ; Store it back to srsfd stack slot so it can be restored
277
278  add       R3, SP, #0x54           ; Make R3 point to SVC LR saved on entry
279  add       R2, SP, #0x38           ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
280  and       R1, R1, #0x1f           ; Check to see if User or System Mode
281  cmp       R1, #0x1f               ; if ((CPSR == 0x10) || (CPSR == 0x1f))
282  cmpne     R1, #0x10               ;
283  ldmeqed   R2, {lr}^               ;   restore unbanked lr
284                                    ; else
285  ldmneed   R3, {lr}                ;   restore SVC lr, via ldmfd SP!, {LR}
286
287  ldmfd     SP!,{R0-R12}            ; Restore general purpose registers
288                                    ; Exception handler can not change SP
289
290  add       SP,SP,#0x20             ; Clear out the remaining stack space
291  ldmfd     SP!,{LR}                ; restore the link register for this context
292  rfefd     SP!                     ; return from exception via srsfd stack slot
293
294  END
295
296
297