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