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