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 EXPORT ExceptionHandlersStart 58 EXPORT ExceptionHandlersEnd 59 EXPORT CommonExceptionEntry 60 EXPORT AsmCommonExceptionEntry 61 IMPORT CommonCExceptionHandler 62 63 PRESERVE8 64 AREA DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5 65 66 // 67 // This code gets copied to the ARM vector table 68 // ExceptionHandlersStart - ExceptionHandlersEnd gets copied 69 // 70 ExceptionHandlersStart 71 72 Reset 73 b ResetEntry 74 75 UndefinedInstruction 76 b UndefinedInstructionEntry 77 78 SoftwareInterrupt 79 b SoftwareInterruptEntry 80 81 PrefetchAbort 82 b PrefetchAbortEntry 83 84 DataAbort 85 b DataAbortEntry 86 87 ReservedException 88 b ReservedExceptionEntry 89 90 Irq 91 b IrqEntry 92 93 Fiq 94 b FiqEntry 95 96 ResetEntry 97 srsfd #0x13! ; Store return state on SVC stack 98 ; We are already in SVC mode 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,CommonExceptionEntry 105 bx R1 106 107 UndefinedInstructionEntry 108 sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry 109 srsfd #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,CommonExceptionEntry; 117 bx R1 118 119 SoftwareInterruptEntry 120 srsfd #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,CommonExceptionEntry 128 bx R1 129 130 PrefetchAbortEntry 131 sub LR,LR,#4 132 srsfd #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,CommonExceptionEntry 140 bx R1 141 142 DataAbortEntry 143 sub LR,LR,#8 144 srsfd #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 ; ExceptionType 151 ldr R1,CommonExceptionEntry 152 bx R1 153 154 ReservedExceptionEntry 155 srsfd #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 ; ExceptionType 162 ldr R1,CommonExceptionEntry 163 bx R1 164 165 IrqEntry 166 sub LR,LR,#4 167 srsfd #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,CommonExceptionEntry 175 bx R1 176 177 FiqEntry 178 sub LR,LR,#4 179 srsfd #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,CommonExceptionEntry 188 bx R1 189 190 // 191 // This gets patched by the C code that patches in the vector table 192 // 193 CommonExceptionEntry 194 dcd AsmCommonExceptionEntry 195 196 ExceptionHandlersEnd 197 198 // 199 // This code runs from CpuDxe driver loaded address. It is patched into 200 // CommonExceptionEntry. 201 // 202 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] ; srsfd 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 stmeqed R2, {lr}^ ; save unbanked lr 223 ; else 224 stmneed 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 differnt 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 237 NoAdjustNeeded 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 /* 256 VOID 257 EFIAPI 258 CommonCExceptionHandler ( 259 IN EFI_EXCEPTION_TYPE ExceptionType, R0 260 IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 261 ) 262 263 */ 264 blx 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 ldmeqed R2, {lr}^ ; restore unbanked lr 290 ; else 291 ldmneed 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 END 301 302 303