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