1 ;------------------------------------------------------------------------------ ; 2 ; Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR> 3 ; This program and the accompanying materials 4 ; are licensed and made available under the terms and conditions of the BSD License 5 ; which accompanies this distribution. The full text of the license may be found at 6 ; http://opensource.org/licenses/bsd-license.php. 7 ; 8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 ; 11 ; Module Name: 12 ; 13 ; ExceptionHandlerAsm.Asm 14 ; 15 ; Abstract: 16 ; 17 ; x64 CPU Exception Handler 18 ; 19 ; Notes: 20 ; 21 ;------------------------------------------------------------------------------ 22 23 ; 24 ; CommonExceptionHandler() 25 ; 26 27 extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions 28 extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag 29 extern ASM_PFX(CommonExceptionHandler) 30 31 SECTION .data 32 33 DEFAULT REL 34 SECTION .text 35 36 ALIGN 8 37 38 AsmIdtVectorBegin: 39 %rep 32 40 db 0x6a ; push #VectorNum 41 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum 42 push rax 43 mov rax, ASM_PFX(CommonInterruptEntry) 44 jmp rax 45 %endrep 46 AsmIdtVectorEnd: 47 48 HookAfterStubHeaderBegin: 49 db 0x6a ; push 50 @VectorNum: 51 db 0 ; 0 will be fixed 52 push rax 53 mov rax, HookAfterStubHeaderEnd 54 jmp rax 55 HookAfterStubHeaderEnd: 56 mov rax, rsp 57 and sp, 0xfff0 ; make sure 16-byte aligned for exception context 58 sub rsp, 0x18 ; reserve room for filling exception data later 59 push rcx 60 mov rcx, [rax + 8] 61 bt [ASM_PFX(mErrorCodeFlag)], ecx 62 jnc .0 63 push qword [rsp] ; push additional rcx to make stack alignment 64 .0: 65 xchg rcx, [rsp] ; restore rcx, save Exception Number in stack 66 push qword [rax] ; push rax into stack to keep code consistence 67 68 ;---------------------------------------; 69 ; CommonInterruptEntry ; 70 ;---------------------------------------; 71 ; The follow algorithm is used for the common interrupt routine. 72 ; Entry from each interrupt with a push eax and eax=interrupt number 73 ; Stack frame would be as follows as specified in IA32 manuals: 74 ; 75 ; +---------------------+ <-- 16-byte aligned ensured by processor 76 ; + Old SS + 77 ; +---------------------+ 78 ; + Old RSP + 79 ; +---------------------+ 80 ; + RFlags + 81 ; +---------------------+ 82 ; + CS + 83 ; +---------------------+ 84 ; + RIP + 85 ; +---------------------+ 86 ; + Error Code + 87 ; +---------------------+ 88 ; + Vector Number + 89 ; +---------------------+ 90 ; + RBP + 91 ; +---------------------+ <-- RBP, 16-byte aligned 92 ; The follow algorithm is used for the common interrupt routine. 93 global ASM_PFX(CommonInterruptEntry) 94 ASM_PFX(CommonInterruptEntry): 95 cli 96 pop rax 97 ; 98 ; All interrupt handlers are invoked through interrupt gates, so 99 ; IF flag automatically cleared at the entry point 100 ; 101 xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx 102 and rcx, 0xFF 103 cmp ecx, 32 ; Intel reserved vector for exceptions? 104 jae NoErrorCode 105 bt [ASM_PFX(mErrorCodeFlag)], ecx 106 jc HasErrorCode 107 108 NoErrorCode: 109 110 ; 111 ; Push a dummy error code on the stack 112 ; to maintain coherent stack map 113 ; 114 push qword [rsp] 115 mov qword [rsp + 8], 0 116 HasErrorCode: 117 push rbp 118 mov rbp, rsp 119 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 120 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 121 122 ; 123 ; Stack: 124 ; +---------------------+ <-- 16-byte aligned ensured by processor 125 ; + Old SS + 126 ; +---------------------+ 127 ; + Old RSP + 128 ; +---------------------+ 129 ; + RFlags + 130 ; +---------------------+ 131 ; + CS + 132 ; +---------------------+ 133 ; + RIP + 134 ; +---------------------+ 135 ; + Error Code + 136 ; +---------------------+ 137 ; + RCX / Vector Number + 138 ; +---------------------+ 139 ; + RBP + 140 ; +---------------------+ <-- RBP, 16-byte aligned 141 ; 142 143 ; 144 ; Since here the stack pointer is 16-byte aligned, so 145 ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 146 ; is 16-byte aligned 147 ; 148 149 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 150 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 151 push r15 152 push r14 153 push r13 154 push r12 155 push r11 156 push r10 157 push r9 158 push r8 159 push rax 160 push qword [rbp + 8] ; RCX 161 push rdx 162 push rbx 163 push qword [rbp + 48] ; RSP 164 push qword [rbp] ; RBP 165 push rsi 166 push rdi 167 168 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero 169 movzx rax, word [rbp + 56] 170 push rax ; for ss 171 movzx rax, word [rbp + 32] 172 push rax ; for cs 173 mov rax, ds 174 push rax 175 mov rax, es 176 push rax 177 mov rax, fs 178 push rax 179 mov rax, gs 180 push rax 181 182 mov [rbp + 8], rcx ; save vector number 183 184 ;; UINT64 Rip; 185 push qword [rbp + 24] 186 187 ;; UINT64 Gdtr[2], Idtr[2]; 188 xor rax, rax 189 push rax 190 push rax 191 sidt [rsp] 192 xchg rax, [rsp + 2] 193 xchg rax, [rsp] 194 xchg rax, [rsp + 8] 195 196 xor rax, rax 197 push rax 198 push rax 199 sgdt [rsp] 200 xchg rax, [rsp + 2] 201 xchg rax, [rsp] 202 xchg rax, [rsp + 8] 203 204 ;; UINT64 Ldtr, Tr; 205 xor rax, rax 206 str ax 207 push rax 208 sldt ax 209 push rax 210 211 ;; UINT64 RFlags; 212 push qword [rbp + 40] 213 214 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 215 mov rax, cr8 216 push rax 217 mov rax, cr4 218 or rax, 0x208 219 mov cr4, rax 220 push rax 221 mov rax, cr3 222 push rax 223 mov rax, cr2 224 push rax 225 xor rax, rax 226 push rax 227 mov rax, cr0 228 push rax 229 230 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 231 mov rax, dr7 232 push rax 233 mov rax, dr6 234 push rax 235 mov rax, dr3 236 push rax 237 mov rax, dr2 238 push rax 239 mov rax, dr1 240 push rax 241 mov rax, dr0 242 push rax 243 244 ;; FX_SAVE_STATE_X64 FxSaveState; 245 sub rsp, 512 246 mov rdi, rsp 247 db 0xf, 0xae, 0x7 ;fxsave [rdi] 248 249 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear 250 cld 251 252 ;; UINT32 ExceptionData; 253 push qword [rbp + 16] 254 255 ;; Prepare parameter and call 256 mov rcx, [rbp + 8] 257 mov rdx, rsp 258 ; 259 ; Per X64 calling convention, allocate maximum parameter stack space 260 ; and make sure RSP is 16-byte aligned 261 ; 262 sub rsp, 4 * 8 + 8 263 mov rax, ASM_PFX(CommonExceptionHandler) 264 call rax 265 add rsp, 4 * 8 + 8 266 267 cli 268 ;; UINT64 ExceptionData; 269 add rsp, 8 270 271 ;; FX_SAVE_STATE_X64 FxSaveState; 272 273 mov rsi, rsp 274 db 0xf, 0xae, 0xE ; fxrstor [rsi] 275 add rsp, 512 276 277 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 278 ;; Skip restoration of DRx registers to support in-circuit emualators 279 ;; or debuggers set breakpoint in interrupt/exception context 280 add rsp, 8 * 6 281 282 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 283 pop rax 284 mov cr0, rax 285 add rsp, 8 ; not for Cr1 286 pop rax 287 mov cr2, rax 288 pop rax 289 mov cr3, rax 290 pop rax 291 mov cr4, rax 292 pop rax 293 mov cr8, rax 294 295 ;; UINT64 RFlags; 296 pop qword [rbp + 40] 297 298 ;; UINT64 Ldtr, Tr; 299 ;; UINT64 Gdtr[2], Idtr[2]; 300 ;; Best not let anyone mess with these particular registers... 301 add rsp, 48 302 303 ;; UINT64 Rip; 304 pop qword [rbp + 24] 305 306 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; 307 pop rax 308 ; mov gs, rax ; not for gs 309 pop rax 310 ; mov fs, rax ; not for fs 311 ; (X64 will not use fs and gs, so we do not restore it) 312 pop rax 313 mov es, rax 314 pop rax 315 mov ds, rax 316 pop qword [rbp + 32] ; for cs 317 pop qword [rbp + 56] ; for ss 318 319 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 320 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 321 pop rdi 322 pop rsi 323 add rsp, 8 ; not for rbp 324 pop qword [rbp + 48] ; for rsp 325 pop rbx 326 pop rdx 327 pop rcx 328 pop rax 329 pop r8 330 pop r9 331 pop r10 332 pop r11 333 pop r12 334 pop r13 335 pop r14 336 pop r15 337 338 mov rsp, rbp 339 pop rbp 340 add rsp, 16 341 cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 342 jz DoReturn 343 cmp qword [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 344 jz ErrorCode 345 jmp qword [rsp - 32] 346 ErrorCode: 347 sub rsp, 8 348 jmp qword [rsp - 24] 349 350 DoReturn: 351 cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET 352 jz DoIret 353 push rax 354 mov rax, rsp ; save old RSP to rax 355 mov rsp, [rsp + 0x20] 356 push qword [rax + 0x10] ; save CS in new location 357 push qword [rax + 0x8] ; save EIP in new location 358 push qword [rax + 0x18] ; save EFLAGS in new location 359 mov rax, [rax] ; restore rax 360 popfq ; restore EFLAGS 361 DB 0x48 ; prefix to composite "retq" with next "retf" 362 retf ; far return 363 DoIret: 364 iretq 365 366 ;------------------------------------------------------------------------------------- 367 ; GetTemplateAddressMap (&AddressMap); 368 ;------------------------------------------------------------------------------------- 369 ; comments here for definition of address map 370 global ASM_PFX(AsmGetTemplateAddressMap) 371 ASM_PFX(AsmGetTemplateAddressMap): 372 mov rax, AsmIdtVectorBegin 373 mov qword [rcx], rax 374 mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32 375 mov rax, HookAfterStubHeaderBegin 376 mov qword [rcx + 0x10], rax 377 ret 378 379 ;------------------------------------------------------------------------------------- 380 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr); 381 ;------------------------------------------------------------------------------------- 382 global ASM_PFX(AsmVectorNumFixup) 383 ASM_PFX(AsmVectorNumFixup): 384 mov rax, rdx 385 mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al 386 ret 387 388