#------------------------------------------------------------------------------ ; | |
# Copyright (c) 2012 - 2017, Intel Corporation. All rights reserved.<BR> | |
# This program and the accompanying materials | |
# are licensed and made available under the terms and conditions of the BSD License | |
# which accompanies this distribution. The full text of the license may be found at | |
# http://opensource.org/licenses/bsd-license.php. | |
# | |
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
# | |
# Module Name: | |
# | |
# ExceptionHandlerAsm.S | |
# | |
# Abstract: | |
# | |
# x64 CPU Exception Handler | |
# | |
# Notes: | |
# | |
#------------------------------------------------------------------------------ | |
ASM_GLOBAL ASM_PFX(CommonExceptionHandler) | |
#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions | |
#EXTRN ASM_PFX(mDoFarReturnFlag):QWORD # Do far return flag | |
.text | |
#ifdef __APPLE__ | |
# macros are different between GNU and Xcode as. | |
.macro IDT_MACRO | |
push $0 | |
#else | |
.macro IDT_MACRO arg | |
push \arg | |
#endif | |
.byte 0xe9 # jmp ASM_PFX(CommonInterruptEntry) | |
.long ASM_PFX(CommonInterruptEntry) - . - 4 | |
.endm | |
AsmIdtVectorBegin: | |
IDT_MACRO $0 | |
IDT_MACRO $1 | |
IDT_MACRO $2 | |
IDT_MACRO $3 | |
IDT_MACRO $4 | |
IDT_MACRO $5 | |
IDT_MACRO $6 | |
IDT_MACRO $7 | |
IDT_MACRO $8 | |
IDT_MACRO $9 | |
IDT_MACRO $10 | |
IDT_MACRO $11 | |
IDT_MACRO $12 | |
IDT_MACRO $13 | |
IDT_MACRO $14 | |
IDT_MACRO $15 | |
IDT_MACRO $16 | |
IDT_MACRO $17 | |
IDT_MACRO $18 | |
IDT_MACRO $19 | |
IDT_MACRO $20 | |
IDT_MACRO $21 | |
IDT_MACRO $22 | |
IDT_MACRO $23 | |
IDT_MACRO $24 | |
IDT_MACRO $25 | |
IDT_MACRO $26 | |
IDT_MACRO $27 | |
IDT_MACRO $28 | |
IDT_MACRO $29 | |
IDT_MACRO $30 | |
IDT_MACRO $31 | |
AsmIdtVectorEnd: | |
HookAfterStubHeaderBegin: | |
.byte 0x6a # push | |
PatchVectorNum: | |
.byte 0 # 0 will be fixed | |
.byte 0xe9 # jmp ASM_PFX(HookAfterStubHeaderEnd) | |
PatchFuncAddress: | |
.set HOOK_ADDRESS, ASM_PFX(HookAfterStubHeaderEnd) - . - 4 | |
.long HOOK_ADDRESS # will be fixed | |
ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) | |
ASM_PFX(HookAfterStubHeaderEnd): | |
pushq %rax | |
movq %rsp, %rax | |
andl $0x0fffffff0, %esp # make sure 16-byte aligned for exception context | |
subq $0x18, %rsp # reserve room for filling exception data later | |
pushq %rcx | |
movq 8(%rax), %rcx | |
bt %ecx, ASM_PFX(mErrorCodeFlag)(%rip) | |
jnc NoErrorData | |
pushq (%rsp) # push additional rcx to make stack alignment | |
NoErrorData: | |
xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack | |
movq (%rax), %rax # restore rax | |
#---------------------------------------; | |
# CommonInterruptEntry ; | |
#---------------------------------------; | |
# The follow algorithm is used for the common interrupt routine. | |
ASM_GLOBAL ASM_PFX(CommonInterruptEntry) | |
ASM_PFX(CommonInterruptEntry): | |
cli | |
# | |
# All interrupt handlers are invoked through interrupt gates, so | |
# IF flag automatically cleared at the entry point | |
# | |
# | |
# Calculate vector number | |
# | |
xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number. | |
andq $0x0FF, %rcx | |
cmp $32, %ecx # Intel reserved vector for exceptions? | |
jae NoErrorCode | |
pushq %rax | |
movl ASM_PFX(mErrorCodeFlag)(%rip), %eax | |
bt %ecx, %eax | |
popq %rax | |
jc CommonInterruptEntry_al_0000 | |
NoErrorCode: | |
# | |
# Push a dummy error code on the stack | |
# to maintain coherent stack map | |
# | |
pushq (%rsp) | |
movq $0, 8(%rsp) | |
CommonInterruptEntry_al_0000: | |
pushq %rbp | |
movq %rsp, %rbp | |
pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler | |
pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag | |
# | |
# Stack: | |
# +---------------------+ <-- 16-byte aligned ensured by processor | |
# + Old SS + | |
# +---------------------+ | |
# + Old RSP + | |
# +---------------------+ | |
# + RFlags + | |
# +---------------------+ | |
# + CS + | |
# +---------------------+ | |
# + RIP + | |
# +---------------------+ | |
# + Error Code + | |
# +---------------------+ | |
# + RCX / Vector Number + | |
# +---------------------+ | |
# + RBP + | |
# +---------------------+ <-- RBP, 16-byte aligned | |
# | |
# | |
# Since here the stack pointer is 16-byte aligned, so | |
# EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 | |
# is 16-byte aligned | |
# | |
#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; | |
#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; | |
pushq %r15 | |
pushq %r14 | |
pushq %r13 | |
pushq %r12 | |
pushq %r11 | |
pushq %r10 | |
pushq %r9 | |
pushq %r8 | |
pushq %rax | |
pushq 8(%rbp) # RCX | |
pushq %rdx | |
pushq %rbx | |
pushq 48(%rbp) # RSP | |
pushq (%rbp) # RBP | |
pushq %rsi | |
pushq %rdi | |
#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero | |
movzwq 56(%rbp), %rax | |
pushq %rax # for ss | |
movzwq 32(%rbp), %rax | |
pushq %rax # for cs | |
mov %ds, %rax | |
pushq %rax | |
mov %es, %rax | |
pushq %rax | |
mov %fs, %rax | |
pushq %rax | |
mov %gs, %rax | |
pushq %rax | |
movq %rcx, 8(%rbp) # save vector number | |
#; UINT64 Rip; | |
pushq 24(%rbp) | |
#; UINT64 Gdtr[2], Idtr[2]; | |
xorq %rax, %rax | |
pushq %rax | |
pushq %rax | |
sidt (%rsp) | |
xchgq 2(%rsp), %rax | |
xchgq (%rsp), %rax | |
xchgq 8(%rsp), %rax | |
xorq %rax, %rax | |
pushq %rax | |
pushq %rax | |
sgdt (%rsp) | |
xchgq 2(%rsp), %rax | |
xchgq (%rsp), %rax | |
xchgq 8(%rsp), %rax | |
#; UINT64 Ldtr, Tr; | |
xorq %rax, %rax | |
str %ax | |
pushq %rax | |
sldt %ax | |
pushq %rax | |
#; UINT64 RFlags; | |
pushq 40(%rbp) | |
#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; | |
movq %cr8, %rax | |
pushq %rax | |
movq %cr4, %rax | |
orq $0x208, %rax | |
movq %rax, %cr4 | |
pushq %rax | |
mov %cr3, %rax | |
pushq %rax | |
mov %cr2, %rax | |
pushq %rax | |
xorq %rax, %rax | |
pushq %rax | |
mov %cr0, %rax | |
pushq %rax | |
#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
movq %dr7, %rax | |
pushq %rax | |
movq %dr6, %rax | |
pushq %rax | |
movq %dr3, %rax | |
pushq %rax | |
movq %dr2, %rax | |
pushq %rax | |
movq %dr1, %rax | |
pushq %rax | |
movq %dr0, %rax | |
pushq %rax | |
#; FX_SAVE_STATE_X64 FxSaveState; | |
subq $512, %rsp | |
movq %rsp, %rdi | |
.byte 0x0f, 0x0ae, 0x07 #fxsave [rdi] | |
#; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear | |
cld | |
#; UINT32 ExceptionData; | |
pushq 16(%rbp) | |
#; Prepare parameter and call | |
mov 8(%rbp), %rcx | |
mov %rsp, %rdx | |
# | |
# Per X64 calling convention, allocate maximum parameter stack space | |
# and make sure RSP is 16-byte aligned | |
# | |
subq $40, %rsp | |
call ASM_PFX(CommonExceptionHandler) | |
addq $40, %rsp | |
cli | |
#; UINT64 ExceptionData; | |
addq $8, %rsp | |
#; FX_SAVE_STATE_X64 FxSaveState; | |
movq %rsp, %rsi | |
.byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi] | |
addq $512, %rsp | |
#; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
#; Skip restoration of DRx registers to support in-circuit emualators | |
#; or debuggers set breakpoint in interrupt/exception context | |
addq $48, %rsp | |
#; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; | |
popq %rax | |
movq %rax, %cr0 | |
addq $8, %rsp # not for Cr1 | |
popq %rax | |
movq %rax, %cr2 | |
popq %rax | |
movq %rax, %cr3 | |
popq %rax | |
movq %rax, %cr4 | |
popq %rax | |
movq %rax, %cr8 | |
#; UINT64 RFlags; | |
popq 40(%rbp) | |
#; UINT64 Ldtr, Tr; | |
#; UINT64 Gdtr[2], Idtr[2]; | |
#; Best not let anyone mess with these particular registers... | |
addq $48, %rsp | |
#; UINT64 Rip; | |
popq 24(%rbp) | |
#; UINT64 Gs, Fs, Es, Ds, Cs, Ss; | |
popq %rax | |
# mov %rax, %gs ; not for gs | |
popq %rax | |
# mov %rax, %fs ; not for fs | |
# (X64 will not use fs and gs, so we do not restore it) | |
popq %rax | |
mov %rax, %es | |
popq %rax | |
mov %rax, %ds | |
popq 32(%rbp) # for cs | |
popq 56(%rbp) # for ss | |
#; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; | |
#; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; | |
popq %rdi | |
popq %rsi | |
addq $8, %rsp # not for rbp | |
popq 48(%rbp) # for rsp | |
popq %rbx | |
popq %rdx | |
popq %rcx | |
popq %rax | |
popq %r8 | |
popq %r9 | |
popq %r10 | |
popq %r11 | |
popq %r12 | |
popq %r13 | |
popq %r14 | |
popq %r15 | |
movq %rbp, %rsp | |
popq %rbp | |
addq $16, %rsp | |
cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler | |
jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag | |
cmpb $1, -40(%rsp) | |
jz ErrorCode | |
jmp *-32(%rsp) | |
ErrorCode: | |
subq $8, %rsp | |
jmp *-24(%rsp) | |
DoReturn: | |
pushq %rax | |
movq ASM_PFX(mDoFarReturnFlag)(%rip), %rax | |
cmpq $0, %rax # Check if need to do far return instead of IRET | |
popq %rax | |
jz DoIret | |
pushq %rax | |
movq %rsp, %rax # save old RSP to rax | |
movq 0x20(%rsp), %rsp | |
pushq 0x10(%rax) # save CS in new location | |
pushq 0x8(%rax) # save EIP in new location | |
pushq 0x18(%rax) # save EFLAGS in new location | |
movq (%rax), %rax # restore rax | |
popfq # restore EFLAGS | |
lretq # far return | |
DoIret: | |
iretq | |
#------------------------------------------------------------------------------------- | |
# AsmGetTemplateAddressMap (&AddressMap); | |
#------------------------------------------------------------------------------------- | |
# comments here for definition of address map | |
ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap) | |
ASM_PFX(AsmGetTemplateAddressMap): | |
pushq %rbp | |
movq %rsp, %rbp | |
leaq AsmIdtVectorBegin(%rip), %rax | |
movq %rax, (%rcx) | |
.set ENTRY_SIZE, ASM_PFX(HookAfterStubHeaderEnd) - HookAfterStubHeaderBegin | |
movq $(ENTRY_SIZE), 0x08(%rcx) | |
leaq HookAfterStubHeaderBegin(%rip), %rax | |
movq %rax, 0x10(%rcx) | |
popq %rbp | |
ret | |
#------------------------------------------------------------------------------------- | |
# VOID | |
# EFIAPI | |
# AsmVectorNumFixup ( | |
# IN VOID *NewVectorAddr, // RCX | |
# IN UINT8 VectorNum // RDX | |
# IN VOID *OldVectorAddr, // R8 | |
# ); | |
#------------------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(AsmVectorNumFixup) | |
ASM_PFX(AsmVectorNumFixup): | |
pushq %rbp | |
movq %rsp, %rbp | |
# Patch vector # | |
movb %dl, (PatchVectorNum - HookAfterStubHeaderBegin)(%rcx) | |
# Patch Function address | |
subq %rcx, %r8 # Calculate the offset value | |
movl (PatchFuncAddress - HookAfterStubHeaderBegin)(%rcx), %eax | |
addq %r8, %rax | |
movl %eax, (PatchFuncAddress - HookAfterStubHeaderBegin)(%rcx) | |
popq %rbp | |
ret | |
#END | |