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