#------------------------------------------------------------------------------ | |
#* | |
#* Copyright (c) 2012 - 2015, 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. | |
#* | |
#* ExceptionHandlerAsm.S | |
#* | |
#* Abstract: | |
#* | |
#* IA32 CPU Exception Handler | |
# | |
#------------------------------------------------------------------------------ | |
#.MMX | |
#.XMM | |
ASM_GLOBAL ASM_PFX(CommonExceptionHandler) | |
ASM_GLOBAL ASM_PFX(CommonInterruptEntry) | |
ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) | |
#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions | |
#EXTRN ASM_PFX(mDoFarReturnFlag):DWORD # Do far return flag | |
.text | |
# | |
# exception handler stub table | |
# | |
Exception0Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 0 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception1Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 1 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception2Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 2 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception3Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 3 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception4Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 4 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception5Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 5 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception6Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 6 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception7Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 7 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception8Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 8 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception9Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 9 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception10Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 10 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception11Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 11 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception12Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 12 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception13Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 13 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception14Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 14 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception15Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 15 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception16Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 16 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception17Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 17 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception18Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 18 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception19Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 19 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception20Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 20 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception21Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 21 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception22Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 22 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception23Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 23 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception24Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 24 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception25Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 25 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception26Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 26 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception27Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 27 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception28Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 28 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception29Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 29 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception30Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 30 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
Exception31Handle: | |
.byte 0x6a # push #VectorNum | |
.byte 31 | |
pushl %eax | |
.byte 0xB8 | |
.long ASM_PFX(CommonInterruptEntry) | |
jmp *%eax | |
HookAfterStubBegin: | |
.byte 0x6a # push | |
VectorNum: | |
.byte 0 # 0 will be fixed | |
pushl %eax | |
.byte 0xB8 # movl ASM_PFX(HookAfterStubHeaderEnd), %eax | |
.long ASM_PFX(HookAfterStubHeaderEnd) | |
jmp *%eax | |
ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) | |
ASM_PFX(HookAfterStubHeaderEnd): | |
popl %eax | |
subl $8, %esp # reserve room for filling exception data later | |
pushl 8(%esp) | |
xchgl (%esp), %ecx # get vector number | |
bt %ecx, ASM_PFX(mErrorCodeFlag) | |
jnc NoErrorData | |
pushl (%esp) # addition push if exception data needed | |
NoErrorData: | |
xchg (%esp), %ecx # restore ecx | |
pushl %eax | |
#---------------------------------------; | |
# CommonInterruptEntry ; | |
#---------------------------------------; | |
# The follow algorithm is used for the common interrupt routine. | |
ASM_GLOBAL ASM_PFX(CommonInterruptEntry) | |
ASM_PFX(CommonInterruptEntry): | |
cli | |
popl %eax | |
# | |
# All interrupt handlers are invoked through interrupt gates, so | |
# IF flag automatically cleared at the entry point | |
# | |
# | |
# Get vector number from top of stack | |
# | |
xchgl (%esp), %ecx | |
andl $0x0FF, %ecx # Vector number should be less than 256 | |
cmpl $32, %ecx # Intel reserved vector for exceptions? | |
jae NoErrorCode | |
bt %ecx, ASM_PFX(mErrorCodeFlag) | |
jc HasErrorCode | |
NoErrorCode: | |
# | |
# Stack: | |
# +---------------------+ | |
# + EFlags + | |
# +---------------------+ | |
# + CS + | |
# +---------------------+ | |
# + EIP + | |
# +---------------------+ | |
# + ECX + | |
# +---------------------+ <-- ESP | |
# | |
# Registers: | |
# ECX - Vector Number | |
# | |
# | |
# Put Vector Number on stack | |
# | |
pushl %ecx | |
# | |
# Put 0 (dummy) error code on stack, and restore ECX | |
# | |
xorl %ecx, %ecx # ECX = 0 | |
xchgl 4(%esp), %ecx | |
jmp ErrorCodeAndVectorOnStack | |
HasErrorCode: | |
# | |
# Stack: | |
# +---------------------+ | |
# + EFlags + | |
# +---------------------+ | |
# + CS + | |
# +---------------------+ | |
# + EIP + | |
# +---------------------+ | |
# + Error Code + | |
# +---------------------+ | |
# + ECX + | |
# +---------------------+ <-- ESP | |
# | |
# Registers: | |
# ECX - Vector Number | |
# | |
# | |
# Put Vector Number on stack and restore ECX | |
# | |
xchgl (%esp), %ecx | |
ErrorCodeAndVectorOnStack: | |
pushl %ebp | |
movl %esp, %ebp | |
# | |
# Stack: | |
# +---------------------+ | |
# + EFlags + | |
# +---------------------+ | |
# + CS + | |
# +---------------------+ | |
# + EIP + | |
# +---------------------+ | |
# + Error Code + | |
# +---------------------+ | |
# + Vector Number + | |
# +---------------------+ | |
# + EBP + | |
# +---------------------+ <-- EBP | |
# | |
# | |
# Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 | |
# is 16-byte aligned | |
# | |
andl $0x0fffffff0, %esp | |
subl $12, %esp | |
subl $8, %esp | |
pushl $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler | |
pushl $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag | |
#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; | |
pushl %eax | |
pushl %ecx | |
pushl %edx | |
pushl %ebx | |
leal 24(%ebp), %ecx | |
pushl %ecx # ESP | |
pushl (%ebp) # EBP | |
pushl %esi | |
pushl %edi | |
#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; | |
movl %ss, %eax | |
pushl %eax | |
movzwl 16(%ebp), %eax | |
pushl %eax | |
movl %ds, %eax | |
pushl %eax | |
movl %es, %eax | |
pushl %eax | |
movl %fs, %eax | |
pushl %eax | |
movl %gs, %eax | |
pushl %eax | |
#; UINT32 Eip; | |
movl 12(%ebp), %eax | |
pushl %eax | |
#; UINT32 Gdtr[2], Idtr[2]; | |
subl $8, %esp | |
sidt (%esp) | |
movl 2(%esp), %eax | |
xchgl (%esp), %eax | |
andl $0x0FFFF, %eax | |
movl %eax, 4(%esp) | |
subl $8, %esp | |
sgdt (%esp) | |
movl 2(%esp), %eax | |
xchgl (%esp), %eax | |
andl $0x0FFFF, %eax | |
movl %eax, 4(%esp) | |
#; UINT32 Ldtr, Tr; | |
xorl %eax, %eax | |
str %ax | |
pushl %eax | |
sldt %ax | |
pushl %eax | |
#; UINT32 EFlags; | |
movl 20(%ebp), %eax | |
pushl %eax | |
#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; | |
## insure FXSAVE/FXRSTOR is enabled in CR4... | |
## ... while we're at it, make sure DE is also enabled... | |
mov $1, %eax | |
pushl %ebx # temporarily save value of ebx on stack | |
cpuid # use CPUID to determine if FXSAVE/FXRESTOR | |
# and DE are supported | |
popl %ebx # retore value of ebx that was overwritten | |
# by CPUID | |
movl %cr4, %eax | |
pushl %eax # push cr4 firstly | |
testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support | |
jz L1 | |
orl $BIT9, %eax # Set CR4.OSFXSR | |
L1: | |
testl $BIT2, %edx # Test for Debugging Extensions support | |
jz L2 | |
orl $BIT3, %eax # Set CR4.DE | |
L2: | |
movl %eax, %cr4 | |
movl %cr3, %eax | |
pushl %eax | |
movl %cr2, %eax | |
pushl %eax | |
xorl %eax, %eax | |
pushl %eax | |
movl %cr0, %eax | |
pushl %eax | |
#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
movl %dr7, %eax | |
pushl %eax | |
movl %dr6, %eax | |
pushl %eax | |
movl %dr3, %eax | |
pushl %eax | |
movl %dr2, %eax | |
pushl %eax | |
movl %dr1, %eax | |
pushl %eax | |
movl %dr0, %eax | |
pushl %eax | |
#; FX_SAVE_STATE_IA32 FxSaveState; | |
subl $512, %esp | |
movl %esp, %edi | |
testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support. | |
# edx still contains result from CPUID above | |
jz L3 | |
.byte 0x0f, 0x0ae, 0x07 #fxsave [edi] | |
L3: | |
#; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear | |
cld | |
#; UINT32 ExceptionData; | |
pushl 8(%ebp) | |
#; Prepare parameter and call | |
movl %esp, %edx | |
pushl %edx | |
movl 4(%ebp), %edx | |
pushl %edx | |
# | |
# Call External Exception Handler | |
# | |
call ASM_PFX(CommonExceptionHandler) | |
addl $8, %esp | |
cli | |
#; UINT32 ExceptionData; | |
addl $4, %esp | |
#; FX_SAVE_STATE_IA32 FxSaveState; | |
movl %esp, %esi | |
movl $1, %eax | |
cpuid # use CPUID to determine if FXSAVE/FXRESTOR | |
# are supported | |
testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support | |
jz L4 | |
.byte 0x0f, 0x0ae, 0x0e # fxrstor [esi] | |
L4: | |
addl $512, %esp | |
#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
#; Skip restoration of DRx registers to support in-circuit emualators | |
#; or debuggers set breakpoint in interrupt/exception context | |
addl $24, %esp | |
#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; | |
popl %eax | |
movl %eax, %cr0 | |
addl $4, %esp # not for Cr1 | |
popl %eax | |
movl %eax, %cr2 | |
popl %eax | |
movl %eax, %cr3 | |
popl %eax | |
movl %eax, %cr4 | |
#; UINT32 EFlags; | |
popl 20(%ebp) | |
#; UINT32 Ldtr, Tr; | |
#; UINT32 Gdtr[2], Idtr[2]; | |
#; Best not let anyone mess with these particular registers... | |
addl $24, %esp | |
#; UINT32 Eip; | |
popl 12(%ebp) | |
#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; | |
#; NOTE - modified segment registers could hang the debugger... We | |
#; could attempt to insulate ourselves against this possibility, | |
#; but that poses risks as well. | |
#; | |
popl %gs | |
popl %fs | |
popl %es | |
popl %ds | |
popl 16(%ebp) | |
popl %ss | |
#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; | |
popl %edi | |
popl %esi | |
addl $4, %esp # not for ebp | |
addl $4, %esp # not for esp | |
popl %ebx | |
popl %edx | |
popl %ecx | |
popl %eax | |
popl -8(%ebp) | |
popl -4(%ebp) | |
movl %ebp, %esp | |
popl %ebp | |
addl $8, %esp | |
cmpl $0, -16(%esp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler | |
jz DoReturn | |
cmpl $1, -20(%esp) # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag | |
jz ErrorCode | |
jmp *-16(%esp) | |
ErrorCode: | |
subl $4, %esp | |
jmp *-12(%esp) | |
DoReturn: | |
cmpl $0, ASM_PFX(mDoFarReturnFlag) | |
jz DoIret | |
pushl 8(%esp) # save EFLAGS | |
addl $16, %esp | |
pushl -8(%esp) # save CS in new location | |
pushl -8(%esp) # save EIP in new location | |
pushl -8(%esp) # save EFLAGS in new location | |
popfl # restore EFLAGS | |
lret # far return | |
DoIret: | |
iretl | |
#---------------------------------------; | |
# _AsmGetTemplateAddressMap ; | |
#---------------------------------------; | |
# | |
# Protocol prototype | |
# AsmGetTemplateAddressMap ( | |
# EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap | |
# ); | |
# | |
# Routine Description: | |
# | |
# Return address map of interrupt handler template so that C code can generate | |
# interrupt table. | |
# | |
# Arguments: | |
# | |
# | |
# Returns: | |
# | |
# Nothing | |
# | |
# | |
# Input: [ebp][0] = Original ebp | |
# [ebp][4] = Return address | |
# | |
# Output: Nothing | |
# | |
# Destroys: Nothing | |
#-----------------------------------------------------------------------------; | |
#------------------------------------------------------------------------------------- | |
# AsmGetAddressMap (&AddressMap); | |
#------------------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap) | |
ASM_PFX(AsmGetTemplateAddressMap): | |
pushl %ebp | |
movl %esp,%ebp | |
pushal | |
movl 0x8(%ebp), %ebx | |
movl $Exception0Handle, (%ebx) | |
movl $(Exception1Handle - Exception0Handle), 0x4(%ebx) | |
movl $(HookAfterStubBegin), 0x8(%ebx) | |
popal | |
popl %ebp | |
ret | |
#------------------------------------------------------------------------------------- | |
# AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr); | |
#------------------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(AsmVectorNumFixup) | |
ASM_PFX(AsmVectorNumFixup): | |
movl 8(%esp), %eax | |
movl 4(%esp), %ecx | |
movb %al, (VectorNum - HookAfterStubBegin)(%ecx) | |
ret |