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
643 lines
16 KiB
ArmAsm
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
|