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