1 #------------------------------------------------------------------------------ ;
2 # Copyright (c) 2012 - 2017, 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.
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.
13 # ExceptionHandlerAsm.S
17 # x64 CPU Exception Handler
21 #------------------------------------------------------------------------------
25 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
27 #EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
28 #EXTRN ASM_PFX(mDoFarReturnFlag):QWORD # Do far return flag
32 # macros are different between GNU and Xcode as.
39 .byte 0xe9 # jmp ASM_PFX(CommonInterruptEntry)
40 .long ASM_PFX(CommonInterruptEntry) - . - 4
78 HookAfterStubHeaderBegin:
81 .byte 0 # 0 will be fixed
82 .byte 0xe9 # jmp ASM_PFX(HookAfterStubHeaderEnd)
84 .set HOOK_ADDRESS, ASM_PFX(HookAfterStubHeaderEnd) - . - 4
85 .long HOOK_ADDRESS # will be fixed
86 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
87 ASM_PFX(HookAfterStubHeaderEnd):
90 andl $0x0fffffff0, %esp # make sure 16-byte aligned for exception context
91 subq $0x18, %rsp # reserve room for filling exception data later
94 bt %ecx, ASM_PFX(mErrorCodeFlag)(%rip)
96 pushq (%rsp) # push additional rcx to make stack alignment
98 xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack
99 movq (%rax), %rax # restore rax
101 #---------------------------------------;
102 # CommonInterruptEntry ;
103 #---------------------------------------;
104 # The follow algorithm is used for the common interrupt routine.
106 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
107 ASM_PFX(CommonInterruptEntry):
110 # All interrupt handlers are invoked through interrupt gates, so
111 # IF flag automatically cleared at the entry point
114 # Calculate vector number
116 xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
118 cmp $32, %ecx # Intel reserved vector for exceptions?
121 movl ASM_PFX(mErrorCodeFlag)(%rip), %eax
124 jc CommonInterruptEntry_al_0000
129 # Push a dummy error code on the stack
130 # to maintain coherent stack map
134 CommonInterruptEntry_al_0000:
137 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
138 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
142 # +---------------------+ <-- 16-byte aligned ensured by processor
144 # +---------------------+
146 # +---------------------+
148 # +---------------------+
150 # +---------------------+
152 # +---------------------+
154 # +---------------------+
155 # + RCX / Vector Number +
156 # +---------------------+
158 # +---------------------+ <-- RBP, 16-byte aligned
163 # Since here the stack pointer is 16-byte aligned, so
164 # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
168 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
169 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
187 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
188 movzwq 56(%rbp), %rax
190 movzwq 32(%rbp), %rax
201 movq %rcx, 8(%rbp) # save vector number
206 #; UINT64 Gdtr[2], Idtr[2];
233 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
249 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
263 #; FX_SAVE_STATE_X64 FxSaveState;
266 .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi]
268 #; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
271 #; UINT32 ExceptionData;
274 #; Prepare parameter and call
278 # Per X64 calling convention, allocate maximum parameter stack space
279 # and make sure RSP is 16-byte aligned
282 call ASM_PFX(CommonExceptionHandler)
286 #; UINT64 ExceptionData;
289 #; FX_SAVE_STATE_X64 FxSaveState;
292 .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi]
295 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
296 #; Skip restoration of DRx registers to support in-circuit emualators
297 #; or debuggers set breakpoint in interrupt/exception context
300 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
303 addq $8, %rsp # not for Cr1
317 #; UINT64 Gdtr[2], Idtr[2];
318 #; Best not let anyone mess with these particular registers...
324 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
326 # mov %rax, %gs ; not for gs
328 # mov %rax, %fs ; not for fs
329 # (X64 will not use fs and gs, so we do not restore it)
334 popq 32(%rbp) # for cs
335 popq 56(%rbp) # for ss
337 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
338 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
341 addq $8, %rsp # not for rbp
342 popq 48(%rbp) # for rsp
359 cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
360 jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
370 movq ASM_PFX(mDoFarReturnFlag)(%rip), %rax
371 cmpq $0, %rax # Check if need to do far return instead of IRET
375 movq %rsp, %rax # save old RSP to rax
376 movq 0x20(%rsp), %rsp
377 pushq 0x10(%rax) # save CS in new location
378 pushq 0x8(%rax) # save EIP in new location
379 pushq 0x18(%rax) # save EFLAGS in new location
380 movq (%rax), %rax # restore rax
381 popfq # restore EFLAGS
387 #-------------------------------------------------------------------------------------
388 # AsmGetTemplateAddressMap (&AddressMap);
389 #-------------------------------------------------------------------------------------
390 # comments here for definition of address map
391 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
392 ASM_PFX(AsmGetTemplateAddressMap):
396 leaq AsmIdtVectorBegin(%rip), %rax
398 .set ENTRY_SIZE, ASM_PFX(HookAfterStubHeaderEnd) - HookAfterStubHeaderBegin
399 movq $(ENTRY_SIZE), 0x08(%rcx)
400 leaq HookAfterStubHeaderBegin(%rip), %rax
401 movq %rax, 0x10(%rcx)
406 #-------------------------------------------------------------------------------------
409 # AsmVectorNumFixup (
410 # IN VOID *NewVectorAddr, // RCX
411 # IN UINT8 VectorNum // RDX
412 # IN VOID *OldVectorAddr, // R8
414 #-------------------------------------------------------------------------------------
415 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
416 ASM_PFX(AsmVectorNumFixup):
421 movb %dl, (PatchVectorNum - HookAfterStubHeaderBegin)(%rcx)
423 # Patch Function address
424 subq %rcx, %r8 # Calculate the offset value
425 movl (PatchFuncAddress - HookAfterStubHeaderBegin)(%rcx), %eax
427 movl %eax, (PatchFuncAddress - HookAfterStubHeaderBegin)(%rcx)