Anderw Fish 07da1ac8c4 UefiCpuPkg: CpuExceptionHandlerLib: Make self modifying code work with Xcode
CpuExceptionHandlerLib has code that contains absolute relocations, not supported by
Xcode for X64, and it then copies this code to an alternate location in memory. It is 
very hard to write IP relative self-modifiying code. I had to update AsmVectorNumFixup()
to also patch in the absolute addressess after the code was copied. 
 
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Anderw Fish <afish@apple.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16068 6f19259b-4bc3-4df7-8a09-765794883524
2014-09-09 06:50:51 +00:00

643 lines
16 KiB
ArmAsm

#------------------------------------------------------------------------------
#*
#* Copyright (c) 2012 - 2013, 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;
movl %cr4, %eax
orl $0x208, %eax
movl %eax, %cr4
pushl %eax
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
.byte 0x0f, 0x0ae, 0x07 #fxsave [edi]
#; 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
.byte 0x0f, 0x0ae, 0x0e # fxrstor [esi]
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
retf # 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