1 //------------------------------------------------------------------------------
3 // Use ARMv6 instruction to operate on a single stack
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>
9 // SPDX-License-Identifier: BSD-2-Clause-Patent
11 //------------------------------------------------------------------------------
13 #include <Library/PcdLib.h>
17 This is the stack constructed by the exception handler (low address to high address)
18 # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
21 R0 0x00 # stmfd SP!,{R0-R12}
34 SP 0x34 # reserved via subtraction 0x20 (32) from SP
43 LR 0x54 # SVC Link register (we need to restore it)
45 LR 0x58 # pushed by srsfd
51 EXPORT ExceptionHandlersStart
52 EXPORT ExceptionHandlersEnd
53 EXPORT CommonExceptionEntry
54 EXPORT AsmCommonExceptionEntry
55 IMPORT CommonCExceptionHandler
58 AREA DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5
61 // This code gets copied to the ARM vector table
62 // ExceptionHandlersStart - ExceptionHandlersEnd gets copied
64 ExceptionHandlersStart
70 b UndefinedInstructionEntry
73 b SoftwareInterruptEntry
82 b ReservedExceptionEntry
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
97 mov R0,#0 ; ExceptionType
98 ldr R1,CommonExceptionEntry
101 UndefinedInstructionEntry
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
109 mov R0,#1 ; ExceptionType
110 ldr R1,CommonExceptionEntry;
113 SoftwareInterruptEntry
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
120 mov R0,#2 ; ExceptionType
121 ldr R1,CommonExceptionEntry
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
132 mov R0,#3 ; ExceptionType
133 ldr R1,CommonExceptionEntry
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
144 mov R0,#4 ; ExceptionType
145 ldr R1,CommonExceptionEntry
148 ReservedExceptionEntry
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
155 mov R0,#5 ; ExceptionType
156 ldr R1,CommonExceptionEntry
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
167 mov R0,#6 ; ExceptionType
168 ldr R1,CommonExceptionEntry
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
185 // This gets patched by the C code that patches in the vector table
188 dcd AsmCommonExceptionEntry
193 // This code runs from CpuDxe driver loaded address. It is patched into
194 // CommonExceptionEntry.
196 AsmCommonExceptionEntry
197 mrc p15, 0, R1, c6, c0, 2 ; Read IFAR
198 str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
200 mrc p15, 0, R1, c5, c0, 1 ; Read IFSR
201 str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
203 mrc p15, 0, R1, c6, c0, 0 ; Read DFAR
204 str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
206 mrc p15, 0, R1, c5, c0, 0 ; Read DFSR
207 str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
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
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))
216 stmeqed R2, {lr}^ ; save unbanked lr
218 stmneed R2, {lr} ; save SVC lr
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
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
233 str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC
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
238 ; R0 is ExceptionType
239 mov R1,SP ; R1 is SystemContext
241 #if (FixedPcdGet32(PcdVFPEnabled))
242 vpush {d0-d15} ; save vstm registers in case they are used in optimizations
245 mov R4, SP ; Save current SP
247 subne SP, SP, #4 ; Adjust SP if not 8-byte aligned
252 CommonCExceptionHandler (
253 IN EFI_EXCEPTION_TYPE ExceptionType, R0
254 IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
258 blx CommonCExceptionHandler ; Call exception handler
260 mov SP, R4 ; Restore SP
262 #if (FixedPcdGet32(PcdVFPEnabled))
266 ldr R1, [SP, #0x4c] ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR
267 mcr p15, 0, R1, c5, c0, 1 ; Write IFSR
269 ldr R1, [SP, #0x44] ; Restore EFI_SYSTEM_CONTEXT_ARM.DFSR
270 mcr p15, 0, R1, c5, c0, 0 ; Write DFSR
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
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
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))
283 ldmeqed R2, {lr}^ ; restore unbanked lr
285 ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR}
287 ldmfd SP!,{R0-R12} ; Restore general purpose registers
288 ; Exception handler can not change SP
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