#/**@file\r
# Low leve x64 specific debug support functions.\r
#\r
-# Copyright (c) 2006, Intel Corporation\r
+# Copyright (c) 2006 - 2008, Intel Corporation\r
# All rights reserved. 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
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
#\r
-#**/\r
+#**/ \r
\r
-.globl _OrigVector\r
-.globl _InterruptEntryStub\r
-.globl _StubSize\r
-.globl _CommonIdtEntry\r
-.globl _FxStorSupport\r
+.intel_syntax noprefix\r
\r
-_AppEsp: .long 0x11111111 # ?\r
-_DebugEsp: .long 0x22222222 # ?\r
-_ExtraPush: .long 0x33333333 # ?\r
-_ExceptData: .long 0x44444444 # ?\r
-_Eflags: .long 0x55555555 # ?\r
-_OrigVector: .long 0x66666666 # ?\r
-_StubSize: .long _InterruptEntryStubEnd - _InterruptEntryStub\r
\r
-.globl _FxStorSupport\r
-_FxStorSupport:\r
- ret\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
+ \r
+.data \r
\r
-.globl _Vect2Desc\r
-_Vect2Desc:\r
- ret\r
+ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)\r
+ASM_PFX(AppRsp): .long 0x11111111 # ?\r
+ .long 0x11111111 # ?\r
+ASM_PFX(DebugRsp): .long 0x22222222 # ?\r
+ .long 0x22222222 # ?\r
+ASM_PFX(ExtraPush): .long 0x33333333 # ?\r
+ .long 0x33333333 # ?\r
+ASM_PFX(ExceptData): .long 0x44444444 # ?\r
+ .long 0x44444444 # ?\r
+ASM_PFX(Rflags): .long 0x55555555 # ?\r
+ .long 0x55555555 # ?\r
+ASM_PFX(OrigVector): .long 0x66666666 # ?\r
+ .long 0x66666666 # ?\r
\r
-.globl _InterruptEntryStub\r
-_InterruptEntryStub:\r
- ret\r
+## The declarations below define the memory region that will be used for the debug stack.\r
+## The context record will be built by pushing register values onto this stack.\r
+## It is imparitive that alignment be carefully managed, since the FXSTOR and\r
+## FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.\r
+##\r
+## The stub will switch stacks from the application stack to the debuger stack\r
+## and pushes the exception number.\r
+##\r
+## Then we building the context record on the stack. Since the stack grows down,\r
+## we push the fields of the context record from the back to the front. There\r
+## are 336 bytes of stack used prior allocating the 512 bytes of stack to be\r
+## used as the memory buffer for the fxstor instruction. Therefore address of\r
+## the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which\r
+## must be 16 byte aligned.\r
+##\r
+## We carefully locate the stack to make this happen.\r
+##\r
+## For reference, the context structure looks like this:\r
+## struct {\r
+## UINT64 ExceptionData;\r
+## FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned\r
+## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+## UINT64 RFlags;\r
+## UINT64 Ldtr, Tr;\r
+## UINT64 Gdtr[2], Idtr[2];\r
+## UINT64 Rip;\r
+## UINT64 Gs, Fs, Es, Ds, Cs, Ss;\r
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+## } SYSTEM_CONTEXT_X64; // 64 bit system context record\r
+\r
+.align 16\r
+DebugStackEnd : .ascii "DbgStkEnd >>>>>>" # 16 byte long string - must be 16 bytes to preserve alignment\r
+ .rept 0x1ffc\r
+ .long 0x00000000 \r
+ .endr\r
+ # 32K should be enough stack\r
+ # This allocation is coocked to insure\r
+ # that the the buffer for the FXSTORE instruction\r
+ # will be 16 byte aligned also.\r
+ #\r
+ASM_PFX(ExceptionNumber): .long 0x77777777 # first entry will be the vector number pushed by the stub\r
+ .long 0x77777777 # ?\r
+\r
+DebugStackBegin : .ascii "<<<< DbgStkBegin" # initial debug ESP == DebugStackBegin, set in stub\r
+ \r
+\r
+.text\r
+\r
+#------------------------------------------------------------------------------\r
+# BOOLEAN\r
+# FxStorSupport (\r
+# void\r
+# )\r
+#\r
+# Abstract: Returns TRUE if FxStor instructions are supported\r
+#\r
+.globl ASM_PFX(FxStorSupport)\r
+ASM_PFX(FxStorSupport): \r
+#\r
+# cpuid corrupts rbx which must be preserved per the C calling convention\r
+#\r
+ push rbx\r
+ mov rax, 1\r
+ cpuid\r
+ mov eax, edx\r
+ and rax, 0x01000000\r
+ shr rax, 24\r
+ pop rbx\r
+ ret\r
+#------------------------------------------------------------------------------\r
+# void\r
+# Vect2Desc (\r
+# IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx\r
+# void (*Vector) (void) // rdx\r
+# )\r
+#\r
+# Abstract: Encodes an IDT descriptor with the given physical address\r
+#\r
+.globl ASM_PFX(Vect2Desc)\r
+ASM_PFX(Vect2Desc):\r
+ mov rax, rdx\r
+ mov word ptr [rcx], ax # write bits 15..0 of offset\r
+ mov dx, cs\r
+ mov word ptr [rcx+2], dx # SYS_CODE_SEL from GDT\r
+ mov word ptr [rcx+4], 0x0e00 OR 0x8000 # type = 386 interrupt gate, present\r
+ shr rax, 16\r
+ mov word ptr [rcx+6], ax # write bits 31..16 of offset\r
+ shr rax, 16\r
+ mov dword ptr [rcx+8], eax # write bits 63..32 of offset\r
+\r
+ ret\r
+\r
+#------------------------------------------------------------------------------\r
+# InterruptEntryStub\r
+#\r
+# Abstract: This code is not a function, but is a small piece of code that is\r
+# copied and fixed up once for each IDT entry that is hooked.\r
+#\r
+.globl ASM_PFX(InterruptEntryStub)\r
+ASM_PFX(InterruptEntryStub):\r
+\r
+ push 0 # push vector number - will be modified before installed\r
+ jmp ASM_PFX(CommonIdtEntry)\r
+ \r
+.globl ASM_PFX(InterruptEntryStubEnd)\r
+ASM_PFX(InterruptEntryStubEnd):\r
\r
-.globl _InterruptEntryStubEnd\r
-_InterruptEntryStubEnd:\r
ret\r
\r
-.globl _CommonIdtEntry\r
-_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
+.globl ASM_PFX(CommonIdtEntry)\r
+##\r
+## At this point, the stub has saved the current application stack esp into AppRsp\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
+## [16 bytes alignment, do not care it]\r
+## SS from interrupted task\r
+## RSP from interrupted task\r
+## rflags from interrupted task\r
+## CS from interrupted task\r
+## RIP from interrupted task\r
+## Error code <-------------------- Only present for some exeption types\r
+##\r
+## Vector Number <----------------- pushed in our IDT Entry\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
+## UINT64 ExceptionData;\r
+## FX_SAVE_STATE_X64 FxSaveState;\r
+## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+## UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;\r
+## UINT64 RFlags;\r
+## UINT64 Ldtr, Tr;\r
+## UINT64 Gdtr[2], Idtr[2];\r
+## UINT64 Rip;\r
+## UINT64 Gs, Fs, Es, Ds, Cs, Ss;\r
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+## } SYSTEM_CONTEXT_X64; // 64\r
+ASM_PFX(CommonIdtEntry):\r
+\r
ret\r
\r
-PhonyIretd:\r
- iret\r
+## NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp\r
+ push rax\r
+ mov rax, qword ptr [rsp][8] # save vector number\r
+ mov ASM_PFX(ExceptionNumber), rax # save vector number\r
+ pop rax\r
+ add rsp, 8 # pop vector number\r
+ mov ASM_PFX(AppRsp), rsp # save stack top\r
+ mov rsp, offset DebugStackBegin # switch to debugger stack\r
+ sub rsp, 8 # leave space for vector number\r
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+ push r15\r
+ push r14\r
+ push r13\r
+ push r12\r
+ push r11\r
+ push r10\r
+ push r9\r
+ push r8\r
+ push rax\r
+ push rcx\r
+ push rdx\r
+ push rbx\r
+ push rsp\r
+ push rbp\r
+ push rsi\r
+ push rdi\r
+## Save interrupt state rflags register...\r
+ pushfq\r
+ pop rax\r
+ mov qword ptr ASM_PFX(Rflags), rax\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
+ cmp dword ptr ASM_PFX(ExceptionNumber), 0\r
+ jz ExtraPushOne\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 10\r
+ jz ExtraPushOne\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 11\r
+ jz ExtraPushOne\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 12\r
+ jz ExtraPushOne\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 13\r
+ jz ExtraPushOne\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 14\r
+ jz ExtraPushOne\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 17\r
+ jz ExtraPushOne\r
+ mov dword ptr ASM_PFX(ExtraPush), 0\r
+ mov dword ptr ASM_PFX(ExceptData), 0\r
+ jmp ExtraPushDone\r
+ExtraPushOne:\r
+ mov dword ptr ASM_PFX(ExtraPush), 1\r
+\r
+## If there's some extra data, save it also, and modify the saved AppRsp to effectively\r
+## pop this value off the application's stack.\r
+ mov rax, ASM_PFX(AppRsp)\r
+ mov rbx, [rax]\r
+ mov ASM_PFX(ExceptData), rbx\r
+ add rax, 8\r
+ mov ASM_PFX(AppRsp), rax\r
+\r
+ExtraPushDone:\r
+\r
+## The "push" above pushed the debug stack rsp. Since what we're actually doing\r
+## is building the context record on the debug stack, we need to save the pushed\r
+## debug RSP, and replace it with the application's last stack entry...\r
+ mov rax, [rsp + 24]\r
+ mov ASM_PFX(DebugRsp), rax\r
+ mov rax, ASM_PFX(AppRsp)\r
+ add rax, 40\r
+ # application stack has ss, rsp, rflags, cs, & rip, so\r
+ # last actual application stack entry is\r
+ # 40 bytes into the application stack.\r
+ mov [rsp + 24], rax\r
+## continue building context record\r
+## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero\r
+ mov rax, ss\r
+ push rax\r
+ # CS from application is one entry back in application stack\r
+ mov rax, ASM_PFX(AppRsp)\r
+ movzx rax, word ptr [rax + 8]\r
+ push rax\r
+\r
+ mov rax, ds\r
+ push rax\r
+ mov rax, es\r
+ push rax\r
+ mov rax, fs\r
+ push rax\r
+ mov rax, gs\r
+ push rax\r
+## UINT64 Rip;\r
+ # Rip from application is on top of application stack\r
+ mov rax, ASM_PFX(AppRsp)\r
+ push qword ptr [rax]\r
+## UINT64 Gdtr[2], Idtr[2];\r
+ push 0\r
+ push 0\r
+ sidt qword ptr [rsp]\r
+ push 0\r
+ push 0\r
+ sgdt qword ptr [rsp]\r
+\r
+## UINT64 Ldtr, Tr;\r
+ xor rax, rax\r
+ str ax\r
+ push rax\r
+ sldt ax\r
+ push rax\r
+\r
+## UINT64 RFlags;\r
+## Rflags from application is two entries back in application stack\r
+ mov rax, ASM_PFX(AppRsp)\r
+ push qword ptr [rax + 16]\r
+## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+## insure FXSAVE/FXRSTOR is enabled in CR4...\r
+## ... while we're at it, make sure DE is also enabled...\r
+ mov rax, cr8\r
+ push rax\r
+ mov rax, cr4\r
+ or rax, 0x208\r
+ mov cr4, rax\r
+ push rax\r
+ mov rax, cr3\r
+ push rax\r
+ mov rax, cr2\r
+ push rax\r
+ push 0\r
+ mov rax, cr0\r
+ push rax\r
+## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ mov rax, dr7\r
+ push rax\r
+## clear Dr7 while executing debugger itself\r
+ xor rax, rax\r
+ mov dr7, rax\r
+\r
+ mov rax, dr6\r
+ push rax\r
+## insure all status bits in dr6 are clear...\r
+ xor rax, rax\r
+ mov dr6, rax\r
+\r
+ mov rax, dr3\r
+ push rax\r
+ mov rax, dr2\r
+ push rax\r
+ mov rax, dr1\r
+ push rax\r
+ mov rax, dr0\r
+ push rax\r
+\r
+## FX_SAVE_STATE_X64 FxSaveState;\r
+ sub rsp, 512\r
+ mov rdi, rsp\r
+ # IMPORTANT!! The debug stack has been carefully constructed to\r
+ # insure that rsp and rdi are 16 byte aligned when we get here.\r
+ # They MUST be. If they are not, a GP fault will occur.\r
+ # FXSTOR_RDI\r
+ .byte 0x0f\r
+ .byte 0xae\r
+ .byte 0x07\r
+\r
+## UINT64 ExceptionData;\r
+ mov rax, ASM_PFX(ExceptData)\r
+ push rax\r
+# call to C code which will in turn call registered handler\r
+# pass in the vector number\r
+ mov rdx, rsp\r
+ mov rcx, ASM_PFX(ExceptionNumber)\r
+ sub rsp, 40\r
+ call ASM_PFX(InterruptDistrubutionHub)\r
+ add rsp, 40\r
+# restore context...\r
+## UINT64 ExceptionData;\r
+ add rsp, 8\r
+## FX_SAVE_STATE_X64 FxSaveState;\r
+ mov rsi, rsp\r
+ # FXRSTOR_RSI\r
+ .byte 0x0f\r
+ .byte 0xae\r
+ .byte 0x0e\r
+ add rsp, 512\r
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ pop rax\r
+ mov dr0, rax\r
+ pop rax\r
+ mov dr1, rax\r
+ pop rax\r
+ mov dr2, rax\r
+ pop rax\r
+ mov dr3, rax\r
+## skip restore of dr6. We cleared dr6 during the context save.\r
+ add rsp, 8\r
+ pop rax\r
+ mov dr7, rax\r
+## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+ pop rax\r
+ mov cr0, rax\r
+ add rsp, 8\r
+ pop rax\r
+ mov cr2, rax\r
+ pop rax\r
+ mov cr3, rax\r
+ pop rax\r
+ mov cr4, rax\r
+ pop rax\r
+ mov cr8, rax\r
+## UINT64 RFlags;\r
+ mov rax, ASM_PFX(AppRsp)\r
+ pop qword ptr [rax + 16]\r
+## UINT64 Ldtr, Tr;\r
+## UINT64 Gdtr[2], Idtr[2];\r
+## Best not let anyone mess with these particular registers...\r
+ add rsp, 48\r
+## UINT64 Rip;\r
+ pop qword ptr [rax]\r
+\r
+## UINT64 Gs, Fs, Es, Ds, Cs, Ss;\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 rax\r
+ # mov gs, rax\r
+ pop rax\r
+ # mov fs, rax\r
+ pop rax\r
+ mov es, rax\r
+ pop rax\r
+ mov ds, rax\r
+ mov rax, ASM_PFX(AppRsp)\r
+ pop qword ptr [rax + 8]\r
+ pop rax\r
+ mov ss, rax\r
+## The next stuff to restore is the general purpose registers that were pushed\r
+## using the "push" instruction.\r
+##\r
+## The value of RSP as stored in the context record is the application RSP\r
+## including the 5 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 rbx, [rsp + 24] # move the potentially modified AppRsp into rbx\r
+ mov rax, ASM_PFX(AppRsp)\r
+ add rax, 40\r
+ cmp rbx, rax\r
+ je NoAppStackMove\r
+\r
+ mov rax, ASM_PFX(AppRsp)\r
+ mov rcx, [rax] # RIP\r
+ mov [rbx], rcx\r
+\r
+ mov rcx, [rax + 8] # CS\r
+ mov [rbx + 8], rcx\r
+\r
+ mov rcx, [rax + 16] # RFLAGS\r
+ mov [rbx + 16], rcx\r
+\r
+ mov rcx, [rax + 24] # RSP\r
+ mov [rbx + 24], rcx\r
+\r
+ mov rcx, [rax + 32] # SS\r
+ mov [rbx + 32], rcx\r
+\r
+ mov rax, rbx # modify the saved AppRsp to the new AppRsp\r
+ mov ASM_PFX(AppRsp), rax\r
+NoAppStackMove:\r
+ mov rax, ASM_PFX(DebugRsp) # restore the DebugRsp on the debug stack\r
+ # so our "pop" will not cause a stack switch\r
+ mov [rsp + 24], rax\r
+\r
+ cmp dword ptr ASM_PFX(ExceptionNumber), 0x068\r
+ jne NoChain\r
+\r
+Chain:\r
+\r
+## Restore rflags so when we chain, the flags will be exactly as if we were never here.\r
+## We gin up the stack to do an iretq so we can get ALL the flags.\r
+ mov rax, ASM_PFX(AppRsp)\r
+ mov rbx, [rax + 40]\r
+ push rbx\r
+ mov rax, ss\r
+ push rax\r
+ mov rax, rsp\r
+ add rax, 16\r
+ push rax\r
+ mov rax, ASM_PFX(AppRsp)\r
+ mov rbx, [rax + 16]\r
+ and rbx, NOT 0x300 # special handling for IF and TF\r
+ push rbx\r
+ mov rax, cs\r
+ push rax\r
+ mov rax, offset PhonyIretq\r
+ push rax\r
+ iretq\r
+PhonyIretq:\r
+\r
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+ pop rdi\r
+ pop rsi\r
+ pop rbp\r
+ pop rsp\r
+ pop rbx\r
+ pop rdx\r
+ pop rcx\r
+ pop rax\r
+ pop r8\r
+ pop r9\r
+ pop r10\r
+ pop r11\r
+ pop r12\r
+ pop r13\r
+ pop r14\r
+ pop r15\r
+\r
+## Switch back to application stack\r
+ mov rsp, ASM_PFX(AppRsp)\r
+## Jump to original handler\r
+ jmp ASM_PFX(OrigVector)\r
+NoChain:\r
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;\r
+ pop rdi\r
+ pop rsi\r
+ pop rbp\r
+ pop rsp\r
+ pop rbx\r
+ pop rdx\r
+ pop rcx\r
+ pop rax\r
+ pop r8\r
+ pop r9\r
+ pop r10\r
+ pop r11\r
+ pop r12\r
+ pop r13\r
+ pop r14\r
+ pop r15\r
+\r
+## Switch back to application stack\r
+ mov rsp, ASM_PFX(AppRsp)\r
+\r
+## We're outa here...\r
+ iret\r