AsmFuncs.S revision 4fd606d1f5abe38e1f42c38de1d2e895166bd0f4
///**@file
// Low leve x64 specific debug support functions.
//
// Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
// Portions copyright (c) 2008 - 2009, Apple Inc. 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
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
//**/
.data
.long 0x11111111 # ?
.long 0x22222222 # ?
.long 0x33333333 # ?
.long 0x44444444 # ?
.long 0x55555555 # ?
.long 0x66666666 # ?
// The declarations below define the memory region that will be used for the debug stack.
// The context record will be built by pushing register values onto this stack.
// It is imparitive that alignment be carefully managed, since the FXSTOR and
// FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
//
// The stub will switch stacks from the application stack to the debuger stack
// and pushes the exception number.
//
// Then we building the context record on the stack. Since the stack grows down,
// we push the fields of the context record from the back to the front. There
// are 336 bytes of stack used prior allocating the 512 bytes of stack to be
// used as the memory buffer for the fxstor instruction. Therefore address of
// the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which
// must be 16 byte aligned.
//
// We carefully locate the stack to make this happen.
//
// For reference, the context structure looks like this:
// struct {
// UINT64 ExceptionData;
// FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned
// UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
// UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
// UINT64 RFlags;
// UINT64 Ldtr, Tr;
// UINT64 Gdtr[2], Idtr[2];
// UINT64 Rip;
// UINT64 Gs, Fs, Es, Ds, Cs, Ss;
// UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
// UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
// } SYSTEM_CONTEXT_X64; // 64 bit system context record
.p2align 4
DebugStackEnd : .ascii "DbgStkEnd >>>>>>" # 16 byte long string - must be 16 bytes to preserve alignment
#
ASM_PFX(ExceptionNumber): .long 0x77777777 # first entry will be the vector number pushed by the stub
.long 0x77777777 # ?
.text
//------------------------------------------------------------------------------
// BOOLEAN
// FxStorSupport (
// void
// )
//
// Abstract: Returns TRUE if FxStor instructions are supported
//
//
// cpuid corrupts rbx which must be preserved per the C calling convention
//
//------------------------------------------------------------------------------
// void
// Vect2Desc (
// IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx
// void (*Vector) (void) // rdx
// )
//
// Abstract: Encodes an IDT descriptor with the given physical address
//
//------------------------------------------------------------------------------
// InterruptEntryStub
//
// Abstract: This code is not a function, but is a small piece of code that is
// copied and fixed up once for each IDT entry that is hooked.
//
//------------------------------------------------------------------------------
// CommonIdtEntry
//
// Abstract: This code is not a function, but is the common part for all IDT
// vectors.
//
//
// At this point, the stub has saved the current application stack esp into AppRsp
// and switched stacks to the debug stack, where it pushed the vector number
//
// The application stack looks like this:
//
// ...
// (last application stack entry)
// [16 bytes alignment, do not care it]
// SS from interrupted task
// RSP from interrupted task
// rflags from interrupted task
// CS from interrupted task
// RIP from interrupted task
// Error code <-------------------- Only present for some exeption types
//
// Vector Number <----------------- pushed in our IDT Entry
//
// 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 {
// UINT64 ExceptionData;
// FX_SAVE_STATE_X64 FxSaveState;
// UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
// UINT64 Cr0, Cr2, Cr3, Cr4, Cr8;
// UINT64 RFlags;
// UINT64 Ldtr, Tr;
// UINT64 Gdtr[2], Idtr[2];
// UINT64 Rip;
// UINT64 Gs, Fs, Es, Ds, Cs, Ss;
// UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
// UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
// } SYSTEM_CONTEXT_X64; // 64
// NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp
// UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
// UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
// Save interrupt state rflags register...
// 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.
// If there's some extra data, save it also, and modify the saved AppRsp to effectively
// pop this value off the application's stack.
// The "push" above pushed the debug stack rsp. Since what we're actually doing
// is building the context record on the debug stack, we need to save the pushed
// debug RSP, and replace it with the application's last stack entry...
// continue building context record
// UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
// UINT64 Rip;
// UINT64 Gdtr[2], Idtr[2];
push $0
push $0
push $0
push $0
// UINT64 Ldtr, Tr;
// UINT64 RFlags;
// Rflags from application is two entries back in application stack
// UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
// ... while we're at it, make sure DE is also enabled...
push $0
// UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
// clear Dr7 while executing debugger itself
// insure all status bits in dr6 are clear...
// FX_SAVE_STATE_X64 FxSaveState;
// UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
// UINT64 ExceptionData;
// call to C code which will in turn call registered handler
// pass in the vector number
// restore context...
// UINT64 ExceptionData;
// FX_SAVE_STATE_X64 FxSaveState;
// UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
// skip restore of dr6. We cleared dr6 during the context save.
// UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
// UINT64 RFlags;
// UINT64 Ldtr, Tr;
// UINT64 Gdtr[2], Idtr[2];
// Best not let anyone mess with these particular registers...
// UINT64 Rip;
// UINT64 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.
//
##
// Restore rflags so when we chain, the flags will be exactly as if we were never here.
// We gin up the stack to do an iretq so we can get ALL the flags.
// UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
// UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
// Switch back to application stack
// Jump to original handler
// UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
// UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
// Switch back to application stack
// We're outa here...