AsmFuncs.S revision 4fd606d1f5abe38e1f42c38de1d2e895166bd0f4
#/**@file
# Low leve IA32 specific debug support functions.
#
# Copyright (c) 2006 - 2011, 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.
#
#**/
ASM_GLOBAL ASM_PFX(OrigVector)
ASM_GLOBAL ASM_PFX(InterruptEntryStub)
ASM_GLOBAL ASM_PFX(StubSize)
ASM_GLOBAL ASM_PFX(CommonIdtEntry)
ASM_GLOBAL ASM_PFX(FxStorSupport)
ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)
ASM_PFX(AppEsp): .long 0x11111111 # ?
ASM_PFX(DebugEsp): .long 0x22222222 # ?
ASM_PFX(ExtraPush): .long 0x33333333 # ?
ASM_PFX(ExceptData): .long 0x44444444 # ?
ASM_PFX(Eflags): .long 0x55555555 # ?
ASM_PFX(OrigVector): .long 0x66666666 # ?
#------------------------------------------------------------------------------
# BOOLEAN
# FxStorSupport (
# void
# )
#
# Abstract: Returns TRUE if FxStor instructions are supported
#
ASM_GLOBAL ASM_PFX(FxStorSupport)
ASM_PFX(FxStorSupport):
#
# cpuid corrupts ebx which must be preserved per the C calling convention
#
push %ebx
mov $0x1,%eax
cpuid
mov %edx,%eax
and $0x1000000,%eax
shr $0x18,%eax
pop %ebx
ret
#------------------------------------------------------------------------------
# void
# Vect2Desc (
# DESCRIPTOR * DestDesc,
# void (*Vector) (void)
# )
#
# Abstract: Encodes an IDT descriptor with the given physical address
#
ASM_GLOBAL ASM_PFX(Vect2Desc)
ASM_PFX(Vect2Desc):
push %ebp
mov %esp,%ebp
mov 0xc(%ebp),%eax
mov 0x8(%ebp),%ecx
mov %ax,(%ecx)
movw $0x20,0x2(%ecx)
movw $0x8e00,0x4(%ecx)
shr $0x10,%eax
mov %ax,0x6(%ecx)
leave
ret
ASM_GLOBAL ASM_PFX(InterruptEntryStub)
ASM_PFX(InterruptEntryStub):
mov %esp,0x0 # save stack top
mov $0x0,%esp # switch to debugger stack
push $0x0 # push vector number - will be modified before installed
jmp ASM_PFX(CommonIdtEntry) # jump CommonIdtEntry
ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd)
ASM_PFX(InterruptEntryStubEnd):
#------------------------------------------------------------------------------
# CommonIdtEntry
#
# Abstract: This code is not a function, but is the common part for all IDT
# vectors.
#
ASM_GLOBAL ASM_PFX(CommonIdtEntry)
ASM_PFX(CommonIdtEntry):
##
## At this point, the stub has saved the current application stack esp into AppEsp
## and switched stacks to the debug stack, where it pushed the vector number
##
## The application stack looks like this:
##
## ...
## (last application stack entry)
## eflags from interrupted task
## CS from interrupted task
## EIP from interrupted task
## Error code <-------------------- Only present for some exeption types
##
##
## The stub switched us to the debug stack and pushed the interrupt number.
##
## Next, construct the context record. It will be build on the debug stack by
## pushing the registers in the correct order so as to create the context structure
## on the debug stack. The context record must be built from the end back to the
## beginning because the stack grows down...
#
## For reference, the context record looks like this:
##
## typedef
## struct {
## UINT32 ExceptionData;
## FX_SAVE_STATE_IA32 FxSaveState;
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
## UINT32 Cr0, Cr2, Cr3, Cr4;
## UINT32 EFlags;
## UINT32 Ldtr, Tr;
## UINT32 Gdtr[2], Idtr[2];
## UINT32 Eip;
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
## } SYSTEM_CONTEXT_IA32; // 32 bit system context record
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pusha
## Save interrupt state eflags register...
pushf
pop %eax
## We need to determine if any extra data was pushed by the exception, and if so, save it
## To do this, we check the exception number pushed by the stub, and cache the
## result in a variable since we'll need this again.
mov %eax,0x0
cmpl $0x8,0x0
jne ASM_PFX(CommonIdtEntry+0x20)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
cmpl $0xa,0x0
jne ASM_PFX(CommonIdtEntry+0x35)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
cmpl $0xb,0x0
jne ASM_PFX(CommonIdtEntry+0x4a)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
cmpl $0xc,0x0
jne ASM_PFX(CommonIdtEntry+0x5f)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
cmpl $0xd,0x0
jne ASM_PFX(CommonIdtEntry+0x74)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
cmpl $0xe,0x0
jne ASM_PFX(CommonIdtEntry+0x89)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
cmpl $0x11,0x0
jne ASM_PFX(CommonIdtEntry+0x9e)
movl $0x1,0x0
jmp ASM_PFX(CommonIdtEntry+0xa8)
movl $0x0,0x0
## If there's some extra data, save it also, and modify the saved AppEsp to effectively
## pop this value off the application's stack.
cmpl $0x1,0x0
jne ASM_PFX(CommonIdtEntry+0xc8)
mov 0x0,%eax
mov (%eax),%ebx
mov %ebx,0x0
add $0x4,%eax
mov %eax,0x0
jmp ASM_PFX(CommonIdtEntry+0xd2)
movl $0x0,0x0
## The "pushad" above pushed the debug stack esp. Since what we're actually doing
## is building the context record on the debug stack, we need to save the pushed
## debug ESP, and replace it with the application's last stack entry...
mov 0xc(%esp),%eax
mov %eax,0x0
mov 0x0,%eax
add $0xc,%eax
# application stack has eflags, cs, & eip, so
# last actual application stack entry is
# 12 bytes into the application stack.
mov %eax,0xc(%esp)
## continue building context record
## UINT32 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
mov %ss,%eax
push %eax
# CS from application is one entry back in application stack
mov 0x0,%eax
movzwl 0x4(%eax),%eax
push %eax
mov %ds,%eax
push %eax
mov %es,%eax
push %eax
mov %fs,%eax
push %eax
mov %gs,%eax
push %eax
## UINT32 Eip;
# Eip from application is on top of application stack
mov 0x0,%eax
pushl (%eax)
## UINT32 Gdtr[2], Idtr[2];
push $0x0
push $0x0
sidtl (%esp)
push $0x0
push $0x0
sgdtl (%esp)
## UINT32 Ldtr, Tr;
xor %eax,%eax
str %eax
push %eax
sldt %eax
push %eax
## UINT32 EFlags;
## Eflags from application is two entries back in application stack
mov 0x0,%eax
pushl 0x8(%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 %cr4,%eax
or $0x208,%eax
mov %eax,%cr4
push %eax
mov %cr3,%eax
push %eax
mov %cr2,%eax
push %eax
push $0x0
mov %cr0,%eax
push %eax
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
mov %db7,%eax
push %eax
## clear Dr7 while executing debugger itself
xor %eax,%eax
mov %eax,%db7
mov %db6,%eax
push %eax
## insure all status bits in dr6 are clear...
xor %eax,%eax
mov %eax,%db6
mov %db3,%eax
push %eax
mov %db2,%eax
push %eax
mov %db1,%eax
push %eax
mov %db0,%eax
push %eax
## FX_SAVE_STATE_IA32 FxSaveState;
sub $0x200,%esp
mov %esp,%edi
# IMPORTANT!! The debug stack has been carefully constructed to
# insure that esp and edi are 16 byte aligned when we get here.
# They MUST be. If they are not, a GP fault will occur.
fxsave (%edi)
## UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
## UINT32 ExceptionData;
mov 0x0,%eax
push %eax
# call to C code which will in turn call registered handler
# pass in the vector number
mov %esp,%eax
push %eax
mov 0x0,%eax
push %eax
call ASM_PFX(CommonIdtEntry+0x184)
add $0x8,%esp
# restore context...
## UINT32 ExceptionData;
add $0x4,%esp
## FX_SAVE_STATE_IA32 FxSaveState;
mov %esp,%esi
fxrstor (%esi)
add $0x200,%esp
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
pop %eax
mov %eax,%db0
pop %eax
mov %eax,%db1
pop %eax
mov %eax,%db2
pop %eax
mov %eax,%db3
## skip restore of dr6. We cleared dr6 during the context save.
add $0x4,%esp
pop %eax
mov %eax,%db7
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
pop %eax
mov %eax,%cr0
add $0x4,%esp
pop %eax
mov %eax,%cr2
pop %eax
mov %eax,%cr3
pop %eax
mov %eax,%cr4
## UINT32 EFlags;
mov 0x0,%eax
popl 0x8(%eax)
## UINT32 Ldtr, Tr;
## UINT32 Gdtr[2], Idtr[2];
## Best not let anyone mess with these particular registers...
add $0x18,%esp
## UINT32 Eip;
popl (%eax)
## UINT32 SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
## NOTE - modified segment registers could hang the debugger... We
## could attempt to insulate ourselves against this possibility,
## but that poses risks as well.
##
pop %gs
pop %fs
pop %es
pop %ds
popl 0x4(%eax)
pop %ss
mov 0xc(%esp),%ebx
## The next stuff to restore is the general purpose registers that were pushed
## using the "pushad" instruction.
##
## The value of ESP as stored in the context record is the application ESP
## including the 3 entries on the application stack caused by the exception
## itself. It may have been modified by the debug agent, so we need to
## determine if we need to relocate the application stack.
mov 0x0,%eax # move the potentially modified AppEsp into ebx
add $0xc,%eax
cmp %eax,%ebx
je ASM_PFX(CommonIdtEntry+0x202)
mov 0x0,%eax
mov (%eax),%ecx # EIP
mov %ecx,(%ebx)
mov 0x4(%eax),%ecx # CS
mov %ecx,0x4(%ebx)
mov 0x8(%eax),%ecx # EFLAGS
mov %ecx,0x8(%ebx)
mov %ebx,%eax # modify the saved AppEsp to the new AppEsp
mov %eax,0x0
mov 0x0,%eax # restore the DebugEsp on the debug stack
# so our "popad" will not cause a stack switch
mov %eax,0xc(%esp)
cmpl $0x68,0x0
jne PhonyIretd+0xd
## Restore eflags so when we chain, the flags will be exactly as if we were never here.
## We gin up the stack to do an iretd so we can get ALL the flags.
mov 0x0,%eax
mov 0x8(%eax),%ebx
and $0xfffffcff,%ebx # special handling for IF and TF
push %ebx
push %cs
push $0x0
iret
PhonyIretd:
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
popa
## Switch back to application stack
mov 0x0,%esp
jmp *0x0
## Jump to original handler
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
popa
## Switch back to application stack
mov 0x0,%esp
## We're outa here...
iret