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