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