singrdk/base/Kernel/Native/halkd.cpp

3002 lines
98 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// halkd.cpp: runtime support for debugging
//
// For more information see:
// \nt\base\ntos\kd64
// \nt\base\boot\kdcom
// \nt\base\boot\kd1394
// \nt\base\boot\kdusb2
// \nt\sdktools\debuggers\ntsd64
//
#include "hal.h"
#include "halkd.h"
extern "C" void * __cdecl memcpy(void *, const void *, size_t);
extern "C" void * __cdecl memset(void *, int, size_t);
//
// Debugger Debugging
//
#define KDDBG if (0) kdprintf
#define KDDBG2 if (0) kdprintf
#if defined(_IA64_)
#define SIGN_EXTEND_PTR(p) p
#else
#define SIGN_EXTEND_PTR(p) ((ULONG_PTR)(LONG_PTR)(LONG)(p))
#endif
#define KeProcessorLevel 15
//
// Globals
//
extern const Struct_Microsoft_Singularity_BootInfo *g_pBootInfo;
static Struct_Microsoft_Singularity_X86_IDTP g_idt;
BOOL KdDebuggerNotPresent = FALSE;
#define KDP_MESSAGE_BUFFER_SIZE 4096
static CHAR KdpMessageBuffer[KDP_MESSAGE_BUFFER_SIZE];
static BOOL KdpContextSent;
static KPROCESSOR_STATE KdpProcessorState[MAX_CPU];
static KD_CONTEXT KdpContext;
static int KeNumberProcessors = 1;
static UINT16 KdpSpinBase = 0x2f00;
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
BREAKPOINT_ENTRY KdpBreakpointTable[BREAKPOINT_TABLE_SIZE] = {0};
//
// KdpRetryCount controls the number of retries before we give
// up and assume kernel debugger is not present.
// KdpNumberRetries is the number of retries left. Initially,
// it is set to 5 such that booting NT without debugger won't be
// delayed to long.
//
ULONG KdCompNumberRetries = 5;
ULONG KdCompRetryCount = 5;
ULONG KdPacketId = 0;
void (*KdSendPacket)(ULONG PacketType,
IN PSTRING MessageHeader,
IN PSTRING MessageData OPTIONAL,
IN OUT PKD_CONTEXT KdContext) = NULL;
KDP_STATUS (*KdReceivePacket)(IN ULONG PacketType,
OUT PSTRING MessageHeader,
OUT PSTRING MessageData,
OUT PULONG DataLength,
IN OUT PKD_CONTEXT KdContext) = NULL;
bool (*KdPollBreakIn)() = NULL;
//
// Static data - these are walked by the kernel debugger
//
//PsLoadedModuleList ===========================================================
struct KLDR_DATA_TABLE_ENTRY_WITH_NAME : KLDR_DATA_TABLE_ENTRY
{
WCHAR wzName[32];
};
static KLDR_DATA_TABLE_ENTRY_WITH_NAME KdModuleKernelEntry[128];
static ULONG KdModuleKernelUsed = 0;
static LIST_ENTRY PsLoadedModuleList;
static PMINIDUMP_MODULE_LIST KdMinidumpModuleList = NULL;
// KdVersionBlock =============================================================
static DBGKD_GET_VERSION64 KdVersionBlock = {
DBGKD_MAJOR_SINGULARITY << 8, // MajorVersion ... this one sort of works
0, // Minor
DBGKD_64BIT_PROTOCOL_VERSION2, // Protocol
DBGKD_VERS_FLAG_NOMM, //DBGKD_VERS_FLAG_DATA, // Flags
IMAGE_FILE_MACHINE_I386, // Machine Type
PACKET_TYPE_MAX, // Max packet
DbgKdMaximumStateChange - DbgKdMinimumStateChange, // MaxStateChange
DbgKdSetContextApi /*DbgKdMaximumManipulate*/ - DbgKdMinimumManipulate, // MaxManipulate we support
0, // Simulation
0, // Unused
0, // KernBase
(ULONG64)&PsLoadedModuleList, // PsLoadedModuleList
0 // DebuggerDataList
};
// ========================================================================
// Forward declarations
static void KdpLock(void);
static void KdpUnlock(void);
static void KdpEnter(void);
static void KdpLeave(void);
static void KdpFakeOutPsLoadedModuleList(void);
static KCONTINUE_STATUS
KdpSendWaitContinue(
IN ULONG OutPacketType,
IN PSTRING OutMessageHeader,
IN PSTRING OutMessageData OPTIONAL,
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
);
static void LoadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context);
static void UnloadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context);
extern int printf(const char *pszFmt, ...);
///////////////////////////////////////// Debugger Unique Interrupts Routines.
//
// NB: Without these, we share routines with the mainline code and we get
// caught in a loop when the debugger inserts a break after the pushfd when
// someone tries to single step through Processor:g_DisableInterrupts!
//
static __declspec(naked) bool KdpDisableInterrupts()
{
__asm {
pushfd;
pop eax;
test eax, Struct_Microsoft_Singularity_X86_EFlags_IF;
setnz al;
nop; // required so that the linker doesn't combine with g_Disable
cli;
ret;
}
}
static __declspec(naked) void KdpRestoreInterrupts(bool enabled)
{
__asm {
nop;
test cl, cl;
je done;
nop; // required so that the linker doesn't combine with g_Restore
sti;
done:
ret;
}
}
//////////////////////////////////////////////////////////////////////////////
//
static volatile INT32 KdpInDebugger = 0;
static volatile bool KdpInDebuggerIntEnabled = FALSE;
#define MAXIMUM_RETRIES 20
static void KdpNulSendPacket(ULONG PacketType,
IN PSTRING MessageHeader,
IN PSTRING MessageData OPTIONAL,
IN OUT PKD_CONTEXT KdContext)
{
}
static KDP_STATUS KdpNulReceivePacket(IN ULONG PacketType,
OUT PSTRING MessageHeader,
OUT PSTRING MessageData,
OUT PULONG DataLength,
IN OUT PKD_CONTEXT KdContext)
{
return KDP_PACKET_TIMEOUT;
}
static bool KdpNulPollBreakIn()
{
return false;
}
void KdInitialize(Struct_Microsoft_Singularity_BootInfo *bi)
{
KdpLock();
if (KdpComInit(bi)) {
KdpSpinBase = 0x2f00;
KdSendPacket = KdpComSendPacket;
KdReceivePacket = KdpComReceivePacket;
KdPollBreakIn = KdpComPollBreakIn;
kdprintf("Serial Port (bi->DebugBasePort=%x).\n", bi->DebugBasePort);
}
else if (Kdp1394Init(bi)) {
KdpSpinBase = 0x4f00;
KdSendPacket = Kdp1394SendPacket;
KdReceivePacket = Kdp1394ReceivePacket;
KdPollBreakIn = Kdp1394PollBreakIn;
kdprintf("1394 Port (bi->DebugBasePort=%x).\n", bi->DebugBasePort);
}
else {
kdprintf("No debugger.\n");
KdSendPacket = KdpNulSendPacket;
KdReceivePacket = KdpNulReceivePacket;
KdPollBreakIn = KdpNulPollBreakIn;
KdDebuggerNotPresent = true;
}
// Retries are set to this after boot
KdpContext.KdpDefaultRetries = MAXIMUM_RETRIES;
KdpUnlock();
KdpFakeOutPsLoadedModuleList();
}
static void KdpLock()
{
for (;;) {
bool enabled = KdpDisableInterrupts();
if (InterlockedCompareExchange(&KdpInDebugger, 1, 0) == 0) {
KdpInDebuggerIntEnabled = enabled;
return;
}
KdpRestoreInterrupts(enabled);
__asm pause
}
}
static void KdpUnlock()
{
KdpInDebugger = 0;
KdpRestoreInterrupts(KdpInDebuggerIntEnabled);
}
static void KdpEnter()
{
if (KeNumberProcessors > 1) {
Class_Microsoft_Singularity_MpExecution::g_FreezeAllProcessors();
}
}
static void KdpLeave()
{
if (KeNumberProcessors > 1) {
Class_Microsoft_Singularity_MpExecution::g_ThawAllProcessors();
}
}
//////////////////////////////////////////////////////////////////////////////
//
extern int strformat(void (*pfOutput)(void *pContext, char c), void *pContext,
const char * pszFmt, va_list args);
#define KD_LEFT 0
#define KD_HEIGHT 46
static UINT16 kdcurs = KD_LEFT;
static UINT16 kdattr = 0x2f00;
static void koutput(void *pContext, char c)
{
//
// Update cursor position
//
if ((kdcurs % 80) < KD_LEFT) {
kdcurs += KD_LEFT - (kdcurs % 80);
}
if (kdcurs >= KD_HEIGHT * 80) {
for (UINT16 i = 0; i < KD_HEIGHT - 1; i++) {
for (UINT16 j = KD_LEFT; j < 80; j++) {
((UINT16 *)0xb8000)[i*80+j] = ((UINT16 *)0xb8000)[i*80+80+j];
}
}
for (UINT16 j = KD_LEFT; j < 80; j++) {
((UINT16 *)0xb8000)[(KD_HEIGHT-1)*80+j] = kdattr | ' ';
}
kdcurs = kdcurs - 80;
}
//
// Output character
//
if (c >= ' ' && c <= '~') {
((UINT16 *)0xb8000)[kdcurs++] = kdattr | c;
}
else if (c == '\t') {
kdcurs += 8 - (kdcurs % 8);
}
else if (c == '\n') {
while ((kdcurs % 80) != 0) {
((UINT16 *)0xb8000)[kdcurs++] = kdattr | ' ';
}
}
else if (c == '\r') {
kdcurs -= (kdcurs % 80);
}
else if (c == '\f') {
kdcurs = 0;
}
}
void kdprints(const char * pszFmt)
{
while (*pszFmt) {
koutput(NULL, *pszFmt++);
}
}
void kdprintf(const char * pszFmt, ...)
{
va_list args;
va_start(args, pszFmt);
strformat(koutput, NULL, pszFmt, args);
va_end(args);
}
void KdpSpin()
{
static UINT8 state = 0;
*((UINT16 *)0xb809e) = KdpSpinBase + ("+-|*" [state++ & 0x3]);
}
//////////////////////////////////////////////////////////////////////////////
//
ULONG KdpComputeChecksum(IN PCHAR Buffer, IN ULONG Length)
{
// Compute the checksum for the string passed in.
ULONG Checksum = 0;
while (Length > 0) {
Checksum = Checksum + (ULONG)*(PUCHAR)Buffer++;
Length--;
}
return(Checksum);
} // KdpComputeChecksum
//////////////////////////////////////////////////////////////////////////////
//
static
VOID KdSingularityToWindbgContext(IN CONST Struct_Microsoft_Singularity_X86_ThreadContext *singularity,
OUT CONTEXT *windbg)
{
RtlZeroMemory(windbg, sizeof(*windbg));
windbg->ContextFlags = (CONTEXT_CONTROL |
CONTEXT_INTEGER |
CONTEXT_SEGMENTS |
CONTEXT_DEBUG_REGISTERS);
// CONTEXT_FULL;
windbg->Eax = singularity->eax;
windbg->Ebx = singularity->ebx;
windbg->Ecx = singularity->ecx;
windbg->Edx = singularity->edx;
windbg->Esp = singularity->esp;
windbg->Ebp = singularity->ebp;
windbg->Esi = singularity->esi;
windbg->Edi = singularity->edi;
windbg->Eip = singularity->eip;
windbg->EFlags = singularity->efl;
// CONTEXT_FLOATING_POINT
if (singularity->regs) {
windbg->ContextFlags |= CONTEXT_FLOATING_POINT;
#if 0
PUCHAR pmmx = (PUCHAR)&singularity->mmx;
kdprintf(" MMX=%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
pmmx[0], pmmx[1], pmmx[2], pmmx[3],
pmmx[4], pmmx[5], pmmx[6], pmmx[7],
pmmx[8], pmmx[9], pmmx[10], pmmx[11],
pmmx[12], pmmx[13], pmmx[14], pmmx[15]);
kdprintf(" MMX=%04x %04x %02x %03x %04x:%08x %04x:%08x\n",
singularity->mmx.fcw,
singularity->mmx.fsw,
singularity->mmx.ftw,
singularity->mmx.fop,
singularity->mmx.cs,
singularity->mmx.eip,
singularity->mmx.ds,
singularity->mmx.dp);
#endif
windbg->FloatSave.ControlWord = singularity->mmx.fcw;
windbg->FloatSave.StatusWord = singularity->mmx.fsw;
windbg->FloatSave.TagWord = singularity->mmx.ftw;
windbg->FloatSave.ErrorOffset = singularity->mmx.eip;
windbg->FloatSave.ErrorSelector = singularity->mmx.cs;
windbg->FloatSave.DataOffset = singularity->mmx.dp;
windbg->FloatSave.DataSelector = singularity->mmx.ds;
memcpy((uint8*)windbg->FloatSave.RegisterArea+0, &singularity->mmx.st0, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+10, &singularity->mmx.st1, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+20, &singularity->mmx.st2, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+30, &singularity->mmx.st3, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+40, &singularity->mmx.st4, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+50, &singularity->mmx.st5, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+60, &singularity->mmx.st6, 10);
memcpy((uint8*)windbg->FloatSave.RegisterArea+70, &singularity->mmx.st7, 10);
}
// CONTEXT_EXTENDED_REGISTERS
if (singularity->regs & 1) {
windbg->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
memcpy(windbg->ExtendedRegisters, &singularity->mmx, 512);
}
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
windbg->Dr0 = singularity->dr0;
windbg->Dr1 = singularity->dr1;
windbg->Dr2 = singularity->dr2;
windbg->Dr3 = singularity->dr3;
windbg->Dr6 = singularity->dr6;
windbg->Dr7 = singularity->dr7;
#if 0
__asm {
mov ebx, windbg;
mov eax, dr0;
mov [ebx]CONTEXT.Dr0, eax;
mov eax, dr1;
mov [ebx]CONTEXT.Dr1, eax;
mov eax, dr2;
mov [ebx]CONTEXT.Dr2, eax;
mov eax, dr3;
mov [ebx]CONTEXT.Dr3, eax;
mov eax, dr6;
mov [ebx]CONTEXT.Dr6, eax;
mov eax, dr7;
mov [ebx]CONTEXT.Dr7, eax;
}
#endif
#if 1
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_SEGMENTS.
//
__asm {
mov ebx, windbg;
xor eax, eax;
mov ax, gs;
mov [ebx]CONTEXT.SegGs, eax;
mov ax, fs;
mov [ebx]CONTEXT.SegFs, eax;
mov ax, es;
mov [ebx]CONTEXT.SegEs, eax;
mov ax, ds;
mov [ebx]CONTEXT.SegDs, eax;
}
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_CONTROL.
//
__asm {
mov ebx, windbg;
xor eax, eax;
mov ax, ss;
mov [ebx]CONTEXT.SegSs, eax;
}
windbg->SegCs = singularity->cs0;
#endif
}
VOID KdWindbgToSingularityContext(IN CONST CONTEXT *windbg,
OUT Struct_Microsoft_Singularity_X86_ThreadContext *singularity)
{
singularity->eax = windbg->Eax;
singularity->ebx = windbg->Ebx;
singularity->ecx = windbg->Ecx;
singularity->edx = windbg->Edx;
singularity->esp = windbg->Esp;
singularity->ebp = windbg->Ebp;
singularity->esi = windbg->Esi;
singularity->edi = windbg->Edi;
singularity->eip = windbg->Eip;
singularity->efl = windbg->EFlags;
// CONTEXT_FLOATING_POINT
if (windbg->ContextFlags & CONTEXT_FLOATING_POINT) {
singularity->mmx.fcw = (uint16)windbg->FloatSave.ControlWord;
singularity->mmx.fsw = (uint16)windbg->FloatSave.StatusWord;
singularity->mmx.ftw = (uint16)windbg->FloatSave.TagWord;
singularity->mmx.cs = (uint16)windbg->FloatSave.ErrorSelector;
singularity->mmx.eip = windbg->FloatSave.ErrorOffset;
singularity->mmx.ds = (uint16)windbg->FloatSave.DataSelector;
singularity->mmx.dp = windbg->FloatSave.DataOffset;
memcpy(&singularity->mmx.st0, windbg->FloatSave.RegisterArea+0, 10);
memcpy(&singularity->mmx.st1, windbg->FloatSave.RegisterArea+10, 10);
memcpy(&singularity->mmx.st2, windbg->FloatSave.RegisterArea+20, 10);
memcpy(&singularity->mmx.st3, windbg->FloatSave.RegisterArea+30, 10);
memcpy(&singularity->mmx.st4, windbg->FloatSave.RegisterArea+40, 10);
memcpy(&singularity->mmx.st5, windbg->FloatSave.RegisterArea+50, 10);
memcpy(&singularity->mmx.st6, windbg->FloatSave.RegisterArea+60, 10);
memcpy(&singularity->mmx.st7, windbg->FloatSave.RegisterArea+70, 10);
}
// CONTEXT_EXTENDED_REGISTERS
if (windbg->ContextFlags & CONTEXT_EXTENDED_REGISTERS) {
memcpy(&singularity->mmx, windbg->ExtendedRegisters, 512);
}
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
if (windbg->ContextFlags & CONTEXT_DEBUG_REGISTERS) {
singularity->dr0 = windbg->Dr0;
singularity->dr1 = windbg->Dr1;
singularity->dr2 = windbg->Dr2;
singularity->dr3 = windbg->Dr3;
singularity->dr6 = windbg->Dr6;
singularity->dr7 = windbg->Dr7;
#if 0
__asm {
mov ebx, windbg;
mov eax, [ebx]CONTEXT.Dr0;
mov dr0, eax;
mov eax, [ebx]CONTEXT.Dr1;
mov dr1, eax;
mov eax, [ebx]CONTEXT.Dr2;
mov dr2, eax;
mov eax, [ebx]CONTEXT.Dr3;
mov dr3, eax;
mov eax, 0; //CONTEXT.Dr6 : DR6 is reset when changing BPTs.
mov dr6, eax;
mov eax, [ebx]CONTEXT.Dr7;
mov eax, dr7;
}
#endif
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Misc KD functions
//
NTSTATUS
KdpCopyMemoryChunks(
ULONG64 Address,
PVOID Buffer,
ULONG TotalSize,
ULONG ChunkSize,
ULONG Flags,
PULONG ActualSize OPTIONAL
)
// Routine Description:
// Copies memory to/from a buffer to/from a system address.
// The address can be physical or virtual.
// The buffer is assumed to be valid for the duration of this call.
//
// Arguments:
// Address - System address.
// Buffer - Buffer to read from or write to.
// TotalSize - Number of bytes to read/write.
// ChunkSize - Maximum single item transfer size, must
// be 1, 2, 4 or 8.
// 0 means choose a default.
// Flags - MMDBG_COPY flags for MmDbgCopyMemory.
// ActualSize - Number of bytes actually read/written.
//
// Return Value:
// NTSTATUS
{
ULONG Length;
ULONG CopyChunk;
// NTSTATUS Status;
#if defined(_IA64_)
ULONG64 AddressStart = Address;
#endif
if (ChunkSize > MMDBG_COPY_MAX_SIZE) {
ChunkSize = MMDBG_COPY_MAX_SIZE;
} else if (ChunkSize == 0) {
// Default to 4 byte chunks as that's
// what the previous code did.
ChunkSize = 4;
}
//
// MmDbgCopyMemory only copies a single aligned chunk at a
// time. It is Kd's responsibility to chunk up a larger
// request for individual copy requests. This gives Kd
// the flexibility to pick a chunk size and also frees
// Mm from having to worry about more than a page at a time.
// Additionally, it is important that we access memory with the
// largest size possible because we could be accessing
// memory-mapped I/O space.
//
Length = TotalSize;
CopyChunk = 1;
while (Length > 0) {
// Expand the chunk size as long as:
// We haven't hit the chunk limit.
// We have enough data left.
// The address is properly aligned.
while (CopyChunk < ChunkSize &&
(CopyChunk << 1) <= Length &&
(Address & ((CopyChunk << 1) - 1)) == 0) {
CopyChunk <<= 1;
}
// Shrink the chunk size to fit the available data.
while (CopyChunk > Length) {
CopyChunk >>= 1;
}
Address &= 0xffffffff;
if (Address < Struct_Microsoft_Singularity_BootInfo_PHYSICAL_DISABLED) {
break;
}
if (Address == 0) {
break;
}
#if PAGING
ULONG64 RawAddress = Address;
if (Flags & MMDBG_COPY_PHYSICAL) {
// Temporarily map the physical memory range.
// TODO: KernelMapPhysicalMemory tries to acquire a lock -- if
// this lock is not free, we may deadlock here.
// Also, remapping for every chunk is inefficient.
KDDBG("Physical address = 0x%x size = 0x%x\n", int(Address), int(CopyChunk));
Struct_Microsoft_Singularity_Memory_PhysicalAddress physical;
Struct_Microsoft_Singularity_Memory_PhysicalAddress::m__ctor(
&physical,
UIntPtr(Address));
Address = ULONG64(Class_Microsoft_Singularity_Memory_MemoryManager
::g_KernelMapPhysicalMemory(
physical,
UIntPtr(CopyChunk)));
KDDBG("Physical address 0x%x mapped to virtual address 0x%x\n", int(RawAddress), int(Address));
}
else {
if (Class_Microsoft_Singularity_Memory_MemoryManager::c_isInitialized
&& !Class_Microsoft_Singularity_Memory_VMManager::g_IsPageMapped(
Class_Microsoft_Singularity_Memory_MemoryManager::g_PageAlign(
UIntPtr(Address)))) {
break;
}
}
#endif
if (Flags & MMDBG_COPY_WRITE) {
memcpy((void*)Address, Buffer, CopyChunk);
} else {
memcpy(Buffer, (void*)Address, CopyChunk);
}
#if PAGING
if (Flags & MMDBG_COPY_PHYSICAL) {
KDDBG("Unmapping physical address 0x%x (virtual address 0x%x)\n", int(RawAddress), int(Address));
Class_Microsoft_Singularity_Memory_MemoryManager
::g_KernelUnmapPhysicalMemory(
UIntPtr(Address), UIntPtr(Address + CopyChunk));
KDDBG("Unmapped physical address 0x%x (virtual address 0x%x)\n", int(RawAddress), int(Address));
Address = RawAddress;
}
#endif
Address += CopyChunk;
Buffer = (PVOID)((PUCHAR)Buffer + CopyChunk);
Length -= CopyChunk;
}
if (ActualSize) {
*ActualSize = TotalSize - Length;
}
//
// Flush the instruction cache in case the write was into the instruction
// stream. Only do this when writing into the kernel address space,
// and if any bytes were actually written
//
if ((Flags & MMDBG_COPY_WRITE) && Length < TotalSize) {
#if defined(_IA64_)
//
// KeSweepCurrentIcacheRange requires a valid virtual address.
// It is used because KeSweepCurrentICache does not work until
// the HAL as been initialized.
//
if (Flags & MMDBG_COPY_PHYSICAL) {
KeSweepCurrentIcache();
}
else {
KeSweepCurrentIcacheRange((PVOID)AddressStart, TotalSize - Length);
}
#else
__asm wbinvd;
// KeSweepCurrentIcache();
#endif
}
return Length != 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
}
static
VOID
KdpSetCommonState(
IN ULONG NewState,
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context,
OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange
)
{
PCHAR PcMemory = (PCHAR)x86Context->eip;
ULONG InstrCount;
PUCHAR InstrStream;
WaitStateChange->NewState = NewState;
WaitStateChange->ProcessorLevel = KeProcessorLevel;
WaitStateChange->Processor = GetCurrentProcessorNumber();
WaitStateChange->NumberProcessors = KeNumberProcessors;
WaitStateChange->Thread = SIGN_EXTEND_PTR(x86Context->_thread);
WaitStateChange->ProgramCounter = SIGN_EXTEND_PTR(x86Context->eip);
RtlZeroMemory(&WaitStateChange->AnyControlReport,
sizeof(WaitStateChange->AnyControlReport));
//
// Copy instruction stream immediately following location of event.
//
InstrStream = WaitStateChange->ControlReport.InstructionStream;
KdpCopyFromPtr(InstrStream, PcMemory, DBGKD_MAXSTREAM, &InstrCount);
WaitStateChange->ControlReport.InstructionCount = (USHORT)InstrCount;
//
// Clear breakpoints in copied area.
// If there were any breakpoints cleared, recopy the instruction area
// without them.
//
// if (KdpDeleteBreakpointRange(PcMemory, PcMemory + InstrCount - 1)) {
// KdpCopyFromPtr(InstrStream, PcMemory, InstrCount, &InstrCount);
// }
}
VOID
KdpSetContextState(
IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// Fill in the Wait_State_Change message record.
//
// Arguments:
// WaitStateChange - Supplies pointer to record to fill in
// x86Context - Supplies a pointer to a context record.
//
// Return Value:
// None.
{
#if 0
PKPRCB Prcb;
//
// Special registers for the x86
//
Prcb = KeGetCurrentPrcb();
WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.KernelDr6;
WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.KernelDr7;
#endif
UINT32 _dr6;
UINT32 _dr7;
UINT16 _cs;
UINT16 _ds;
UINT16 _es;
UINT16 _fs;
__asm {
mov eax, dr6;
mov _dr6, eax;
mov eax, dr7;
mov _dr7, eax;
mov ax, cs;
mov _cs, ax;
mov ax, ds;
mov _ds, ax;
mov ax, es;
mov _es, ax;
mov ax, fs;
mov _fs, ax;
}
// I'm not sure we're handling dr6 right here.
KDDBG("KdpSetContextState dr6=%08x dr7=%08x cs=%04x/%04x\n",
_dr6, _dr7, _cs, _ds);
WaitStateChange->ControlReport.Dr6 = _dr6;
WaitStateChange->ControlReport.Dr7 = _dr7;
WaitStateChange->ControlReport.SegCs = _cs;
WaitStateChange->ControlReport.SegDs = _ds;
WaitStateChange->ControlReport.SegEs = _es;
WaitStateChange->ControlReport.SegFs = _fs;
WaitStateChange->ControlReport.EFlags = x86Context->efl;
WaitStateChange->ControlReport.ReportFlags = X86_REPORT_INCLUDES_SEGS;
#if !PAGING
// Let the debugger know so that it doesn't have to retrieve the CS descriptor.
WaitStateChange->ControlReport.ReportFlags |= X86_REPORT_STANDARD_CS;
#endif
}
ULONG
WcsToStr(WCHAR *pwcsSrc, ULONG Length, PCHAR pszDst)
{
for (ULONG n = 0; n < Length; n++) {
*pszDst++ = (char)*pwcsSrc++;
}
*pszDst++ = '\0';
return Length + 1;
}
bool
KdpReportLoadSymbolsStateChange(
IN WCHAR *PathName,
IN ULONG PathNameLength,
IN ULONG64 BaseOfDll,
IN ULONG ProcessId,
IN ULONG CheckSum,
IN ULONG SizeOfImage,
IN BOOLEAN UnloadSymbols,
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// This routine sends a load symbols state change packet to the kernel
// debugger and waits for a manipulate state message.
//
// Arguments:
// PathName - Supplies a pointer to the pathname of the image whose
// symbols are to be loaded.
// BaseOfDll - Supplies the base address where the image was loaded.
// ProcessId - Unique identifier for process that is using
// the symbols. -1 for system process.
// CheckSum - Checksum from image header.
// UnloadSymbol - TRUE if the symbols that were previously loaded for
// the named image are to be unloaded from the debugger.
//
// Return Value:
// A value of TRUE is returned if the exception is handled. Otherwise, a
// value of FALSE is returned.
{
// NB: \nt\sdktools\debuggers\ntsd64\event.cpp
// PathNameLength = 0, ProcessId = 0, BaseOfDll = -1 for reboot.
// PathNameLength = 0, ProcessId = 0, BaseOfDll = -2 for hibernate.
STRING MessageData;
STRING MessageHeader;
DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
KCONTINUE_STATUS Status;
KDDBG("KdpReportLoadSymbolsStateChange %p\n", x86Context);
do {
//
// Construct the wait state change message and message descriptor.
//
KdpSetCommonState(DbgKdLoadSymbolsStateChange, x86Context,
&WaitStateChange);
WaitStateChange.u.LoadSymbols.UnloadSymbols = UnloadSymbols;
WaitStateChange.u.LoadSymbols.BaseOfDll = BaseOfDll;
WaitStateChange.u.LoadSymbols.ProcessId = ProcessId;
WaitStateChange.u.LoadSymbols.CheckSum = CheckSum;
WaitStateChange.u.LoadSymbols.SizeOfImage = SizeOfImage;
if (PathName != NULL) {
WaitStateChange.u.LoadSymbols.PathNameLength =
WcsToStr(PathName, PathNameLength, KdpMessageBuffer);
}
else {
WaitStateChange.u.LoadSymbols.PathNameLength = 0;
}
MessageData.Buffer = KdpMessageBuffer;
MessageData.Length = (USHORT)WaitStateChange.u.LoadSymbols.PathNameLength;
KdpSetContextState(&WaitStateChange, x86Context);
MessageHeader.Length = sizeof(WaitStateChange);
MessageHeader.Buffer = (PCHAR)&WaitStateChange;
Status = KdpSendWaitContinue(
PACKET_TYPE_KD_STATE_CHANGE64,
&MessageHeader,
&MessageData,
x86Context
);
} while (Status == ContinueProcessorReselected) ;
return (Status == ContinueSuccess) ? true : false;
}
static
KCONTINUE_STATUS
KdpReportExceptionStateChange(
IN PEXCEPTION_RECORD64 ExceptionRecord,
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context,
IN BOOLEAN FirstChance
)
// Routine Description:
// This routine sends an exception state change packet to the kernel
// debugger and waits for a manipulate state message.
//
// Arguments:
// ExceptionRecord - Supplies a pointer to an exception record.
// x86Context - Supplies a pointer to a context record.
// FirstChance - Supplies a boolean value that determines whether this is
// the first or second chance for the exception.
//
// Return Value:
// A value of TRUE is returned if the exception is handled. Otherwise, a
// value of FALSE is returned.
{
STRING MessageData;
STRING MessageHeader;
DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
KCONTINUE_STATUS Status;
KDDBG("KdpReportExceptionStateChange %p\n", x86Context);
do {
//
// Construct the wait state change message and message descriptor.
//
KdpSetCommonState(DbgKdExceptionStateChange, x86Context,
&WaitStateChange);
WaitStateChange.u.Exception.ExceptionRecord = *ExceptionRecord;
WaitStateChange.u.Exception.FirstChance = FirstChance;
KdpSetContextState(&WaitStateChange, x86Context);
MessageHeader.Length = sizeof(WaitStateChange);
MessageHeader.Buffer = (PCHAR)&WaitStateChange;
MessageData.Length = 0;
//
// Send packet to the kernel debugger on the host machine,
// wait for answer.
//
Status = KdpSendWaitContinue(
PACKET_TYPE_KD_STATE_CHANGE64,
&MessageHeader,
&MessageData,
x86Context
);
} while (Status == ContinueProcessorReselected) ;
return Status;
}
static
VOID
KdpReadVirtualMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData
)
// Routine Description:
// This function is called in response to a read virtual memory 32-bit
// state manipulation message. Its function is to read virtual memory
// and return.
//
// Arguments:
// m - Supplies a pointer to the state manipulation message.
// AdditionalData - Supplies a pointer to a descriptor for the data to read.
// x86Context - Supplies a pointer to the current context.
//
// Return Value:
// None.
{
ULONG Length;
STRING MessageHeader;
//
// Trim the transfer count to fit in a single message.
//
Length = m->u.ReadMemory.TransferCount;
if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) {
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
}
//
// Move the data to the destination buffer.
//
if (m->u.ReadMemory.TargetBaseAddress >= 0x80000000) {
KDDBG(" Read out of range!\n");
for (UINT i = 0; i < Length; i++) {
AdditionalData->Buffer[i] = 0;
}
Length = 0;
}
else {
m->ReturnStatus =
KdpCopyMemoryChunks(m->u.ReadMemory.TargetBaseAddress,
AdditionalData->Buffer,
Length,
0,
MMDBG_COPY_UNSAFE,
&Length);
}
//
// Set the actual number of bytes read, initialize the message header,
// and send the reply packet to the host debugger.
//
AdditionalData->Length = (USHORT)Length;
m->u.ReadMemory.ActualBytesRead = Length;
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData,
&KdpContext);
return;
}
static
VOID
KdpWriteVirtualMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData
)
// Routine Description:
// This function is called in response of a write virtual memory 32-bit
// state manipulation message. Its function is to write virtual memory
// and return.
//
// Arguments:
// m - Supplies a pointer to the state manipulation message.
// AdditionalData - Supplies a pointer to a descriptor for the data to write.
// x86Context - Supplies a pointer to the current context.
//
// Return Value:
// None.
{
STRING MessageHeader;
//
// Move the data to the destination buffer.
//
m->ReturnStatus =
KdpCopyMemoryChunks(m->u.WriteMemory.TargetBaseAddress,
AdditionalData->Buffer,
AdditionalData->Length,
0,
MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE,
&m->u.WriteMemory.ActualBytesWritten);
//
// Set the actual number of bytes written, initialize the message header,
// and send the reply packet to the host debugger.
//
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
return;
}
static
VOID
KdpReadPhysicalMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData
)
// Routine Description:
// This function is called in response to a read physical memory 32-bit
// state manipulation message. Its function is to read physical memory
// and return.
//
// Arguments:
// m - Supplies a pointer to the state manipulation message.
// AdditionalData - Supplies a pointer to a descriptor for the data to read.
// x86Context - Supplies a pointer to the current context.
//
// Return Value:
// None.
{
ULONG Length;
STRING MessageHeader;
//
// Trim the transfer count to fit in a single message.
//
Length = m->u.ReadMemory.TransferCount;
if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) {
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
}
m->ReturnStatus =
KdpCopyMemoryChunks(m->u.ReadMemory.TargetBaseAddress,
AdditionalData->Buffer,
Length,
0,
MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL,
&Length);
//
// Set the actual number of bytes read, initialize the message header,
// and send the reply packet to the host debugger.
//
AdditionalData->Length = (USHORT)Length;
m->u.ReadMemory.ActualBytesRead = Length;
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData,
&KdpContext);
return;
}
static
VOID
KdpWritePhysicalMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData
)
// Routine Description:
// This function is called in response of a write physical memory 32-bit
// state manipulation message. Its function is to write physical memory
// and return.
//
// Arguments:
// m - Supplies a pointer to the state manipulation message.
// AdditionalData - Supplies a pointer to a descriptor for the data to write.
// x86Context - Supplies a pointer to the current context.
//
// Return Value:
// None.
{
STRING MessageHeader;
//
// Move the data to the destination buffer.
//
m->ReturnStatus =
KdpCopyMemoryChunks(m->u.WriteMemory.TargetBaseAddress,
AdditionalData->Buffer,
AdditionalData->Length,
0,
MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL,
&m->u.WriteMemory.ActualBytesWritten);
//
// Set the actual number of bytes written, initialize the message header,
// and send the reply packet to the host debugger.
//
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
return;
}
static
VOID
KdpReadMachineSpecificRegister(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// This function is called in response of a write physical memory 32-bit
// state manipulation message. Its function is to write physical memory
// and return.
//
// Arguments:
// m - Supplies a pointer to the state manipulation message.
// AdditionalData - Supplies a pointer to a descriptor for the data to write.
// x86Context - Supplies a pointer to the current context.
//
// Return Value:
// None.
{
STRING MessageHeader;
//
// Read the MSR
//
UINT32 msr = m->u.ReadWriteMsr.Msr;
UINT32 hi, lo;
__asm {
mov ecx, msr;
rdmsr;
mov hi, edx;
mov lo, eax;
}
m->u.ReadWriteMsr.DataValueHigh = hi;
m->u.ReadWriteMsr.DataValueLow = lo;
m->ReturnStatus = STATUS_SUCCESS;
//
// Set the actual number of bytes written, initialize the message header,
// and send the reply packet to the host debugger.
//
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
return;
}
static
VOID
KdpWriteMachineSpecificRegister(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// This function is called in response of a write physical memory 32-bit
// state manipulation message. Its function is to write physical memory
// and return.
//
// Arguments:
// m - Supplies a pointer to the state manipulation message.
// AdditionalData - Supplies a pointer to a descriptor for the data to write.
// x86Context - Supplies a pointer to the current context.
//
// Return Value:
// None.
{
STRING MessageHeader;
//
// Write the MSR
//
UINT32 msr = m->u.ReadWriteMsr.Msr;
UINT32 hi = m->u.ReadWriteMsr.DataValueHigh, lo = m->u.ReadWriteMsr.DataValueLow;
__asm {
mov ecx, msr;
mov edx, hi;
mov eax, lo;
wrmsr;
}
m->ReturnStatus = STATUS_SUCCESS;
//
// Set the actual number of bytes written, initialize the message header,
// and send the reply packet to the host debugger.
//
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
return;
}
static int wcslen(WCHAR *pwz)
{
int len = 0;
while (*pwz++) {
len++;
}
return len;
}
static WCHAR * trim(WCHAR *pwz)
{
WCHAR *pwzBeg = pwz;
for (; *pwz; pwz++) {
if (*pwz == '\\') {
pwzBeg = pwz + 1;
}
}
return pwzBeg;
}
static void KdpFakeOutPsLoadedModuleList()
{
UINT8* pbImage = (UINT8*)g_pBootInfo->DumpAddr32;
PMINIDUMP_HEADER pHeader = (PMINIDUMP_HEADER)(pbImage + 0);
#define VERBOSE 1
#if VERBOSE
printf("KdpFakeOutPsLoadedModuleList (%p):\n"
" BootInfo at %p MINIDUMP_HEADER at %p\n",
&PsLoadedModuleList, g_pBootInfo, pHeader);
#endif
// Need to build a data structure which looks like NT's PsLoadedModuleList
InitializeListHead(&PsLoadedModuleList);
PMINIDUMP_DIRECTORY pDir
= (PMINIDUMP_DIRECTORY)(pbImage + pHeader->StreamDirectoryRva);
for (UINT i = 0; i < pHeader->NumberOfStreams; i++) {
if (pDir[i].StreamType == ModuleListStream) {
KdMinidumpModuleList = (PMINIDUMP_MODULE_LIST)(pbImage + pDir[i].Location.Rva);
break;
}
}
if (KdMinidumpModuleList == NULL) {
#if VERBOSE
printf("Couldn't find module list.\n");
#endif
return;
}
KdVersionBlock.KernBase = (ULONG64)KdMinidumpModuleList->Modules[0].BaseOfImage;
#if VERBOSE
printf("MODULE_LIST: %d entries\n", KdMinidumpModuleList->NumberOfModules);
#endif
#if 1
// We manual include these modules to allow debugging very early in the boot cycle.
for (UINT m = 0; m < KdMinidumpModuleList->NumberOfModules &&
m < (sizeof(KdModuleKernelEntry)/sizeof(KdModuleKernelEntry[0])); m++) {
PMINIDUMP_MODULE pModule = &KdMinidumpModuleList->Modules[m];
KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry = &KdModuleKernelEntry[KdModuleKernelUsed++];
WCHAR *name = trim((WCHAR *)((pbImage + pModule->ModuleNameRva)+4));
USHORT nlen = (USHORT)2 * wcslen(name);
if (nlen > sizeof(pEntry->wzName)) {
nlen = sizeof(pEntry->wzName);
}
pEntry->DllBase = (PVOID *)pModule->BaseOfImage;
pEntry->CheckSum = pModule->CheckSum;
pEntry->TimeDateStamp = pModule->TimeDateStamp;
pEntry->LoadCount = 1;
pEntry->SizeOfImage = pModule->SizeOfImage;
memcpy(pEntry->wzName, name, nlen);
RtlInitUnicodeString(&pEntry->BaseDllName, pEntry->wzName, nlen);
RtlInitUnicodeString(&pEntry->FullDllName, pEntry->wzName, nlen); // Write back on self.
#if VERBOSE
printf("%4d: BaseOfImage %8lx SizeOfImage %8x ModuleNameRva %8x\n",
m,
pModule->BaseOfImage,
pModule->SizeOfImage,
pModule->ModuleNameRva);
printf(" ModuleName: %ls (%p)\n",
pEntry->BaseDllName.Buffer,
pEntry);
#endif
InsertTailList(&PsLoadedModuleList, &pEntry->InLoadOrderLinks);
}
#endif
}
VOID
KdpSysGetVersion(
PDBGKD_GET_VERSION64 Version
)
// Routine Description:
// This function returns to the caller a general information packet
// that contains useful information to a debugger. This packet is also
// used for a debugger to determine if the writebreakpointex and
// readbreakpointex APIs are available.
//
// Arguments:
// Version - Supplies the structure to fill in
//
// Return Value:
// None.
{
*Version = KdVersionBlock;
}
static
VOID
KdpGetVersion(
IN PDBGKD_MANIPULATE_STATE64 m
)
// Routine Description:
// This function returns to the caller a general information packet
// that contains useful information to a debugger. This packet is also
// used for a debugger to determine if the writebreakpointex and
// readbreakpointex APIs are available.
//
// Arguments:
// m - Supplies the state manipulation message.
//
// Return Value:
// None.
{
STRING messageHeader;
messageHeader.Length = sizeof(*m);
messageHeader.Buffer = (PCHAR)m;
KdpSysGetVersion(&m->u.GetVersion64);
//
// the usual stuff
//
m->ReturnStatus = STATUS_SUCCESS;
m->ApiNumber = DbgKdGetVersionApi;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&messageHeader,
NULL,
&KdpContext
);
return;
} // KdGetVersion
static inline ULONG min(ULONG a, ULONG b)
{
return a < b ? a : b;
}
static
VOID
KdpReadControlSpace(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN Struct_Microsoft_Singularity_X86_ThreadContext * x86Context
)
// Routine Description:
// This function is called in response of a read control space state
// manipulation message. Its function is to read implementation
// specific system data.
//
// Arguments:
// m - Supplies the state manipulation message.
// AdditionalData - Supplies any additional data for the message.
// Context - Supplies the current context.
//
// Return Value:
// None.
{
PDBGKD_READ_MEMORY64 a = &m->u.ReadMemory;
STRING MessageHeader;
ULONG Length;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
Length = min(min(a->TransferCount,
PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)),
sizeof(KPROCESSOR_STATE) - (ULONG)a->TargetBaseAddress);
if ((a->TargetBaseAddress + Length <= sizeof(KPROCESSOR_STATE)) &&
(m->Processor < (ULONG)KeNumberProcessors)) {
PKPROCESSOR_STATE ProcessorState = &KdpProcessorState[m->Processor];
if (a->TargetBaseAddress < sizeof(CONTEXT)) {
// Need to update the thread context information.
KdSingularityToWindbgContext(x86Context, &ProcessorState->ContextFrame);
}
if (a->TargetBaseAddress + Length > sizeof(CONTEXT)) {
// Need to update the processor context information.
// ASSERT(m->Processor == 0); // MP support broken.
ProcessorState->SpecialRegisters.Cr2 = x86Context->cr2;
ProcessorState->SpecialRegisters.Cr3 = (ULONG)x86Context->cr3;
KSPECIAL_REGISTERS *pksp = &ProcessorState->SpecialRegisters;
__asm {
mov ebx, pksp;
mov eax, cr0;
mov [ebx].Cr0, eax;
mov eax, cr3;
mov [ebx].Cr3, eax;
_emit 0x0f; // mov eax,cr4
_emit 0x20;
_emit 0xe0;
mov [ebx].Cr4, eax;
// XXX save TR should save segment regs as well.
str ax;
mov [ebx].Tr, ax;
#if 0
mov eax, dr0;
mov [ebx].KernelDr0, eax;
mov eax, dr1;
mov [ebx].KernelDr1, eax;
mov eax, dr2;
mov [ebx].KernelDr2, eax;
mov eax, dr3;
mov [ebx].KernelDr3, eax;
mov eax, dr6;
mov [ebx].KernelDr6, eax;
mov eax, dr7;
mov [ebx].KernelDr7, eax;
#endif
}
const Struct_Microsoft_Singularity_CpuInfo* cpuInfo = &g_pBootInfo->Cpu0 + m->Processor;
ProcessorState->SpecialRegisters.Gdtr.Pad = cpuInfo->GdtPtr.pad;
ProcessorState->SpecialRegisters.Gdtr.Limit = cpuInfo->GdtPtr.limit;
ProcessorState->SpecialRegisters.Gdtr.Base = cpuInfo->GdtPtr.addr;
ProcessorState->SpecialRegisters.Idtr.Pad = g_idt.pad;
ProcessorState->SpecialRegisters.Idtr.Limit = g_idt.limit;
ProcessorState->SpecialRegisters.Idtr.Base = g_idt.addr;
}
m->ReturnStatus = KdpCopyToPtr(AdditionalData->Buffer,
((uint8*)ProcessorState) + a->TargetBaseAddress,
Length,
&Length);
}
else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
Length = 0;
}
AdditionalData->Length = (USHORT)Length;
a->ActualBytesRead = Length;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData,
&KdpContext);
}
static
VOID
KdpWriteControlSpace(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN Struct_Microsoft_Singularity_X86_ThreadContext * x86Context
)
// Routine Description:
// This function is called in response of a write control space state
// manipulation message. Its function is to write implementation
// specific system data.
//
// Arguments:
// m - Supplies the state manipulation message.
// AdditionalData - Supplies any additional data for the message.
// x86Context - Supplies the current context.
//
// Return Value:
// None.
{
PDBGKD_WRITE_MEMORY64 a = &m->u.WriteMemory;
ULONG Length;
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
Length = AdditionalData->Length;
if (((a->TargetBaseAddress + Length) <= sizeof(KPROCESSOR_STATE)) &&
(m->Processor < (ULONG)KeNumberProcessors)) {
PKPROCESSOR_STATE ProcessorState = &KdpProcessorState[m->Processor];
if (a->TargetBaseAddress < sizeof(CONTEXT)) {
// Need to update the thread context information.
KdWindbgToSingularityContext(&ProcessorState->ContextFrame, x86Context);
}
if (a->TargetBaseAddress + Length > sizeof(CONTEXT)) {
// Need to update the processor context information.
KDDBG(" Writing SpecialRegisters.\n");
ASSERT(m->Processor == 0); // MP support broken.
#if 0
// We don't support separate kernel data breakpoints as
// Singularity uses a single address space.
kdprintf(" dr0=%p dr1=%p dr2=%p dr3=%p dr6=%p dr7=%p\n",
(PVOID)(windbg->Dr0),
(PVOID)(windbg->Dr1),
(PVOID)(windbg->Dr2),
(PVOID)(windbg->Dr3),
(PVOID)(windbg->Dr6),
(PVOID)(windbg->Dr7));
KSPECIAL_REGISTERS *pksp = &ProcessorState->SpecialRegisters;
kdprintf(" cr0=%p cr2=%p cr3=%p cr4=%p\n",
pksp->Cr0, pksp->Cr2, pksp->Cr3, pksp->Cr4);
__asm {
mov ebx, pksp;
#if 0
mov eax, [ebx].Cr0;
mov cr0, eax;
mov eax, [ebx].Cr2;
mov cr2, eax;
mov eax, [ebx].Cr2;
mov cr3, eax;
mov eax, [ebx].Cr4;
_emit 0x0f; // mov cr4,eax
_emit 0x22;
_emit 0xe0;
#endif
mov eax, [ebx].KernelDr0;
mov dr0, eax;
mov eax, [ebx].KernelDr1;
mov dr1, eax;
mov eax, [ebx].KernelDr2;
mov dr2, eax;
mov eax, [ebx].KernelDr3;
mov dr3, eax;
mov eax, [ebx].KernelDr6;
mov dr6, eax;
mov eax, [ebx].KernelDr7;
mov dr7, eax;
}
kdprintf(" dr0=%p dr1=%p dr2=%p dr3=%p dr6=%p dr7=%p\n",
(PVOID)(pksp->KernelDr0),
(PVOID)(pksp->KernelDr1),
(PVOID)(pksp->KernelDr2),
(PVOID)(pksp->KernelDr3),
(PVOID)(pksp->KernelDr6),
(PVOID)(pksp->KernelDr7));
kdprintf(" rr0=%p rr1=%p rr2=%p rr3=%p rr6=%p rr7=%p\n",
(PVOID)(pksp->Reserved[0]),
(PVOID)(pksp->Reserved[1]),
(PVOID)(pksp->Reserved[2]),
(PVOID)(pksp->Reserved[3]),
(PVOID)(pksp->Reserved[4]),
(PVOID)(pksp->Reserved[5]));
#endif
}
m->ReturnStatus = KdpCopyFromPtr(((uint8*)ProcessorState) + a->TargetBaseAddress,
AdditionalData->Buffer,
Length,
&Length);
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
Length = 0;
}
a->ActualBytesWritten = Length;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData,
&KdpContext);
}
static
VOID
KdpSetContext(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN Struct_Microsoft_Singularity_X86_ThreadContext * x86Context
)
// Routine Description:
// This function is called in response of a set context state
// manipulation message. Its function is set the current
// context.
//
// Arguments:
// m - Supplies the state manipulation message.
// AdditionalData - Supplies any additional data for the message.
// x86Context - Supplies the current context.
//
// Return Value:
// None.
{
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == sizeof(CONTEXT));
ASSERT(m->Processor == 0); // MP support broken.
if ((m->Processor >= (USHORT)KeNumberProcessors) ||
(KdpContextSent == FALSE)) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
else {
m->ReturnStatus = STATUS_SUCCESS;
KdWindbgToSingularityContext((CONTEXT*)AdditionalData->Buffer, x86Context);
}
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
}
static
VOID
KdpGetContext(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// This function is called in response of a get context state
// manipulation message. Its function is to return the current
// context.
//
// Arguments:
// m - Supplies the state manipulation message.
// AdditionalData - Supplies any additional data for the message.
// x86Context - Supplies the current context.
//
// Return Value:
// None.
{
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
ASSERT(m->Processor == 0); // MP support broken.
if (m->Processor >= (USHORT)KeNumberProcessors) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
else {
m->ReturnStatus = STATUS_SUCCESS;
AdditionalData->Length = sizeof(CONTEXT);
KdSingularityToWindbgContext(x86Context, (CONTEXT*)AdditionalData->Buffer);
KdpContextSent = TRUE;
}
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData,
&KdpContext);
}
ULONG
KdpAddBreakpoint(
IN PVOID Address
)
// Routine Description:
// This routine adds an entry to the breakpoint table and returns a handle
// to the breakpoint table entry.
//
// Arguments:
// Address - Supplies the address where to set the breakpoint.
//
// Return Value:
//
// A value of zero is returned if the specified address is already in the
// breakpoint table, there are no free entries in the breakpoint table, the
// specified address is not correctly aligned, or the specified address is
// not valid. Otherwise, the index of the assigned breakpoint table entry
// plus one is returned as the function value.
{
ULONG Index;
KDP_BREAKPOINT_TYPE Content;
BOOL Accessible;
KDDBG2("KdpAddBreakpoint(%p)\n", Address);
for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index++) {
if (KdpBreakpointTable[Index].Flags == 0) break;
}
if (Index == BREAKPOINT_TABLE_SIZE) {
KDDBG("KD: ran out of breakpoints!\n");
return 0;
}
Accessible = NT_SUCCESS(KdpCopyFromPtr(&Content,
Address,
sizeof(KDP_BREAKPOINT_TYPE),
NULL));
KDDBG("KD: memory %saccessible\n", Accessible ? "" : "in");
if (Accessible) {
KdpBreakpointTable[Index].Address = Address;
KdpBreakpointTable[Index].Content = Content;
KdpBreakpointTable[Index].Flags = KD_BREAKPOINT_IN_USE;
if (!NT_SUCCESS(KdpCopyToPtr(Address,
&KdpBreakpointInstruction,
sizeof(KDP_BREAKPOINT_TYPE),
NULL))) {
KDDBG("KD: Unable to write BP!\n");
}
}
else {
return 0;
}
return Index+1;
}
BOOLEAN
KdpDeleteBreakpoint(
IN ULONG Handle
)
{
ULONG Index = Handle - 1;
KDDBG2("KD: Delete Breakpoint %d\n", Handle);
if ((Handle == 0) || (Handle > BREAKPOINT_TABLE_SIZE)) {
KDDBG("KD: Breakpoint %d invalid.\n", Index);
return FALSE;
}
//
// Replace the instruction contents.
//
if (!NT_SUCCESS(KdpCopyToPtr(KdpBreakpointTable[Index].Address,
&KdpBreakpointTable[Index].Content,
sizeof(KDP_BREAKPOINT_TYPE),
NULL))) {
KDDBG("KD: Breakpoint at 0x%p; unable to clear, flag set.\n",
KdpBreakpointTable[Index].Address);
return FALSE;
}
else {
KDDBG2("KD: Breakpoint at 0x%p cleared.\n",
KdpBreakpointTable[Index].Address);
KdpBreakpointTable[Index].Flags = 0;
}
return TRUE;
}
VOID
KdpWriteBreakpoint(
IN PDBGKD_MANIPULATE_STATE64 m
)
// Routine Description:
// This function is called in response of a write breakpoint state
// manipulation message. Its function is to write a breakpoint
// and return a handle to the breakpoint.
//
// Arguments:
// m - Supplies the state manipulation message.
// AdditionalData - Supplies any additional data for the message.
// x86Context - Supplies the current context.
//
// Return Value:
// None.
{
PDBGKD_WRITE_BREAKPOINT64 a = &m->u.WriteBreakPoint;
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
a->BreakPointHandle = KdpAddBreakpoint((PVOID)(ULONG_PTR)a->BreakPointAddress);
if (a->BreakPointHandle != 0) {
m->ReturnStatus = STATUS_SUCCESS;
}
else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
}
VOID
KdpRestoreBreakpoint(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData
)
// Routine Description:
// This function is called in response of a restore breakpoint state
// manipulation message. Its function is to restore a breakpoint
// using the specified handle.
//
// Arguments:
// m - Supplies the state manipulation message.
// AdditionalData - Supplies any additional data for the message.
// Context - Supplies the current context.
//
// Return Value:
// None.
{
PDBGKD_RESTORE_BREAKPOINT a = &m->u.RestoreBreakPoint;
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
if (KdpDeleteBreakpoint(a->BreakPointHandle)) {
m->ReturnStatus = STATUS_SUCCESS;
}
else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL,
&KdpContext);
}
static
VOID
KdpGetStateChange(
IN PDBGKD_MANIPULATE_STATE64 ManipulateState,
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// Extract continuation control data from Manipulate_State message
//
// Arguments:
// ManipulateState - supplies pointer to Manipulate_State packet
// x86Context - Supplies a pointer to a context record.
//
// Return Value:
// None.
{
//PKPRCB Prcb;
//ULONG Processor;
if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus)) {
//
// If NT_SUCCESS returns TRUE, then the debugger is doing a
// continue, and it makes sense to apply control changes.
// Otherwise the debugger is saying that it doesn't know what
// to do with this exception, so control values are ignored.
//
if (ManipulateState->u.Continue2.ControlSet.TraceFlag == TRUE) {
KDDBG2("KD: Warning - trace flag set\n");
x86Context->efl |= Struct_Microsoft_Singularity_X86_EFlags_TF;
}
else {
x86Context->efl &= ~Struct_Microsoft_Singularity_X86_EFlags_TF;
}
UINT32 _dr7 = ManipulateState->u.Continue2.ControlSet.Dr7;
x86Context->dr7 = ManipulateState->u.Continue2.ControlSet.Dr7;
#if 0
__asm {
mov eax, 0;
mov dr6, eax;
mov eax, _dr7;
mov dr7, eax;
}
#endif
#if 0
for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) {
Prcb = KiProcessorBlock[Processor];
Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
ManipulateState->u.Continue2.ControlSet.Dr7;
Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L;
}
if (ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart != 1) {
KdpCurrentSymbolStart = ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart;
KdpCurrentSymbolEnd = ManipulateState->u.Continue2.ControlSet.CurrentSymbolEnd;
}
#endif
}
}
KCONTINUE_STATUS
KdpSendWaitContinue(
IN ULONG OutPacketType,
IN PSTRING OutMessageHeader,
IN PSTRING OutMessageData OPTIONAL,
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
)
// Routine Description:
// This function sends a packet, and then waits for a continue message.
// BreakIns received while waiting will always cause a resend of the
// packet originally sent out. While waiting, manipulate messages
// will be serviced.
// A resend always resends the original event sent to the debugger,
// not the last response to some debugger command.
//
// Arguments:
// OutPacketType - Supplies the type of packet to send.
// OutMessageHeader - Supplies a pointer to a string descriptor that describes
// the message information.
// OutMessageData - Supplies a pointer to a string descriptor that describes
// the optional message data.
// x86Record - Exception context
//
// Return Value:
// A value of TRUE is returned if the continue message indicates
// success, Otherwise, a value of FALSE is returned.
{
ULONG Length;
STRING MessageData;
STRING MessageHeader;
DBGKD_MANIPULATE_STATE64 ManipulateState;
ULONG ReturnCode;
// NTSTATUS Status;
// KCONTINUE_STATUS ContinueStatus;
//
// Loop servicing state manipulation message until a continue message
// is received.
//
MessageHeader.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)&ManipulateState;
MessageData.MaximumLength = arrayof(KdpMessageBuffer);
MessageData.Buffer = KdpMessageBuffer;
KdpContextSent = FALSE;
ResendPacket:
//
// Send event notification packet to debugger on host. Come back
// here any time we see a breakin sequence.
//
KdSendPacket(OutPacketType,
OutMessageHeader,
OutMessageData,
&KdpContext);
//
// After sending packet, if there is no response from debugger
// AND the packet is for reporting symbol (un)load, the debugger
// will be declared to be not present. Note If the packet is for
// reporting exception, the KdSendPacket will never stop.
//
if (KdDebuggerNotPresent) {
return ContinueSuccess;
}
for (;;) {
//
// Wait for State Manipulate Packet without timeout.
//
KDDBG("KdpSendWait::\r");
do {
ReturnCode = KdReceivePacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
&MessageData,
&Length,
&KdpContext
);
KDDBG2("KdReceivePacket returned %d\n", ReturnCode);
if (ReturnCode == KDP_PACKET_RESEND) {
goto ResendPacket;
}
} while (ReturnCode == KDP_PACKET_TIMEOUT);
KDDBG2("KdpSendWaitContinue: ManipulateState.ApiNumber=0x%x\n", ManipulateState.ApiNumber);
//
// Switch on the return message API number.
//
switch (ManipulateState.ApiNumber) {
case DbgKdReadVirtualMemoryApi:
KDDBG("KdpSendWait::KdReadVirtualMemory (%8p..%8p) (%d bytes)\n",
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress,
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress +
ManipulateState.u.ReadMemory.TransferCount,
ManipulateState.u.ReadMemory.TransferCount);
KdpReadVirtualMemory(&ManipulateState,&MessageData);
break;
#if 0
case DbgKdReadVirtualMemory64Api:
KdpReadVirtualMemory64(&ManipulateState,&MessageData);
break;
#endif
case DbgKdWriteVirtualMemoryApi:
KDDBG("KdpSendWait::KdWriteVirtualMemory(%8p..%8p)\n",
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress,
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress +
ManipulateState.u.WriteMemory.TransferCount);
KdpWriteVirtualMemory(&ManipulateState,&MessageData);
break;
#if 0
case DbgKdWriteVirtualMemory64Api:
KdpWriteVirtualMemory64(&ManipulateState,&MessageData);
break;
#endif
case DbgKdGetVersionApi:
KDDBG("KdpSendWait::KdGetVersion()\n");
KdpGetVersion(&ManipulateState);
break;
case DbgKdGetContextApi:
KDDBG("KdpSendWait::KdGetContext(p=%x)\n", ManipulateState.Processor);
KdpGetContext(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdReadControlSpaceApi:
KDDBG("KdpSendWait::KdReadControlSpace (%8p..%8p p=%x)\n",
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress,
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress +
ManipulateState.u.ReadMemory.TransferCount,
(ULONG_PTR)ManipulateState.Processor);
KdpReadControlSpace(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdWriteControlSpaceApi:
KDDBG("KdpSendWait::KdWriteControlSpace (%8p..%8p p=%x)\n",
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress,
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress +
ManipulateState.u.WriteMemory.TransferCount,
(ULONG_PTR)ManipulateState.Processor);
KdpWriteControlSpace(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdSetContextApi:
KDDBG("KdpSendWait::KdSetContext(p=%x)\n", ManipulateState.Processor);
KdpSetContext(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdWriteBreakPointApi:
KDDBG("KdpSendWait::KdWriteBreakPoint(%p)\n",
ManipulateState.u.WriteBreakPoint.BreakPointAddress);
KdpWriteBreakpoint(&ManipulateState);
break;
case DbgKdRestoreBreakPointApi:
if (ManipulateState.u.RestoreBreakPoint.BreakPointHandle < 0x8 ||
ManipulateState.u.RestoreBreakPoint.BreakPointHandle > 0x1e) {
KDDBG("KdpSendWait::KdRestoreBreakpoint(h=%x)\n",
ManipulateState.u.RestoreBreakPoint.BreakPointHandle);
}
KdpRestoreBreakpoint(&ManipulateState,&MessageData);
break;
case DbgKdContinueApi:
KDDBG("KdpSendWait::KdContinue(ContinueStatus=%08x)\n",
ManipulateState.u.Continue.ContinueStatus);
if (NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus)) {
return ContinueSuccess;
}
else {
return ContinueError;
}
break;
case DbgKdContinueApi2:
KDDBG("KdpSendWait::KdContinue2(ContinueStatus=%08x)\n",
ManipulateState.u.Continue2.ContinueStatus);
if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus)) {
KDDBG("KdpSendWait::KdpGetStateChange()\n");
KdpGetStateChange(&ManipulateState,x86Context);
return ContinueSuccess;
}
else {
KDDBG("KdpSendWait::ContinueError!\n");
return ContinueError;
}
break;
case DbgKdReadPhysicalMemoryApi:
KDDBG("KdpSendWait::KdReadPhysicalMemory (%8p..%8p)\n",
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress,
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress +
ManipulateState.u.ReadMemory.TransferCount);
// KdpReadPhysicalMemory(&ManipulateState,&MessageData,x86Context);
KdpReadPhysicalMemory(&ManipulateState,&MessageData);
break;
case DbgKdWritePhysicalMemoryApi:
KdpWritePhysicalMemory(&ManipulateState,&MessageData);
KDDBG("KdpSendWait::KdWritePhysicalMemory (%8p..%8p)\n",
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress,
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress +
ManipulateState.u.ReadMemory.TransferCount);
break;
case DbgKdSwitchProcessor:
{
// KdRestore(FALSE);
bool switched = Class_Microsoft_Singularity_MpExecution::g_SwitchFrozenProcessor((int32) ManipulateState.Processor);
return (switched == true) ? ContinueNextProcessor : ContinueSuccess;
// KdSave(FALSE);
}
break;
case DbgKdReadMachineSpecificRegister:
KdpReadMachineSpecificRegister(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdWriteMachineSpecificRegister:
KdpWriteMachineSpecificRegister(&ManipulateState,&MessageData,x86Context);
break;
#if 0 // Haven't implemented most of the protocol yet!
case DbgKdCheckLowMemoryApi:
KdpCheckLowMemory (&ManipulateState);
break;
case DbgKdReadControlSpaceApi:
KdpReadControlSpace(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdWriteControlSpaceApi:
KdpWriteControlSpace(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdReadIoSpaceApi:
KdpReadIoSpace(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdWriteIoSpaceApi:
KdpWriteIoSpace(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdReadIoSpaceExtendedApi:
KdpReadIoSpaceExtended(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdWriteIoSpaceExtendedApi:
KdpWriteIoSpaceExtended(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdGetBusDataApi:
KdpGetBusData(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdSetBusDataApi:
KdpSetBusData(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdRebootApi:
HalReturnToFirmware(HalRebootRoutine);
break;
#if defined(i386)
case DbgKdSetSpecialCallApi:
KdSetSpecialCall(&ManipulateState,x86Context);
break;
case DbgKdClearSpecialCallsApi:
KdClearSpecialCalls();
break;
case DbgKdSetInternalBreakPointApi:
KdSetInternalBreakpoint(&ManipulateState);
break;
case DbgKdGetInternalBreakPointApi:
KdGetInternalBreakpoint(&ManipulateState);
break;
case DbgKdClearAllInternalBreakpointsApi:
KdpNumInternalBreakpoints = 0;
break;
#endif // i386
case DbgKdCauseBugCheckApi:
KdpCauseBugCheck(&ManipulateState);
break;
case DbgKdPageInApi:
KdpNotSupported(&ManipulateState);
break;
case DbgKdWriteBreakPointExApi:
Status = KdpWriteBreakPointEx(&ManipulateState,
&MessageData,
x86Context);
if (Status) {
ManipulateState.ApiNumber = DbgKdContinueApi;
ManipulateState.u.Continue.ContinueStatus = Status;
return ContinueError;
}
break;
case DbgKdRestoreBreakPointExApi:
KdpRestoreBreakPointEx(&ManipulateState,&MessageData,x86Context);
break;
case DbgKdSearchMemoryApi:
KdpSearchMemory(&ManipulateState, &MessageData, x86Context);
break;
case DbgKdFillMemoryApi:
KdpFillMemory(&ManipulateState, &MessageData, x86Context);
break;
case DbgKdQueryMemoryApi:
KdpQueryMemory(&ManipulateState, x86Context);
break;
//
// Invalid message.
//
#endif // XXX Haven't implemented most of the protocol yet!
default:
kdprintf("KdpSendWaitContinue: unrecognized API number 0x%x\n", ManipulateState.ApiNumber);
MessageData.Length = 0;
ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, &MessageData, &KdpContext);
break;
}
}
}
//
//////////////////////////////////////////////////////////////////////////////
BOOLEAN
KdPrintString(
IN PSTRING Output,
IN BOOLEAN Unicode
)
// Routine Description:
// This routine prints a string.
//
// Arguments:
// Output - Supplies a pointer to a string descriptor for the output string.
//
// Return Value:
// TRUE if Control-C present in input buffer after print is done.
// FALSE otherwise.
{
ULONG Length;
STRING MessageData;
STRING MessageHeader;
DBGKD_DEBUG_IO DebugIo;
if (KdDebuggerNotPresent) {
return FALSE;
}
KdpLock();
// Move the output string to the message buffer.
//
if (Unicode) {
WCHAR *pBuffer = (WCHAR *)Output->Buffer;
for (int i = 0; i < Output->Length; i++) {
KdpMessageBuffer[i] = (char)pBuffer[i];
}
Length = Output->Length;
}
else {
KdpCopyFromPtr(KdpMessageBuffer,
Output->Buffer,
Output->Length,
&Length);
}
// If the total message length is greater than the maximum packet size,
// then truncate the output string.
//
if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE) {
Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
}
// Construct the print string message and message descriptor.
//
DebugIo.ApiNumber = DbgKdPrintStringApi;
DebugIo.ProcessorLevel = KeProcessorLevel;
DebugIo.Processor = (USHORT)GetCurrentProcessorNumber();
DebugIo.u.PrintString.LengthOfString = Length;
MessageHeader.Length = sizeof(DBGKD_DEBUG_IO);
MessageHeader.Buffer = (PCHAR)&DebugIo;
// Construct the print string data and data descriptor.
//
MessageData.Length = (USHORT)Length;
MessageData.Buffer = (PCHAR) KdpMessageBuffer;
// Send packet to the kernel debugger on the host machine.
//
KdSendPacket(PACKET_TYPE_KD_DEBUG_IO,
&MessageHeader,
&MessageData,
&KdpContext);
KdpUnlock();
return FALSE;
}
// This should be fixed.
VOID
KdPutChar(
CHAR c
)
{
static char _KdpDebugStringBuf[KDP_MESSAGE_BUFFER_SIZE];
static STRING KdpDebugString = { 0, KDP_MESSAGE_BUFFER_SIZE, (PCHAR)&_KdpDebugStringBuf };
if (KdpInDebugger) {
koutput(NULL, c);
return;
}
KdpDebugString.Buffer[KdpDebugString.Length++] = c;
if (c == '\n' || KdpDebugString.Length == KdpDebugString.MaximumLength) {
KdPrintString(&KdpDebugString, FALSE);
KdpDebugString.Length = 0;
}
}
/////////////////////////////////////////////////////// Methods Exposed to C#.
//
bool Class_Microsoft_Singularity_DebugStub::
g_Trap(Struct_Microsoft_Singularity_X86_ThreadContext *context, bool firstChance)
{
EXCEPTION_RECORD64 er;
bool handled;
RtlZeroMemory(&er, sizeof(er));
KdpLock();
// Breakpoints:
switch (context->num) {
case Struct_Microsoft_Singularity_X86_EVectors_SingleStep:
er.ExceptionCode = STATUS_SINGLE_STEP;
er.ExceptionAddress = (ULONG64)context->eip;
// context->efl &= ~Struct_Microsoft_Singularity_X86_EFlags_TF;
break;
case Struct_Microsoft_Singularity_X86_EVectors_Breakpoint:
context->eip -= 1;
er.ExceptionCode = STATUS_BREAKPOINT;
er.NumberParameters = 1;
er.ExceptionInformation[0] = BREAKPOINT_BREAK;
er.ExceptionAddress = (ULONG64)context->eip;
break;
case Struct_Microsoft_Singularity_X86_EVectors_IllegalInstruction:
er.ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
break;
case Struct_Microsoft_Singularity_X86_EVectors_PageFault:
KDDBG("KD: 0x0E %d\n", context->num);
er.ExceptionCode = STATUS_ACCESS_VIOLATION;
er.ExceptionAddress = (UINT64)context->eip;
er.NumberParameters = 1;
er.ExceptionInformation[0] = context->cr2;
break;
case Struct_Microsoft_Singularity_X86_EVectors_FirstChanceException: {
KdDebugTrapData *trapData = (KdDebugTrapData *) (context->eax);
switch(trapData->tag) {
case KdDebugTrapData::FIRST_CHANCE_EXCEPTION:
context->eax = trapData->u.firstChanceException.throwAddr;
KDDBG("KD: First chance C# exception\n");
// er.ExceptionCode = STATUS_CPP_EH_EXCEPTION; //0xe06d7363;
er.ExceptionCode = STATUS_VCPP_EXCEPTION; //0x8000ff1f;
er.ExceptionAddress = (UINT64)context->eip;
er.NumberParameters = 1;
er.ExceptionInformation[0] = BREAKPOINT_BREAK;
break;
case KdDebugTrapData::LOADED_BINARY:
KDDBG("KD: Loaded binary\n");
KdpUnlock();
LoadedBinary(context);
return true;
case KdDebugTrapData::UNLOADED_BINARY:
KDDBG("KD: Unloaded binary\n");
KdpUnlock();
UnloadedBinary(context);
return true;
default:
KDDBG("KD: Unexpected interrupt %d\n", context->num);
er.ExceptionCode = 0x80000000 + context->num;
er.ExceptionAddress = (UINT64)context->eip;
break;
}
break;
}
case Struct_Microsoft_Singularity_X86_EVectors_SecondChanceException:
KDDBG("KD: Second chance C# exception\n");
er.ExceptionCode = STATUS_VCPP_EXCEPTION;
er.ExceptionAddress = (UINT64)context->eip;
break;
case Struct_Microsoft_Singularity_X86_EVectors_DebuggerBreakRequest:
KDDBG("KD: Debugger ctrl-break\n");
er.ExceptionCode = STATUS_BREAKPOINT;
er.ExceptionInformation[0] = BREAKPOINT_BREAK;
er.ExceptionAddress = (UINT64)context->eip;
break;
default:
KDDBG("KD: Unexpected interrupt %d\n", context->num);
er.ExceptionCode = 0x80000000 + context->num;
er.ExceptionAddress = (UINT64)context->eip;
break;
}
KDDBG("Trap: Context at %p\n", context);
KDDBG(" CXT=%08x THR=%08x\n",
context, context->_thread);
KDDBG(" EIP=%08x EFL=%08x ERR=%08x CR2=%08x\n",
context->eip, context->efl, context->err, context->cr2);
KDDBG(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
context->eax, context->ebx, context->ecx, context->edx);
KDDBG(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
context->esp, context->ebp, context->esi, context->edi);
#if 0
kdprintf("Exception EIPs = %08x", er.ExceptionAddress);
uintptr ebp = context->ebp;
for (int i = 0; i < 3 && ebp >= Struct_Microsoft_Singularity_BootInfo_PHYSICAL_DISABLED; i++) {
uintptr next = ((uintptr *)ebp)[0];
uintptr code = ((uintptr *)ebp)[1];
kdprintf(" %08x", code);
ebp = next;
}
kdprintf("\n");
#endif
KdpEnter();
handled = (KdpReportExceptionStateChange(&er, context, firstChance) == ContinueSuccess);
if (context->num == Struct_Microsoft_Singularity_X86_EVectors_SingleStep &&
(context->efl & Struct_Microsoft_Singularity_X86_EFlags_TF) == 0) {
#if 0
kdprintf("Continuing to eip=%08x [efl=%08x]\n", context->eip, context->efl);
#endif
#if 0
if (context->eip != 0 && *(uint8*)(context->eip) == 0x9c) {
// we always override into single-step mode if the next instruction is pushfd.
context->efl |= Struct_Microsoft_Singularity_X86_EFlags_TF;
kdprintf("Continuing to eip=%08x [efl=%08x] ****\n", context->eip, context->efl);
#if 0
kdprintf(" CXT=%08x THR=%08x REG=%02x\n",
context, context->_thread, context->regs);
kdprintf(" EIP=%08x EFL=%08x ERR=%08x CR2=%08x\n",
context->eip, context->efl, context->err, context->cr2);
kdprintf(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
context->eax, context->ebx, context->ecx, context->edx);
kdprintf(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
context->esp, context->ebp, context->esi, context->edi);
kdprintf(" DR0=%08x DR1=%08x DR2=%08x DR3=%08x\n",
context->dr0, context->dr1, context->dr2, context->dr3);
kdprintf(" DR6=%08x DR7=%08x DR2=%08x DR3=%08x\n",
context->dr6, context->dr7, context->dr2, context->dr3);
#endif
}
#endif
}
#if 0
if (context->num == Struct_Microsoft_Singularity_X86_EVectors_SingleStep &&
context->eip != 0 && *(uint8*)(context->eip) == 0x9c) {
kdprintf(" CXT=%08x THR=%08x REG=%02x\n",
context, context->_thread, context->regs);
kdprintf(" EIP=%08x EFL=%08x ERR=%08x CR2=%08x\n",
context->eip, context->efl, context->err, context->cr2);
kdprintf(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
context->eax, context->ebx, context->ecx, context->edx);
kdprintf(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
context->esp, context->ebp, context->esi, context->edi);
kdprintf(" DR0=%08x DR1=%08x DR2=%08x DR3=%08x\n",
context->dr0, context->dr1, context->dr2, context->dr3);
kdprintf(" DR6=%08x DR7=%08x DR2=%08x DR3=%08x\n",
context->dr6, context->dr7, context->dr2, context->dr3);
}
kdprintf("-- Trap num=0x%02x eip=%08x\n", context->num, context->eip);
#endif
KdpLeave();
KdpUnlock();
return handled;
}
bool Class_Microsoft_Singularity_DebugStub::
g_TrapForProcessorSwitch(Struct_Microsoft_Singularity_X86_ThreadContext *context)
{
EXCEPTION_RECORD64 er;
RtlZeroMemory(&er, sizeof(er));
er.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
er.ExceptionRecord = (ULONG64)&er;
er.ExceptionAddress = (ULONG64)context->eip;
// KdSave(FALSE);
KCONTINUE_STATUS status = KdpReportExceptionStateChange(&er, context, true);
// KdRestore(FALSE);
return status == ContinueSuccess;
}
void Class_Microsoft_Singularity_DebugStub::g_AddProcessor(int cpuId)
{
KdpLock();
KeNumberProcessors = cpuId + 1;
KdpUnlock();
}
void Class_Microsoft_Singularity_DebugStub::g_RevertToUniprocessor()
{
KdpLock();
KeNumberProcessors = 1;
KdpUnlock();
}
bool Class_Microsoft_Singularity_DebugStub::g_PollForBreak()
{
// KdpLock();
// Don't re-enter debugger if already debugging.
if (KdpInDebugger) {
return FALSE;
}
// If the debugger is enabled, see if a breakin by the kernel
// debugger is pending.
// We might want to enable retry here. The transports support it.
if (KdDebuggerNotPresent) {
return false;
}
// Did we already record a break from the host?
if (KdpContext.KdpControlCPending) {
KdpContext.KdpControlCPending = FALSE;
return true;
}
bool success = KdPollBreakIn();
// KdpUnlock();
return success;
}
void Class_Microsoft_Singularity_DebugStub::g_Break()
{
__asm int 3;
}
bool Class_Microsoft_Singularity_DebugStub::g_LoadedBinary(UIntPtr baseAddress,
UIntPtr bytes,
Class_System_String *name,
uint32 checksum,
uint32 timestamp,
bool silent)
{
return g_LoadedBinary(baseAddress,
bytes,
(UIntPtr)&name->m_firstChar,
checksum,
timestamp,
silent);
}
bool Class_Microsoft_Singularity_DebugStub::g_LoadedBinary(UIntPtr baseAddress,
UIntPtr bytes,
UIntPtr name,
uint32 checksum,
uint32 timestamp,
bool silent)
{
KdDebugTrapData trapData, *trapDataPtr = &trapData;
trapData.tag = KdDebugTrapData::LOADED_BINARY;
trapData.u.loadedBinary.baseAddress = baseAddress;
trapData.u.loadedBinary.bytes = bytes;
trapData.u.loadedBinary.name = name;
trapData.u.loadedBinary.checksum = checksum;
trapData.u.loadedBinary.timestamp = timestamp;
trapData.u.loadedBinary.silent = silent;
// Call LoadedBinary via an __asm int 29:
__asm {
mov eax, trapDataPtr;
int 29;
}
return trapData.u.loadedBinary.ret;
}
static void LoadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context)
{
KdDebugTrapData *trapData = (KdDebugTrapData *) (context->eax);
UIntPtr baseAddress = trapData->u.loadedBinary.baseAddress;
UIntPtr bytes = trapData->u.loadedBinary.bytes;
UIntPtr nameof = trapData->u.loadedBinary.name;
uint32 checksum = trapData->u.loadedBinary.checksum;
uint32 timestamp = trapData->u.loadedBinary.timestamp;
bool silent = trapData->u.loadedBinary.silent;
KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry;
bool good = false;
WCHAR * name = trim((WCHAR *)nameof);
USHORT nlen = (USHORT)2 * wcslen(name);
if (nlen > sizeof(pEntry->wzName)) {
nlen = sizeof(pEntry->wzName);
}
KdpLock();
#if 0 // Debug module names
if (name != NULL) {
kdprintf("LoadedBinary(%08lx: %ls)\n", (uint64)(uintptr)name, name);
}
else {
kdprintf("LoadedBinary(%08lx)\n", (uint64)(uintptr)name);
}
#endif
for (int i = 0; i < ARRAYOF(KdModuleKernelEntry); i++) {
pEntry = &KdModuleKernelEntry[i];
if (pEntry->DllBase == 0) {
pEntry->DllBase = (PVOID *)baseAddress;
pEntry->CheckSum = checksum;
pEntry->TimeDateStamp = timestamp;
pEntry->LoadCount = 1;
pEntry->SizeOfImage = (uintptr)bytes;
memcpy(pEntry->wzName, name, nlen);
RtlInitUnicodeString(&pEntry->FullDllName, name, nlen);
RtlInitUnicodeString(&pEntry->BaseDllName, name, nlen);
#if 0
printf("----: BaseOfImage %8lx SizeOfImage %8x ModuleName %8x\n",
(uint64)(uintptr)baseAddress,
(uintptr)bytes,
(uintptr)pEntry->BaseDllName.Buffer);
printf(" ModuleName: %ls (%p)\n",
pEntry->BaseDllName.Buffer,
pEntry);
#endif
// We should insert in the right order in the list...
InsertTailList(&PsLoadedModuleList, &pEntry->InLoadOrderLinks);
good = true;
break;
}
}
if (!silent) {
if (good) {
KdpReportLoadSymbolsStateChange(pEntry->BaseDllName.Buffer,
pEntry->BaseDllName.Length,
(ULONG64)baseAddress,
(ULONG)0,
checksum,
(LONG)bytes,
FALSE,
context);
}
else {
KdpReportLoadSymbolsStateChange(NULL,
0,
(ULONG64)baseAddress,
(ULONG)0,
checksum,
(LONG)bytes,
FALSE,
context);
}
}
KdpUnlock();
trapData->u.loadedBinary.ret = good;
}
bool Class_Microsoft_Singularity_DebugStub::
g_UnloadedBinary(UIntPtr baseAddress, bool silent)
{
KdDebugTrapData trapData, *trapDataPtr = &trapData;
trapData.tag = KdDebugTrapData::UNLOADED_BINARY;
trapData.u.unloadedBinary.baseAddress = baseAddress;
trapData.u.unloadedBinary.silent = silent;
// Call UnloadedBinary via an __asm int 29:
__asm {
mov eax, trapDataPtr;
int 29;
}
return trapData.u.unloadedBinary.ret;
}
static void UnloadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context)
{
KdDebugTrapData *trapData = (KdDebugTrapData *) (context->eax);
UIntPtr baseAddress = trapData->u.unloadedBinary.baseAddress;
bool silent = trapData->u.unloadedBinary.silent;
bool good = false;
KdpLock();
KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry = NULL;
for (int i = 0; i < ARRAYOF(KdModuleKernelEntry); i++) {
pEntry = &KdModuleKernelEntry[i];
if (pEntry->DllBase == (PVOID*)baseAddress) {
RemoveEntryList(&pEntry->InLoadOrderLinks);
good = true;
break;
}
}
if (good) {
if (!silent) {
// Only tell debugger if we found an image name.
// The debugger ignores unload requests that lack a processId (not us)
// or a path name.
KdpReportLoadSymbolsStateChange(pEntry->BaseDllName.Buffer,
pEntry->BaseDllName.Length,
(ULONG64)baseAddress,
(ULONG)0,
0,
0,
TRUE,
context);
}
RtlZeroMemory(pEntry, sizeof(*pEntry));
}
KdpUnlock();
trapData->u.unloadedBinary.ret = good;
}
bool Class_Microsoft_Singularity_DebugStub::g_IsDebuggerPresent()
{
return !KdDebuggerNotPresent;
}
//////////////////////////////////////////////////////////////////////////////
// Note: Leaves the lock held by the client code, so it had better be trustworthy.
void Class_Microsoft_Singularity_DebugStub::g_PrintBegin(WCHAR **buffer, int *length)
{
if (KdDebuggerNotPresent) {
*buffer = NULL;
*length = 0;
return;
}
else {
KdpLock();
*buffer = (WCHAR *)KdpMessageBuffer;
*length = sizeof(KdpMessageBuffer) / sizeof(WCHAR);
}
}
// Note: Assumes the lock is held, so the client code had better be trustworthy.
void Class_Microsoft_Singularity_DebugStub::g_PrintComplete(WCHAR *buffer, int length)
{
if (KdDebuggerNotPresent) {
return;
}
CHAR *out = KdpMessageBuffer;
if (length > arrayof(KdpMessageBuffer)) {
length = arrayof(KdpMessageBuffer);
}
for (int i = 0; i < length; i++) {
*out++ = (CHAR)*buffer++;
}
// If the total message length is greater than the maximum packet size,
// then truncate the output string.
//
if ((sizeof(DBGKD_DEBUG_IO) + length) > PACKET_MAX_SIZE) {
length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
}
//
// Construct the print string message and message descriptor.
//
DBGKD_DEBUG_IO DebugIo;
DebugIo.ApiNumber = DbgKdPrintStringApi;
DebugIo.ProcessorLevel = KeProcessorLevel;
DebugIo.Processor = (USHORT)GetCurrentProcessorNumber();
DebugIo.u.PrintString.LengthOfString = length;
STRING MessageHeader;
MessageHeader.Length = sizeof(DBGKD_DEBUG_IO);
MessageHeader.Buffer = (PCHAR)&DebugIo;
//
// Construct the print string data and data descriptor.
//
STRING MessageData;
MessageData.Length = (USHORT)length;
MessageData.Buffer = KdpMessageBuffer;
//
// Send packet to the kernel debugger on the host machine.
//
KdSendPacket(PACKET_TYPE_KD_DEBUG_IO,
&MessageHeader,
&MessageData,
&KdpContext);
KdpUnlock();
}
void Class_Microsoft_Singularity_DebugStub::g_Print(WCHAR *buf, int len)
{
if (KdDebuggerNotPresent) {
return;
}
WCHAR *buffer;
int length;
g_PrintBegin(&buffer, &length);
g_PrintComplete(buf, len);
}
void Class_Microsoft_Singularity_DebugStub::g_Print(WCHAR *buf)
{
int len = 0;
while (buf[len] != '\0') {
len++;
}
g_Print(buf, len);
}
//
///////////////////////////////////////////////////////////////// End of File.