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