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