- Fix incorrect comment, spotted by Timo.
[reactos.git] / reactos / ntoskrnl / kd64 / kdapi.c
index b88faa4..1eac9cf 100644 (file)
-/*\r
- * PROJECT:         ReactOS Kernel\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            ntoskrnl/kd64/kdapi.c\r
- * PURPOSE:         KD64 Public Routines and Internal Support\r
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
- */\r
-\r
-/* INCLUDES ******************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* PRIVATE FUNCTIONS *********************************************************/\r
-\r
-VOID\r
-NTAPI\r
-KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,\r
-               IN PCONTEXT Context)\r
-{\r
-    PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory;\r
-    STRING Header;\r
-    NTSTATUS Status = STATUS_SUCCESS;\r
-\r
-    /* Validate the address space */\r
-    if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL)\r
-    {\r
-        /* Check if this is process memory */\r
-        if ((PVOID)(LONG_PTR)Memory->Address < MmHighestUserAddress)\r
-        {\r
-            /* It is */\r
-            Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS;\r
-        }\r
-        else\r
-        {\r
-            /* FIXME: Check if it's session space */\r
-            Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL;\r
-        }\r
-\r
-        /* Set flags */\r
-        Memory->Flags = DBGKD_QUERY_MEMORY_READ |\r
-                        DBGKD_QUERY_MEMORY_WRITE |\r
-                        DBGKD_QUERY_MEMORY_EXECUTE;\r
-    }\r
-    else\r
-    {\r
-        /* Invalid */\r
-        Status = STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    /* Return structure */\r
-    State->ReturnStatus = Status;\r
-    Memory->Reserved = 0;\r
-\r
-    /* Build header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-\r
-    /* Send the packet */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 NULL,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,\r
-                   IN PSTRING Data,\r
-                   IN PCONTEXT Context)\r
-{\r
-    PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint;\r
-    STRING Header;\r
-\r
-    /* Build header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-    ASSERT(Data->Length == 0);\r
-\r
-    /* Create the breakpoint */\r
-    Breakpoint->BreakPointHandle =\r
-        KdpAddBreakpoint((PVOID)(LONG_PTR)Breakpoint->BreakPointAddress);\r
-    if (!Breakpoint->BreakPointHandle)\r
-    {\r
-        /* We failed */\r
-        State->ReturnStatus = STATUS_UNSUCCESSFUL;\r
-    }\r
-    else\r
-    {\r
-        /* Success! */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-    }\r
-\r
-    /* Send the packet */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 NULL,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-DumpTraceData(OUT PSTRING TraceData)\r
-{\r
-    /* Update the buffer */\r
-    TraceDataBuffer[0] = TraceDataBufferPosition;\r
-\r
-    /* Setup the trace data */\r
-    TraceData->Length = TraceDataBufferPosition * sizeof(ULONG);\r
-    TraceData->Buffer = (PCHAR)TraceDataBuffer;\r
-\r
-    /* Reset the buffer location */\r
-    TraceDataBufferPosition = 1;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpGetStateChange(IN PDBGKD_MANIPULATE_STATE64 State,\r
-                  IN PCONTEXT Context)\r
-{\r
-    PKPRCB Prcb;\r
-    ULONG i;\r
-\r
-    /* Check for success */\r
-    if (NT_SUCCESS(State->u.Continue2.ContinueStatus))\r
-    {\r
-        /* Check if we're tracing */\r
-        if (State->u.Continue2.ControlSet.TraceFlag)\r
-        {\r
-            /* Enable TF */\r
-            Context->EFlags |= EFLAGS_TF;\r
-        }\r
-        else\r
-        {\r
-            /* Remove it */\r
-            Context->EFlags &= ~EFLAGS_TF;\r
-        }\r
-\r
-        /* Loop all processors */\r
-        for (i = 0; i < KeNumberProcessors; i++)\r
-        {\r
-            /* Get the PRCB and update DR7 and DR6 */\r
-            Prcb = KiProcessorBlock[i];\r
-            Prcb->ProcessorState.SpecialRegisters.KernelDr7 =\r
-                State->u.Continue2.ControlSet.Dr7;\r
-            Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0;\r
-        }\r
-\r
-        /* Check if we have new symbol information */\r
-        if (State->u.Continue2.ControlSet.CurrentSymbolStart != 1)\r
-        {\r
-            /* Update it */\r
-            KdpCurrentSymbolStart =\r
-                State->u.Continue2.ControlSet.CurrentSymbolStart;\r
-            KdpCurrentSymbolEnd= State->u.Continue2.ControlSet.CurrentSymbolEnd;\r
-        }\r
-    }\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpSetCommonState(IN ULONG NewState,\r
-                  IN PCONTEXT Context,\r
-                  OUT PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)\r
-{\r
-    USHORT InstructionCount;\r
-    BOOLEAN HadBreakpoints;\r
-\r
-    /* Setup common stuff available for all CPU architectures */\r
-    WaitStateChange->NewState = NewState;\r
-    WaitStateChange->ProcessorLevel = KeProcessorLevel;\r
-    WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;\r
-    WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;\r
-    WaitStateChange->Thread = (LONG_PTR)KeGetCurrentThread();\r
-#if defined(_M_X86_)\r
-    WaitStateChange->ProgramCounter = (ULONG)(LONG_PTR)Context->Eip;\r
-#elif defined(_M_AMD64)\r
-    WaitStateChange->ProgramCounter = (LONG_PTR)Context->Rip;\r
-#else\r
-#error Unknown platform\r
-#endif\r
-\r
-    /* Zero out the Control Report */\r
-    RtlZeroMemory(&WaitStateChange->ControlReport,\r
-                  sizeof(DBGKD_CONTROL_REPORT));\r
-\r
-    /* Now copy the instruction stream and set the count */\r
-    RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],\r
-                  (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,\r
-                  DBGKD_MAXSTREAM);\r
-    InstructionCount = DBGKD_MAXSTREAM;\r
-    WaitStateChange->ControlReport.InstructionCount = InstructionCount;\r
-\r
-    /* Clear all the breakpoints in this region */\r
-    HadBreakpoints =\r
-        KdpDeleteBreakpointRange((PVOID)(LONG_PTR)WaitStateChange->ProgramCounter,\r
-                                 (PVOID)((ULONG_PTR)WaitStateChange->ProgramCounter +\r
-                                         WaitStateChange->ControlReport.InstructionCount - 1));\r
-    if (HadBreakpoints)\r
-    {\r
-        /* Copy the instruction stream again, this time without breakpoints */\r
-        RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],\r
-                      (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,\r
-                      WaitStateChange->ControlReport.InstructionCount);\r
-    }\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)\r
-{\r
-    /* Copy the version block */\r
-    RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)\r
-{\r
-    STRING Header;\r
-\r
-    /* Fill out the header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-\r
-    /* Get the version block */\r
-    KdpSysGetVersion(&State->u.GetVersion64);\r
-\r
-    /* Fill out the state */\r
-    State->ApiNumber = DbgKdGetVersionApi;\r
-    State->ReturnStatus = STATUS_SUCCESS;\r
-\r
-    /* Send the packet */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 NULL,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,\r
-                     IN PSTRING Data,\r
-                     IN PCONTEXT Context)\r
-{\r
-    STRING Header;\r
-    ULONG Length = State->u.ReadMemory.TransferCount;\r
-    NTSTATUS Status = STATUS_SUCCESS;\r
-\r
-    /* Validate length */\r
-    if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))\r
-    {\r
-        /* Overflow, set it to maximum possible */\r
-        Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);\r
-    }\r
-\r
-#if 0\r
-    if (!MmIsAddressValid((PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress))\r
-    {\r
-        Ke386SetCr2(State->u.ReadMemory.TargetBaseAddress);\r
-        while (TRUE);\r
-    }\r
-#endif\r
-\r
-    if (!State->u.ReadMemory.TargetBaseAddress)\r
-    {\r
-        Length = 0;\r
-        Status = STATUS_UNSUCCESSFUL;\r
-    }\r
-    else\r
-    {\r
-        RtlCopyMemory(Data->Buffer,\r
-                      (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,\r
-                      Length);\r
-    }\r
-\r
-    /* Fill out the header */\r
-    Data->Length = Length;\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-\r
-    /* Fill out the state */\r
-    State->ReturnStatus = Status;\r
-    State->u.ReadMemory.ActualBytesRead = Length;\r
-\r
-    /* Send the packet */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 Data,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,\r
-                    IN PSTRING Data,\r
-                    IN PCONTEXT Context)\r
-{\r
-    PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;\r
-    STRING Header;\r
-    ULONG Length, RealLength;\r
-    PVOID ControlStart;\r
-\r
-    /* Setup the header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-    ASSERT(Data->Length == 0);\r
-\r
-    /* Check the length requested */\r
-    Length = ReadMemory->TransferCount;\r
-    if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))\r
-    {\r
-        /* Use maximum allowed */\r
-        Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);\r
-    }\r
-\r
-#if defined (_M_AMD64)\r
-    if ((ULONG)ReadMemory->TargetBaseAddress <= 2)\r
-    {\r
-        switch ((ULONG_PTR)ReadMemory->TargetBaseAddress)\r
-        {\r
-            case 1:\r
-                ControlStart = &KiProcessorBlock[State->Processor];\r
-                RealLength = sizeof(PVOID);\r
-                break;\r
-\r
-            case 2:\r
-                ControlStart = &KiProcessorBlock[State->Processor]->\r
-                                         ProcessorState.SpecialRegisters;\r
-                RealLength = sizeof(KSPECIAL_REGISTERS);\r
-                break;\r
-\r
-            default:\r
-                RealLength = 0;\r
-                ControlStart = NULL;\r
-                ASSERT(FALSE);\r
-        }\r
-\r
-        if (RealLength < Length) Length = RealLength;\r
-\r
-        /* Copy the memory */\r
-        RtlCopyMemory(Data->Buffer, ControlStart, Length);\r
-        Data->Length = Length;\r
-\r
-        /* Finish up */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-        ReadMemory->ActualBytesRead = Data->Length;\r
-    }\r
-#else\r
-    /* Make sure that this is a valid request */\r
-    if (((ULONG)ReadMemory->TargetBaseAddress < sizeof(KPROCESSOR_STATE)) &&\r
-        (State->Processor < KeNumberProcessors))\r
-    {\r
-        /* Get the actual length */\r
-        RealLength = sizeof(KPROCESSOR_STATE) -\r
-                     (ULONG_PTR)ReadMemory->TargetBaseAddress;\r
-        if (RealLength < Length) Length = RealLength;\r
-\r
-        /* Set the proper address */\r
-        ControlStart = (PVOID)((ULONG_PTR)ReadMemory->TargetBaseAddress +\r
-                               (ULONG_PTR)&KiProcessorBlock[State->Processor]->\r
-                                           ProcessorState);\r
-\r
-        /* Copy the memory */\r
-        RtlCopyMemory(Data->Buffer, ControlStart, Length);\r
-        Data->Length = Length;\r
-\r
-        /* Finish up */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-        ReadMemory->ActualBytesRead = Data->Length;\r
-    }\r
-#endif\r
-    else\r
-    {\r
-        /* Invalid request */\r
-        Data->Length = 0;\r
-        State->ReturnStatus = STATUS_UNSUCCESSFUL;\r
-        ReadMemory->ActualBytesRead = 0;\r
-    }\r
-\r
-    /* Send the reply */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 Data,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,\r
-                     IN PSTRING Data,\r
-                     IN PCONTEXT Context)\r
-{\r
-    PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;\r
-    STRING Header;\r
-    ULONG Length;\r
-    PVOID ControlStart;\r
-\r
-    /* Setup the header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-\r
-    /* Make sure that this is a valid request */\r
-    Length = WriteMemory->TransferCount;\r
-    if ((((ULONG)WriteMemory->TargetBaseAddress + Length) <=\r
-          sizeof(KPROCESSOR_STATE)) &&\r
-        (State->Processor < KeNumberProcessors))\r
-    {\r
-        /* Set the proper address */\r
-        ControlStart = (PVOID)((ULONG_PTR)WriteMemory->TargetBaseAddress +\r
-                               (ULONG_PTR)&KiProcessorBlock[State->Processor]->\r
-                                           ProcessorState);\r
-\r
-        /* Copy the memory */\r
-        RtlCopyMemory(ControlStart, Data->Buffer, Data->Length);\r
-        Length = Data->Length;\r
-\r
-        /* Finish up */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-        WriteMemory->ActualBytesWritten = Length;\r
-    }\r
-    else\r
-    {\r
-        /* Invalid request */\r
-        Data->Length = 0;\r
-        State->ReturnStatus = STATUS_UNSUCCESSFUL;\r
-        WriteMemory->ActualBytesWritten = 0;\r
-    }\r
-\r
-    /* Send the reply */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 Data,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,\r
-                     IN PSTRING Data,\r
-                     IN PCONTEXT Context)\r
-{\r
-    PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;\r
-    STRING Header;\r
-\r
-    /* Fill out the header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-    ASSERT(Data->Length == 0);\r
-\r
-    /* Get the version block */\r
-    if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))\r
-    {\r
-        /* We're all good */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-    }\r
-    else\r
-    {\r
-        /* We failed */\r
-        State->ReturnStatus = STATUS_UNSUCCESSFUL;\r
-    }\r
-\r
-    /* Send the packet */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 NULL,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,\r
-              IN PSTRING Data,\r
-              IN PCONTEXT Context)\r
-{\r
-    STRING Header;\r
-    PVOID ControlStart;\r
-\r
-    /* Setup the header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-    ASSERT(Data->Length == 0);\r
-\r
-    /* Make sure that this is a valid request */\r
-    if (State->Processor < KeNumberProcessors)\r
-    {\r
-        /* Check if the request is for this CPU */\r
-        if (State->Processor == KeGetCurrentPrcb()->Number)\r
-        {\r
-            /* We're just copying our own context */\r
-            ControlStart = Context;\r
-        }\r
-        else\r
-        {\r
-            /* SMP not yet handled */\r
-            ControlStart = NULL;\r
-            while (TRUE);\r
-        }\r
-\r
-        /* Copy the memory */\r
-        RtlCopyMemory(Data->Buffer, ControlStart, sizeof(CONTEXT));\r
-        Data->Length = sizeof(CONTEXT);\r
-\r
-        /* Finish up */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-    }\r
-    else\r
-    {\r
-        /* Invalid request */\r
-        State->ReturnStatus = STATUS_UNSUCCESSFUL;\r
-    }\r
-\r
-    /* Send the reply */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 Data,\r
-                 &KdpContext);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,\r
-              IN PSTRING Data,\r
-              IN PCONTEXT Context)\r
-{\r
-    STRING Header;\r
-    PVOID ControlStart;\r
-\r
-    /* Setup the header */\r
-    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)State;\r
-    ASSERT(Data->Length == sizeof(CONTEXT));\r
-\r
-    /* Make sure that this is a valid request */\r
-    if (State->Processor < KeNumberProcessors)\r
-    {\r
-        /* Check if the request is for this CPU */\r
-        if (State->Processor == KeGetCurrentPrcb()->Number)\r
-        {\r
-            /* We're just copying our own context */\r
-            ControlStart = Context;\r
-        }\r
-        else\r
-        {\r
-            /* SMP not yet handled */\r
-            ControlStart = NULL;\r
-            while (TRUE);\r
-        }\r
-\r
-        /* Copy the memory */\r
-        RtlCopyMemory(ControlStart, Data->Buffer, sizeof(CONTEXT));\r
-\r
-        /* Finish up */\r
-        State->ReturnStatus = STATUS_SUCCESS;\r
-    }\r
-    else\r
-    {\r
-        /* Invalid request */\r
-        State->ReturnStatus = STATUS_UNSUCCESSFUL;\r
-    }\r
-\r
-    /* Send the reply */\r
-    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                 &Header,\r
-                 Data,\r
-                 &KdpContext);\r
-}\r
-\r
-KCONTINUE_STATUS\r
-NTAPI\r
-KdpSendWaitContinue(IN ULONG PacketType,\r
-                    IN PSTRING SendHeader,\r
-                    IN PSTRING SendData OPTIONAL,\r
-                    IN OUT PCONTEXT Context)\r
-{\r
-    STRING Data, Header;\r
-    DBGKD_MANIPULATE_STATE64 ManipulateState;\r
-    ULONG Length;\r
-    KDSTATUS RecvCode;\r
-FrLdrDbgPrint("Enter KdpSendWaitContinue\n");\r
-    /* Setup the Manipulate State structure */\r
-    Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);\r
-    Header.Buffer = (PCHAR)&ManipulateState;\r
-    Data.MaximumLength = sizeof(KdpMessageBuffer);\r
-    Data.Buffer = KdpMessageBuffer;\r
-    //KdpContextSent = FALSE;\r
-\r
-SendPacket:\r
-    /* Send the Packet */\r
-    KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);\r
-\r
-    /* If the debugger isn't present anymore, just return success */\r
-    if (KdDebuggerNotPresent) return ContinueSuccess;\r
-\r
-    /* Main processing Loop */\r
-    for (;;)\r
-    {\r
-        /* Receive Loop */\r
-        do\r
-        {\r
-            /* Wait to get a reply to our packet */\r
-            RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                                       &Header,\r
-                                       &Data,\r
-                                       &Length,\r
-                                       &KdpContext);\r
-\r
-            /* If we got a resend request, do it */\r
-            if (RecvCode == KdPacketNeedsResend) goto SendPacket;\r
-        } while (RecvCode == KdPacketTimedOut);\r
-\r
-        /* Now check what API we got */\r
-        switch (ManipulateState.ApiNumber)\r
-        {\r
-            case DbgKdReadVirtualMemoryApi:\r
-\r
-                /* Read virtual memory */\r
-                KdpReadVirtualMemory(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdWriteVirtualMemoryApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdWriteVirtualMemoryApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdGetContextApi:\r
-\r
-                /* Get the current context */\r
-                KdpGetContext(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdSetContextApi:\r
-\r
-                /* Set a new context */\r
-                KdpSetContext(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdWriteBreakPointApi:\r
-\r
-                /* Write the breakpoint */\r
-                KdpWriteBreakpoint(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdRestoreBreakPointApi:\r
-\r
-                /* FIXME: TODO */\r
-                KdpRestoreBreakpoint(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdContinueApi:\r
-\r
-                /* Simply continue */\r
-                return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);\r
-\r
-            case DbgKdReadControlSpaceApi:\r
-\r
-                /* Read control space */\r
-                KdpReadControlSpace(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdWriteControlSpaceApi:\r
-\r
-                /* FIXME: TODO */\r
-                KdpWriteControlSpace(&ManipulateState, &Data, Context);\r
-                break;\r
-\r
-            case DbgKdReadIoSpaceApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdReadIoSpaceApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdWriteIoSpaceApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdWriteIoSpaceApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdRebootApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdRebootApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdContinueApi2:\r
-\r
-                /* Check if caller reports success */\r
-                if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))\r
-                {\r
-                    /* Update the state */\r
-                    KdpGetStateChange(&ManipulateState, Context);\r
-                    return ContinueSuccess;\r
-                }\r
-                else\r
-                {\r
-                    /* Return an error */\r
-                    return ContinueError;\r
-                }\r
-                break;\r
-\r
-            case DbgKdReadPhysicalMemoryApi:\r
-\r
-                /* FIXME: TODO */\r
-                goto fail;\r
-                Ke386SetCr2(DbgKdReadPhysicalMemoryApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdWritePhysicalMemoryApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdWritePhysicalMemoryApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdQuerySpecialCallsApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdQuerySpecialCallsApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdSetSpecialCallApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdSetSpecialCallApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdClearSpecialCallsApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdClearSpecialCallsApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdSetInternalBreakPointApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdSetInternalBreakPointApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdGetInternalBreakPointApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdGetInternalBreakPointApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdReadIoSpaceExtendedApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdWriteIoSpaceExtendedApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdGetVersionApi:\r
-\r
-                /* Get version data */\r
-                KdpGetVersion(&ManipulateState);\r
-                break;\r
-\r
-            case DbgKdWriteBreakPointExApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdWriteBreakPointExApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdRestoreBreakPointExApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdRestoreBreakPointExApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdCauseBugCheckApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdCauseBugCheckApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdSwitchProcessor:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdSwitchProcessor);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdPageInApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdPageInApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdReadMachineSpecificRegister:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdReadMachineSpecificRegister);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdWriteMachineSpecificRegister:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdWriteMachineSpecificRegister);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case OldVlm1:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(OldVlm1);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case OldVlm2:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(OldVlm2);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdSearchMemoryApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdSearchMemoryApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdGetBusDataApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdGetBusDataApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdSetBusDataApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdSetBusDataApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdCheckLowMemoryApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdCheckLowMemoryApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdClearAllInternalBreakpointsApi:\r
-\r
-                /* Just clear the counter */\r
-                KdpNumInternalBreakpoints = 0;\r
-                break;\r
-\r
-            case DbgKdFillMemoryApi:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdFillMemoryApi);\r
-                while (TRUE);\r
-                break;\r
-\r
-            case DbgKdQueryMemoryApi:\r
-\r
-                /* Query memory */\r
-                KdpQueryMemory(&ManipulateState, Context);\r
-                break;\r
-\r
-            case DbgKdSwitchPartition:\r
-\r
-                /* FIXME: TODO */\r
-                Ke386SetCr2(DbgKdSwitchPartition);\r
-                while (TRUE);\r
-                break;\r
-\r
-            /* Unsupported Message */\r
-            default:\r
-\r
-                /* Setup an empty message, with failure */\r
-                while (TRUE);\r
-fail:\r
-                Data.Length = 0;\r
-                ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;\r
-\r
-                /* Send it */\r
-                KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,\r
-                             &Header,\r
-                             &Data,\r
-                             &KdpContext);\r
-                break;\r
-        }\r
-    }\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpReportLoadSymbolsStateChange(IN PSTRING PathName,\r
-                                IN PKD_SYMBOLS_INFO SymbolInfo,\r
-                                IN BOOLEAN Unload,\r
-                                IN OUT PCONTEXT Context)\r
-{\r
-    PSTRING ExtraData;\r
-    STRING Data, Header;\r
-    DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;\r
-    KCONTINUE_STATUS Status;\r
-\r
-    /* Start wait loop */\r
-    do\r
-    {\r
-        /* Build the architecture common parts of the message */\r
-        KdpSetCommonState(DbgKdLoadSymbolsStateChange,\r
-                          Context,\r
-                          &WaitStateChange);\r
-\r
-        /* Now finish creating the structure */\r
-        KdpSetContextState(&WaitStateChange, Context);\r
-\r
-        /* Fill out load data */\r
-        WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;\r
-        WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONGLONG)(LONG_PTR)SymbolInfo->BaseOfDll;\r
-        WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;\r
-        WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;\r
-        WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;\r
-\r
-        /* Check if we have a symbol name */\r
-        if (PathName)\r
-        {\r
-            /* Setup the information */\r
-            WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;\r
-            RtlCopyMemory(KdpPathBuffer, PathName->Buffer, PathName->Length);\r
-            Data.Buffer = KdpPathBuffer;\r
-            Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;\r
-            ExtraData = &Data;\r
-        }\r
-        else\r
-        {\r
-            /* No name */\r
-            WaitStateChange.u.LoadSymbols.PathNameLength = 0;\r
-            ExtraData = NULL;\r
-        }\r
-\r
-        /* Setup the header */\r
-        Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);\r
-        Header.Buffer = (PCHAR)&WaitStateChange;\r
-\r
-        /* Send the packet */\r
-        Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,\r
-                                     &Header,\r
-                                     ExtraData,\r
-                                     Context);\r
-    } while(Status == ContinueProcessorReselected);\r
-\r
-    /* Return status */\r
-    return Status;\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,\r
-                              IN OUT PCONTEXT Context,\r
-                              IN BOOLEAN SecondChanceException)\r
-{\r
-    STRING Header, Data;\r
-    DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;\r
-    BOOLEAN Status;\r
-\r
-    /* Start report loop */\r
-    do\r
-    {\r
-        /* Build the architecture common parts of the message */\r
-        KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);\r
-\r
-        /* Convert the exception record to 64-bits and set First Chance flag */\r
-        ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,\r
-                              &WaitStateChange.u.Exception.ExceptionRecord);\r
-        WaitStateChange.u.Exception.FirstChance = !SecondChanceException;\r
-\r
-        /* Now finish creating the structure */\r
-        KdpSetContextState(&WaitStateChange, Context);\r
-\r
-        /* Setup the actual header to send to KD */\r
-        Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64) - sizeof(CONTEXT);\r
-        Header.Buffer = (PCHAR)&WaitStateChange;\r
-\r
-        /* Setup the trace data */\r
-        DumpTraceData(&Data);\r
-\r
-        /* Send State Change packet and wait for a reply */\r
-        Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,\r
-                                     &Header,\r
-                                     &Data,\r
-                                     Context);\r
-    } while (Status == KdPacketNeedsResend);\r
-\r
-    /* Return */\r
-    return Status;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpTimeSlipDpcRoutine(IN PKDPC Dpc,\r
-                      IN PVOID DeferredContext,\r
-                      IN PVOID SystemArgument1,\r
-                      IN PVOID SystemArgument2)\r
-{\r
-    LONG OldSlip, NewSlip, PendingSlip;\r
-\r
-    /* Get the current pending slip */\r
-    PendingSlip = KdpTimeSlipPending;\r
-    do\r
-    {\r
-        /* Save the old value and either disable or enable it now. */\r
-        OldSlip = PendingSlip;\r
-        NewSlip = OldSlip > 1 ? 1 : 0;\r
-\r
-        /* Try to change the value */\r
-    } while (InterlockedCompareExchange(&KdpTimeSlipPending,\r
-                                        NewSlip,\r
-                                        OldSlip) != OldSlip);\r
-\r
-    /* If the New Slip value is 1, then do the Time Slipping */\r
-    if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdpTimeSlipWork(IN PVOID Context)\r
-{\r
-    KIRQL OldIrql;\r
-    LARGE_INTEGER DueTime;\r
-\r
-    /* Update the System time from the CMOS */\r
-    ExAcquireTimeRefreshLock(FALSE);\r
-    ExUpdateSystemTimeFromCmos(FALSE, 0);\r
-    ExReleaseTimeRefreshLock();\r
-\r
-    /* Check if we have a registered Time Slip Event and signal it */\r
-    KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);\r
-    if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);\r
-    KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);\r
-\r
-    /* Delay the DPC until it runs next time */\r
-    DueTime.QuadPart = -1800000000;\r
-    KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,\r
-                   IN OUT PCONTEXT ContextRecord,\r
-                   IN BOOLEAN SecondChanceException)\r
-{\r
-    BOOLEAN Status;\r
-\r
-    /* Save the port data */\r
-    KdSave(FALSE);\r
-\r
-    /* Report a state change */\r
-    Status = KdpReportExceptionStateChange(ExceptionRecord,\r
-                                           ContextRecord,\r
-                                           SecondChanceException);\r
-\r
-    /* Restore the port data and return */\r
-    KdRestore(FALSE);\r
-    return Status;\r
-}\r
-\r
-LARGE_INTEGER\r
-NTAPI\r
-KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)\r
-{\r
-    LARGE_INTEGER Null = {{0}};\r
-\r
-    /* Check if interrupts were disabled */\r
-    if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))\r
-    {\r
-        /* Nothing to return */\r
-        return Null;\r
-    }\r
-\r
-    /* Otherwise, do the call */\r
-    return KeQueryPerformanceCounter(NULL);\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,\r
-                IN PKEXCEPTION_FRAME ExceptionFrame)\r
-{\r
-    BOOLEAN Entered;\r
-FrLdrDbgPrint("KdEnterDebugger!\n");\r
-    /* Check if we have a trap frame */\r
-    if (TrapFrame)\r
-    {\r
-        /* Calculate the time difference for the enter */\r
-        KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);\r
-        KdTimerDifference.QuadPart = KdTimerStop.QuadPart -\r
-                                     KdTimerStart.QuadPart;\r
-    }\r
-    else\r
-    {\r
-        /* No trap frame, so can't calculate */\r
-        KdTimerStop.QuadPart = 0;\r
-    }\r
-\r
-    /* Save the current IRQL */\r
-    KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();\r
-\r
-    /* Freeze all CPUs */\r
-    Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);\r
-\r
-    /* Lock the port, save the state and set debugger entered */\r
-    KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);\r
-    KdSave(FALSE);\r
-    KdEnteredDebugger = TRUE;\r
-\r
-    /* Check freeze flag */\r
-    if (KiFreezeFlag & 1)\r
-    {\r
-        /* Print out errror */\r
-        DbgPrint("FreezeLock was jammed!  Backup SpinLock was used!\n");\r
-    }\r
-\r
-    /* Check processor state */\r
-    if (KiFreezeFlag & 2)\r
-    {\r
-        /* Print out errror */\r
-        DbgPrint("Some processors not frozen in debugger!\n");\r
-    }\r
-\r
-    /* Make sure we acquired the port */\r
-    if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");\r
-FrLdrDbgPrint("KdEnterDebugger returns %d\n", Entered);\r
-    /* Return enter state */\r
-    return Entered;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-KdExitDebugger(IN BOOLEAN Entered)\r
-{\r
-    ULONG TimeSlip;\r
-\r
-    /* Restore the state and unlock the port */\r
-    KdRestore(FALSE);\r
-    if (KdpPortLocked) KdpPortUnlock();\r
-\r
-    /* Unfreeze the CPUs */\r
-    KeThawExecution(Entered);\r
-\r
-    /* Compare time with the one from KdEnterDebugger */\r
-    if (!KdTimerStop.QuadPart)\r
-    {\r
-        /* We didn't get a trap frame earlier in so never got the time */\r
-        KdTimerStart = KdTimerStop;\r
-    }\r
-    else\r
-    {\r
-        /* Query the timer */\r
-        KdTimerStart = KeQueryPerformanceCounter(NULL);\r
-    }\r
-\r
-    /* Check if a Time Slip was on queue */\r
-    TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);\r
-    if (TimeSlip == 1)\r
-    {\r
-        /* Queue a DPC for the time slip */\r
-        InterlockedIncrement(&KdpTimeSlipPending);\r
-        KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);\r
-    }\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-KdEnableDebuggerWithLock(BOOLEAN NeedLock)\r
-{\r
-    KIRQL OldIrql = PASSIVE_LEVEL;\r
-\r
-    /* Check if we need to acquire the lock */\r
-    if (NeedLock)\r
-    {\r
-        /* Lock the port */\r
-        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);\r
-        KdpPortLock();\r
-    }\r
-\r
-    /* Check if we're not disabled */\r
-    if (!KdDisableCount)\r
-    {\r
-        /* Check if we had locked the port before */\r
-        if (NeedLock)\r
-        {\r
-            /* Do the unlock */\r
-            KeLowerIrql(OldIrql);\r
-            KdpPortUnlock();\r
-        }\r
-\r
-        /* Fail: We're already enabled */\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    /* Decrease the disable count */\r
-    if (!(--KdDisableCount))\r
-    {\r
-        /* We're now enabled again! Were we enabled before, too? */\r
-        if (KdPreviouslyEnabled)\r
-        {\r
-            /* Reinitialize the Debugger */\r
-            KdInitSystem(0, NULL) ;\r
-            KdpRestoreAllBreakpoints();\r
-        }\r
-    }\r
-\r
-    /* Check if we had locked the port before */\r
-    if (NeedLock)\r
-    {\r
-        /* Yes, now unlock it */\r
-        KeLowerIrql(OldIrql);\r
-        KdpPortUnlock();\r
-    }\r
-\r
-    /* We're done */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/* PUBLIC FUNCTIONS **********************************************************/\r
-\r
-/*\r
- * @implemented\r
- */\r
-NTSTATUS\r
-NTAPI\r
-KdEnableDebugger(VOID)\r
-{\r
-    /* Use the internal routine */\r
-    while (TRUE);\r
-    return KdEnableDebuggerWithLock(TRUE);\r
-}\r
-\r
-/*\r
- * @unimplemented\r
- */\r
-NTSTATUS\r
-NTAPI\r
-KdSystemDebugControl(IN SYSDBG_COMMAND Command,\r
-                     IN PVOID InputBuffer,\r
-                     IN ULONG InputBufferLength,\r
-                     OUT PVOID OutputBuffer,\r
-                     IN ULONG OutputBufferLength,\r
-                     IN OUT PULONG ReturnLength,\r
-                     IN KPROCESSOR_MODE PreviousMode)\r
-{\r
-    /* HACK */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * @unimplemented\r
- */\r
-NTSTATUS\r
-NTAPI\r
-KdChangeOption(IN KD_OPTION Option,\r
-               IN ULONG InBufferBytes OPTIONAL,\r
-               IN PVOID InBuffer,\r
-               IN ULONG OutBufferBytes OPTIONAL,\r
-               OUT PVOID OutBuffer,\r
-               OUT PULONG OutBufferNeeded OPTIONAL)\r
-{\r
-    /* HACK */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * @unimplemented\r
- */\r
-NTSTATUS\r
-NTAPI\r
-KdPowerTransition(IN DEVICE_POWER_STATE NewState)\r
-{\r
-    /* HACK */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * @unimplemented\r
- */\r
-NTSTATUS\r
-NTAPI\r
-KdDisableDebugger(VOID)\r
-{\r
-    /* HACK */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * @unimplemented\r
- */\r
-BOOLEAN\r
-NTAPI\r
-KdRefreshDebuggerNotPresent(VOID)\r
-{\r
-    /* HACK */\r
-    return KdDebuggerNotPresent;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-NtQueryDebugFilterState(ULONG ComponentId,\r
-                        ULONG Level)\r
-{\r
-    /* HACK */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-NtSetDebugFilterState(ULONG ComponentId,\r
-                      ULONG Level,\r
-                      BOOLEAN State)\r
-{\r
-    /* HACK */\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            ntoskrnl/kd64/kdapi.c
+ * PURPOSE:         KD64 Public Routines and Internal Support
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Stefan Ginsberg (stefan.ginsberg@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+NTSTATUS
+NTAPI
+KdpCopyMemoryChunks(IN ULONG64 Address,
+                    IN PVOID Buffer,
+                    IN ULONG TotalSize,
+                    IN ULONG ChunkSize,
+                    IN ULONG Flags,
+                    OUT PULONG ActualSize OPTIONAL)
+{
+    NTSTATUS Status;
+    ULONG RemainingLength, CopyChunk;
+
+    /* Check if we didn't get a chunk size or if it is too big */
+    if (ChunkSize == 0)
+    {
+        /* Default to 4 byte chunks */
+        ChunkSize = 4;
+    }
+    else if (ChunkSize > MMDBG_COPY_MAX_SIZE)
+    {
+        /* Normalize to maximum size */
+        ChunkSize = MMDBG_COPY_MAX_SIZE;
+    }
+
+    /* Copy the whole range in aligned chunks */
+    RemainingLength = TotalSize;
+    CopyChunk = 1;
+    while (RemainingLength > 0)
+    {
+        /*
+         * Determine the best chunk size for this round.
+         * The ideal size is aligned, isn't larger than the
+         * the remaining length and respects the chunk limit.
+         */
+        while (((CopyChunk * 2) <= RemainingLength) &&
+               (CopyChunk < ChunkSize) &&
+               ((Address & ((CopyChunk * 2) - 1)) == 0))
+        {
+            /* Increase it */
+            CopyChunk *= 2;
+        }
+
+        /*
+         * The chunk size can be larger than the remaining size if this isn't
+         * the first round, so check if we need to shrink it back
+         */
+        while (CopyChunk > RemainingLength)
+        {
+            /* Shrink it */
+            CopyChunk /= 2;
+        }
+
+        /* Do the copy */
+        Status = MmDbgCopyMemory(Address,
+                                 Buffer,
+                                 CopyChunk,
+                                 Flags);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Copy failed, break out */
+            break;
+        }
+
+        /* Update pointers and length for the next run */
+        Address = Address + CopyChunk;
+        Buffer = (PVOID)((ULONG_PTR)Buffer + CopyChunk);
+        RemainingLength = RemainingLength - CopyChunk;
+    }
+
+    /*
+     * Return the size we managed to copy
+     * and return success if we could copy the whole range
+     */
+    if (ActualSize) *ActualSize = TotalSize - RemainingLength;
+    return RemainingLength == 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,
+               IN PCONTEXT Context)
+{
+    PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory;
+    STRING Header;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Validate the address space */
+    if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL)
+    {
+        /* Check if this is process memory */
+        if ((PVOID)(ULONG_PTR)Memory->Address < MmHighestUserAddress)
+        {
+            /* It is */
+            Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS;
+        }
+        else
+        {
+            /* FIXME: Check if it's session space */
+            Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL;
+        }
+
+        /* Set flags */
+        Memory->Flags = DBGKD_QUERY_MEMORY_READ |
+                        DBGKD_QUERY_MEMORY_WRITE |
+                        DBGKD_QUERY_MEMORY_EXECUTE;
+    }
+    else
+    {
+        /* Invalid */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return structure */
+    State->ReturnStatus = Status;
+    Memory->Reserved = 0;
+
+    /* Build header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpSearchMemory(IN PDBGKD_MANIPULATE_STATE64 State,
+                IN PSTRING Data,
+                IN PCONTEXT Context)
+{
+    //PDBGKD_SEARCH_MEMORY SearchMemory = &State->u.SearchMemory;
+    STRING Header;
+
+    /* TODO */
+    KdpDprintf("Memory Search support is unimplemented!\n");
+
+    /* Send a failure packet */
+    State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State,
+              IN PSTRING Data,
+              IN PCONTEXT Context)
+{
+    //PDBGKD_FILL_MEMORY FillMemory = &State->u.FillMemory;
+    STRING Header;
+
+    /* TODO */
+    KdpDprintf("Memory Fill support is unimplemented!\n");
+
+    /* Send a failure packet */
+    State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
+                   IN PSTRING Data,
+                   IN PCONTEXT Context)
+{
+    PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint;
+    STRING Header;
+
+    /* Build header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Create the breakpoint */
+    Breakpoint->BreakPointHandle =
+        KdpAddBreakpoint((PVOID)(ULONG_PTR)Breakpoint->BreakPointAddress);
+    if (!Breakpoint->BreakPointHandle)
+    {
+        /* We failed */
+        State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    }
+    else
+    {
+        /* Success! */
+        State->ReturnStatus = STATUS_SUCCESS;
+    }
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
+                     IN PSTRING Data,
+                     IN PCONTEXT Context)
+{
+    PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
+    STRING Header;
+
+    /* Fill out the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Get the version block */
+    if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
+    {
+        /* We're all good */
+        State->ReturnStatus = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* We failed */
+        State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    }
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+NTSTATUS
+NTAPI
+KdpWriteBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
+                     IN PSTRING Data,
+                     IN PCONTEXT Context)
+{
+    //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx;
+    STRING Header;
+
+    /* TODO */
+    KdpDprintf("Extended Breakpoint Write support is unimplemented!\n");
+
+    /* Send a failure packet */
+    State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+    return STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+KdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
+                       IN PSTRING Data,
+                       IN PCONTEXT Context)
+{
+    //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx;
+    STRING Header;
+
+    /* TODO */
+    KdpDprintf("Extended Breakpoint Restore support is unimplemented!\n");
+
+    /* Send a failure packet */
+    State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+DumpTraceData(IN PSTRING TraceData)
+{
+    /* Update the buffer */
+    TraceDataBuffer[0] = TraceDataBufferPosition;
+
+    /* Setup the trace data */
+    TraceData->Length = TraceDataBufferPosition * sizeof(ULONG);
+    TraceData->Buffer = (PCHAR)TraceDataBuffer;
+
+    /* Reset the buffer location */
+    TraceDataBufferPosition = 1;
+}
+
+VOID
+NTAPI
+KdpSetCommonState(IN ULONG NewState,
+                  IN PCONTEXT Context,
+                  IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange)
+{
+    ULONG InstructionCount;
+    BOOLEAN HadBreakpoints;
+
+    /* Setup common stuff available for all CPU architectures */
+    WaitStateChange->NewState = NewState;
+    WaitStateChange->ProcessorLevel = KeProcessorLevel;
+    WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
+    WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
+    WaitStateChange->Thread = (ULONG64)(LONG_PTR)KeGetCurrentThread();
+    WaitStateChange->ProgramCounter = (ULONG64)(LONG_PTR)KeGetContextPc(Context);
+
+    /* Zero out the entire Control Report */
+    RtlZeroMemory(&WaitStateChange->AnyControlReport,
+                  sizeof(DBGKD_ANY_CONTROL_REPORT));
+
+    /* Now copy the instruction stream and set the count */
+    KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter,
+                        &WaitStateChange->ControlReport.InstructionStream[0],
+                        DBGKD_MAXSTREAM,
+                        0,
+                        MMDBG_COPY_UNSAFE,
+                        &InstructionCount);
+    WaitStateChange->ControlReport.InstructionCount = InstructionCount;
+
+    /* Clear all the breakpoints in this region */
+    HadBreakpoints =
+        KdpDeleteBreakpointRange((PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
+                                 (PVOID)((ULONG_PTR)WaitStateChange->ProgramCounter +
+                                         WaitStateChange->ControlReport.InstructionCount - 1));
+    if (HadBreakpoints)
+    {
+        /* Copy the instruction stream again, this time without breakpoints */
+        KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter,
+                            &WaitStateChange->ControlReport.InstructionStream[0],
+                            InstructionCount,
+                            0,
+                            MMDBG_COPY_UNSAFE,
+                            NULL);
+    }
+}
+
+VOID
+NTAPI
+KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
+{
+    /* Copy the version block */
+    RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));
+}
+
+VOID
+NTAPI
+KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
+{
+    STRING Header;
+
+    /* Fill out the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Get the version block */
+    KdpSysGetVersion(&State->u.GetVersion64);
+
+    /* Fill out the state */
+    State->ApiNumber = DbgKdGetVersionApi;
+    State->ReturnStatus = STATUS_SUCCESS;
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
+                     IN PSTRING Data,
+                     IN PCONTEXT Context)
+{
+    PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
+    STRING Header;
+    ULONG Length = ReadMemory->TransferCount;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Validate length */
+    if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
+    {
+        /* Overflow, set it to maximum possible */
+        Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
+    }
+
+    /* Do the read */
+    State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
+                                              Data->Buffer,
+                                              Length,
+                                              0,
+                                              MMDBG_COPY_UNSAFE,
+                                              &Length);
+
+    /* Return the actual length read */
+    Data->Length = ReadMemory->ActualBytesRead = Length;
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
+                      IN PSTRING Data,
+                      IN PCONTEXT Context)
+{
+    PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
+    STRING Header;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Do the write */
+    State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
+                                              Data->Buffer,
+                                              Data->Length,
+                                              0,
+                                              MMDBG_COPY_UNSAFE |
+                                              MMDBG_COPY_WRITE,
+                                              &WriteMemory->ActualBytesWritten);
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpReadPhysicalmemory(IN PDBGKD_MANIPULATE_STATE64 State,
+                      IN PSTRING Data,
+                      IN PCONTEXT Context)
+{
+    PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
+    STRING Header;
+    ULONG Length = ReadMemory->TransferCount;
+    ULONG Flags, CacheFlags;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Validate length */
+    if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
+    {
+        /* Overflow, set it to maximum possible */
+        Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
+    }
+
+    /* Start with the default flags */
+    Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL;
+
+    /* Get the caching flags and check if a type is specified */
+    CacheFlags = ReadMemory->ActualBytesRead;
+    if (CacheFlags == DBGKD_CACHING_CACHED)
+    {
+        /* Cached */
+        Flags |= MMDBG_COPY_CACHED;
+    }
+    else if (CacheFlags == DBGKD_CACHING_UNCACHED)
+    {
+        /* Uncached */
+        Flags |= MMDBG_COPY_UNCACHED;
+    }
+    else if (CacheFlags == DBGKD_CACHING_UNCACHED)
+    {
+        /* Write Combined */
+        Flags |= DBGKD_CACHING_WRITE_COMBINED;
+    }
+
+    /* Do the read */
+    State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
+                                              Data->Buffer,
+                                              Length,
+                                              0,
+                                              Flags,
+                                              &Length);
+
+    /* Return the actual length read */
+    Data->Length = ReadMemory->ActualBytesRead = Length;
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWritePhysicalmemory(IN PDBGKD_MANIPULATE_STATE64 State,
+                       IN PSTRING Data,
+                       IN PCONTEXT Context)
+{
+    PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
+    STRING Header;
+    ULONG Flags, CacheFlags;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Start with the default flags */
+    Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE | MMDBG_COPY_PHYSICAL;
+
+    /* Get the caching flags and check if a type is specified */
+    CacheFlags = WriteMemory->ActualBytesWritten;
+    if (CacheFlags == DBGKD_CACHING_CACHED)
+    {
+        /* Cached */
+        Flags |= MMDBG_COPY_CACHED;
+    }
+    else if (CacheFlags == DBGKD_CACHING_UNCACHED)
+    {
+        /* Uncached */
+        Flags |= MMDBG_COPY_UNCACHED;
+    }
+    else if (CacheFlags == DBGKD_CACHING_UNCACHED)
+    {
+        /* Write Combined */
+        Flags |= DBGKD_CACHING_WRITE_COMBINED;
+    }
+
+    /* Do the write */
+    State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
+                                              Data->Buffer,
+                                              Data->Length,
+                                              0,
+                                              Flags,
+                                              &WriteMemory->ActualBytesWritten);
+
+    /* Send the packet */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
+                    IN PSTRING Data,
+                    IN PCONTEXT Context)
+{
+    PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
+    STRING Header;
+    ULONG Length;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Check the length requested */
+    Length = ReadMemory->TransferCount;
+    if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
+    {
+        /* Use maximum allowed */
+        Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
+    }
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysReadControlSpace(State->Processor,
+                                                 ReadMemory->TargetBaseAddress,
+                                                 Data->Buffer,
+                                                 Length,
+                                                 &Length);
+
+    /* Return the actual length read */
+    Data->Length = ReadMemory->ActualBytesRead = Length;
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
+                     IN PSTRING Data,
+                     IN PCONTEXT Context)
+{
+    PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
+    STRING Header;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysWriteControlSpace(State->Processor,
+                                                  WriteMemory->TargetBaseAddress,
+                                                  Data->Buffer,
+                                                  Data->Length,
+                                                  &WriteMemory->ActualBytesWritten);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
+              IN PSTRING Data,
+              IN PCONTEXT Context)
+{
+    STRING Header;
+    PCONTEXT TargetContext;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Make sure that this is a valid request */
+    if (State->Processor < KeNumberProcessors)
+    {
+        /* Check if the request is for this CPU */
+        if (State->Processor == KeGetCurrentPrcb()->Number)
+        {
+            /* We're just copying our own context */
+            TargetContext = Context;
+        }
+        else
+        {
+            /* Get the context from the PRCB array */
+            TargetContext = &KiProcessorBlock[State->Processor]->
+                            ProcessorState.ContextFrame;
+        }
+
+        /* Copy it over to the debugger */
+        RtlCopyMemory(Data->Buffer, TargetContext, sizeof(CONTEXT));
+        Data->Length = sizeof(CONTEXT);
+
+        /* Let the debugger set the context now */
+        KdpContextSent = TRUE;
+
+        /* Finish up */
+        State->ReturnStatus = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* Invalid request */
+        State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    }
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
+              IN PSTRING Data,
+              IN PCONTEXT Context)
+{
+    STRING Header;
+    PCONTEXT TargetContext;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == sizeof(CONTEXT));
+
+    /* Make sure that this is a valid request */
+    if ((State->Processor < KeNumberProcessors) && (KdpContextSent == TRUE))
+    {
+        /* Check if the request is for this CPU */
+        if (State->Processor == KeGetCurrentPrcb()->Number)
+        {
+            /* We're just copying our own context */
+            TargetContext = Context;
+        }
+        else
+        {
+            /* Get the context from the PRCB array */
+            TargetContext = &KiProcessorBlock[State->Processor]->
+                            ProcessorState.ContextFrame;
+        }
+
+        /* Copy the new context to it */
+        RtlCopyMemory(TargetContext, Data->Buffer, sizeof(CONTEXT));
+
+        /* Finish up */
+        State->ReturnStatus = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* Invalid request */
+        State->ReturnStatus = STATUS_UNSUCCESSFUL;
+    }
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)
+{
+    /* Crash with the special code */
+    KeBugCheck(MANUALLY_INITIATED_CRASH);
+}
+
+VOID
+NTAPI
+KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
+                               IN PSTRING Data,
+                               IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_READ_WRITE_MSR ReadMsr = &State->u.ReadWriteMsr;
+    LARGE_INTEGER MsrValue;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysReadMsr(ReadMsr->Msr,
+                                        &MsrValue);
+
+    /* Return the data */
+    ReadMsr->DataValueLow = MsrValue.LowPart;
+    ReadMsr->DataValueHigh = MsrValue.HighPart;
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
+                                IN PSTRING Data,
+                                IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_READ_WRITE_MSR WriteMsr = &State->u.ReadWriteMsr;
+    LARGE_INTEGER MsrValue;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Call the internal routine */
+    MsrValue.LowPart = WriteMsr->DataValueLow;
+    MsrValue.HighPart = WriteMsr->DataValueHigh;
+    State->ReturnStatus = KdpSysWriteMsr(WriteMsr->Msr,
+                                         &MsrValue);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
+              IN PSTRING Data,
+              IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_GET_SET_BUS_DATA GetBusData = &State->u.GetSetBusData;
+    ULONG Length;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Check the length requested */
+    Length = GetBusData->Length;
+    if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
+    {
+        /* Use maximum allowed */
+        Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
+    }
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysReadBusData(GetBusData->BusDataType,
+                                            GetBusData->BusNumber,
+                                            GetBusData->SlotNumber,
+                                            GetBusData->Offset,
+                                            Data->Buffer,
+                                            Length,
+                                            &Length);
+
+    /* Return the actual length read */
+    Data->Length = GetBusData->Length = Length;
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 Data,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
+              IN PSTRING Data,
+              IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_GET_SET_BUS_DATA SetBusData = &State->u.GetSetBusData;
+    ULONG Length;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysWriteBusData(SetBusData->BusDataType,
+                                             SetBusData->BusNumber,
+                                             SetBusData->SlotNumber,
+                                             SetBusData->Offset,
+                                             Data->Buffer,
+                                             SetBusData->Length,
+                                             &Length);
+
+    /* Return the actual length written */
+    SetBusData->Length = Length;
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
+               IN PSTRING Data,
+               IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_READ_WRITE_IO64 ReadIo = &State->u.ReadWriteIo;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /*
+     * Clear the value so 1 or 2 byte reads
+     * don't leave the higher bits unmodified 
+     */
+    ReadIo->DataValue = 0;
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysReadIoSpace(Isa,
+                                            0,
+                                            1,
+                                            ReadIo->IoAddress,
+                                            &ReadIo->DataValue,
+                                            ReadIo->DataSize,
+                                            &ReadIo->DataSize);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
+                IN PSTRING Data,
+                IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_READ_WRITE_IO64 WriteIo = &State->u.ReadWriteIo;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysWriteIoSpace(Isa,
+                                             0,
+                                             1,
+                                             WriteIo->IoAddress,
+                                             &WriteIo->DataValue,
+                                             WriteIo->DataSize,
+                                             &WriteIo->DataSize);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
+                       IN PSTRING Data,
+                       IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_READ_WRITE_IO_EXTENDED64 ReadIoExtended = &State->u.
+                                                      ReadWriteIoExtended;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /*
+     * Clear the value so 1 or 2 byte reads
+     * don't leave the higher bits unmodified 
+     */
+    ReadIoExtended->DataValue = 0;
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysReadIoSpace(ReadIoExtended->InterfaceType,
+                                            ReadIoExtended->BusNumber,
+                                            ReadIoExtended->AddressSpace,
+                                            ReadIoExtended->IoAddress,
+                                            &ReadIoExtended->DataValue,
+                                            ReadIoExtended->DataSize,
+                                            &ReadIoExtended->DataSize);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
+                        IN PSTRING Data,
+                        IN PCONTEXT Context)
+{
+    STRING Header;
+    PDBGKD_READ_WRITE_IO_EXTENDED64 WriteIoExtended = &State->u.
+                                                       ReadWriteIoExtended;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+    ASSERT(Data->Length == 0);
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysReadIoSpace(WriteIoExtended->InterfaceType,
+                                            WriteIoExtended->BusNumber,
+                                            WriteIoExtended->AddressSpace,
+                                            WriteIoExtended->IoAddress,
+                                            &WriteIoExtended->DataValue,
+                                            WriteIoExtended->DataSize,
+                                            &WriteIoExtended->DataSize);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)
+{
+    STRING Header;
+
+    /* Setup the header */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Call the internal routine */
+    State->ReturnStatus = KdpSysCheckLowMemory(MMDBG_COPY_UNSAFE);
+
+    /* Send the reply */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+VOID
+NTAPI
+KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)
+{
+    STRING Header;
+
+    /* Set failure */
+    State->ReturnStatus = STATUS_UNSUCCESSFUL;
+
+    /* Setup the packet */
+    Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)State;
+
+    /* Send it */
+    KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                 &Header,
+                 NULL,
+                 &KdpContext);
+}
+
+KCONTINUE_STATUS
+NTAPI
+KdpSendWaitContinue(IN ULONG PacketType,
+                    IN PSTRING SendHeader,
+                    IN PSTRING SendData OPTIONAL,
+                    IN OUT PCONTEXT Context)
+{
+    STRING Data, Header;
+    DBGKD_MANIPULATE_STATE64 ManipulateState;
+    ULONG Length;
+    KDSTATUS RecvCode;
+
+    /* Setup the Manipulate State structure */
+    Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
+    Header.Buffer = (PCHAR)&ManipulateState;
+    Data.MaximumLength = sizeof(KdpMessageBuffer);
+    Data.Buffer = KdpMessageBuffer;
+
+    /* 
+     * Reset the context state to ensure the debugger has received
+     * the current context before it sets it
+     */
+    KdpContextSent = FALSE;
+
+SendPacket:
+    /* Send the Packet */
+    KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
+
+    /* If the debugger isn't present anymore, just return success */
+    if (KdDebuggerNotPresent) return ContinueSuccess;
+
+    /* Main processing Loop */
+    for (;;)
+    {
+        /* Receive Loop */
+        do
+        {
+            /* Wait to get a reply to our packet */
+            RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                                       &Header,
+                                       &Data,
+                                       &Length,
+                                       &KdpContext);
+
+            /* If we got a resend request, do it */
+            if (RecvCode == KdPacketNeedsResend) goto SendPacket;
+        } while (RecvCode == KdPacketTimedOut);
+
+        /* Now check what API we got */
+        switch (ManipulateState.ApiNumber)
+        {
+            case DbgKdReadVirtualMemoryApi:
+
+                /* Read virtual memory */
+                KdpReadVirtualMemory(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWriteVirtualMemoryApi:
+
+                /* Write virtual memory */
+                KdpWriteVirtualMemory(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdGetContextApi:
+
+                /* Get the current context */
+                KdpGetContext(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdSetContextApi:
+
+                /* Set a new context */
+                KdpSetContext(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWriteBreakPointApi:
+
+                /* Write the breakpoint */
+                KdpWriteBreakpoint(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdRestoreBreakPointApi:
+
+                /* Restore the breakpoint */
+                KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdContinueApi:
+
+                /* Simply continue */
+                return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
+
+            case DbgKdReadControlSpaceApi:
+
+                /* Read control space */
+                KdpReadControlSpace(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWriteControlSpaceApi:
+
+                /* Write control space */
+                KdpWriteControlSpace(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdReadIoSpaceApi:
+
+                /* Read I/O Space */
+                KdpReadIoSpace(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWriteIoSpaceApi:
+
+                /* Write I/O Space */
+                KdpWriteIoSpace(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdRebootApi:
+
+                /* Reboot the system */
+                HalReturnToFirmware(HalRebootRoutine);
+                break;
+
+            case DbgKdContinueApi2:
+
+                /* Check if caller reports success */
+                if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
+                {
+                    /* Update the state */
+                    KdpGetStateChange(&ManipulateState, Context);
+                    return ContinueSuccess;
+                }
+                else
+                {
+                    /* Return an error */
+                    return ContinueError;
+                }
+
+            case DbgKdReadPhysicalMemoryApi:
+
+                /* Read  physical memory */
+                KdpReadPhysicalmemory(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWritePhysicalMemoryApi:
+
+                /* Write  physical memory */
+                KdpWritePhysicalmemory(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdQuerySpecialCallsApi:
+            case DbgKdSetSpecialCallApi:
+            case DbgKdClearSpecialCallsApi:
+
+                /* TODO */
+                KdpDprintf("Special Call support is unimplemented!\n");
+                KdpNotSupported(&ManipulateState);
+                break;
+
+            case DbgKdSetInternalBreakPointApi:
+            case DbgKdGetInternalBreakPointApi:
+
+                /* TODO */
+                KdpDprintf("Internal Breakpoint support is unimplemented!\n");
+                KdpNotSupported(&ManipulateState);
+                break;
+
+            case DbgKdReadIoSpaceExtendedApi:
+
+                /* Read I/O Space */
+                KdpReadIoSpaceExtended(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWriteIoSpaceExtendedApi:
+
+                /* Write I/O Space */
+                KdpWriteIoSpaceExtended(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdGetVersionApi:
+
+                /* Get version data */
+                KdpGetVersion(&ManipulateState);
+                break;
+
+            case DbgKdWriteBreakPointExApi:
+
+                /* Write the breakpoint and check if it failed */
+                if (!NT_SUCCESS(KdpWriteBreakPointEx(&ManipulateState,
+                                                     &Data,
+                                                     Context)))
+                {
+                    /* Return an error */
+                    return ContinueError;
+                }
+                break;
+
+            case DbgKdRestoreBreakPointExApi:
+
+                /* Restore the breakpoint */
+                KdpRestoreBreakPointEx(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdCauseBugCheckApi:
+
+                /* Crash the system */
+                KdpCauseBugCheck(&ManipulateState);
+                break;
+
+            case DbgKdSwitchProcessor:
+
+                /* TODO */
+                KdpDprintf("Processor Switch support is unimplemented!\n");
+                KdpNotSupported(&ManipulateState);
+                break;
+
+            case DbgKdPageInApi:
+
+                /* TODO */
+                KdpDprintf("Page-In support is unimplemented!\n");
+                KdpNotSupported(&ManipulateState);
+                break;
+
+            case DbgKdReadMachineSpecificRegister:
+
+                /* Read from the specified MSR */
+                KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdWriteMachineSpecificRegister:
+
+                /* Write to the specified MSR */
+                KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdSearchMemoryApi:
+
+                /* Search memory */
+                KdpSearchMemory(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdGetBusDataApi:
+
+                /* Read from the bus */
+                KdpGetBusData(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdSetBusDataApi:
+
+                /* Write to the bus */
+                KdpSetBusData(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdCheckLowMemoryApi:
+
+                /* Check for memory corruption in the lower 4 GB */
+                KdpCheckLowMemory(&ManipulateState);
+                break;
+
+            case DbgKdClearAllInternalBreakpointsApi:
+
+                /* Just clear the counter */
+                KdpNumInternalBreakpoints = 0;
+                break;
+
+            case DbgKdFillMemoryApi:
+
+                /* Fill memory */
+                KdpFillMemory(&ManipulateState, &Data, Context);
+                break;
+
+            case DbgKdQueryMemoryApi:
+
+                /* Query memory */
+                KdpQueryMemory(&ManipulateState, Context);
+                break;
+
+            case DbgKdSwitchPartition:
+
+                /* TODO */
+                KdpDprintf("Partition Switch support is unimplemented!\n");
+                KdpNotSupported(&ManipulateState);
+                break;
+
+            /* Unsupported Message */
+            default:
+
+                /* Setup an empty message, with failure */
+                KdpDprintf("Received Unhandled API %lx\n", ManipulateState.ApiNumber);
+                Data.Length = 0;
+                ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
+
+                /* Send it */
+                KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+                             &Header,
+                             &Data,
+                             &KdpContext);
+                break;
+        }
+    }
+}
+
+VOID
+NTAPI
+KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
+                                IN PKD_SYMBOLS_INFO SymbolInfo,
+                                IN BOOLEAN Unload,
+                                IN OUT PCONTEXT Context)
+{
+    PSTRING ExtraData;
+    STRING Data, Header;
+    DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
+    ULONG PathNameLength;
+    KCONTINUE_STATUS Status;
+
+    /* Start wait loop */
+    do
+    {
+        /* Build the architecture common parts of the message */
+        KdpSetCommonState(DbgKdLoadSymbolsStateChange,
+                          Context,
+                          &WaitStateChange);
+
+        /* Now finish creating the structure */
+        KdpSetContextState(&WaitStateChange, Context);
+
+        /* Fill out load data */
+        WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
+        WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll;
+        WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
+        WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
+        WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
+
+        /* Check if we have a path name */
+        if (PathName)
+        {
+            /* Copy it to the path buffer */
+            KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer,
+                                KdpPathBuffer,
+                                PathName->Length,
+                                0,
+                                MMDBG_COPY_UNSAFE,
+                                &PathNameLength);
+
+            /* Null terminate */
+            KdpPathBuffer[PathNameLength++] = ANSI_NULL;
+
+            /* Set the path length */
+            WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
+
+            /* Set up the data */
+            Data.Buffer = KdpPathBuffer;
+            Data.Length = PathNameLength;
+            ExtraData = &Data;
+        }
+        else
+        {
+            /* No name */
+            WaitStateChange.u.LoadSymbols.PathNameLength = 0;
+            ExtraData = NULL;
+        }
+
+        /* Setup the header */
+        Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
+        Header.Buffer = (PCHAR)&WaitStateChange;
+
+        /* Send the packet */
+        Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
+                                     &Header,
+                                     ExtraData,
+                                     Context);
+    } while (Status == ContinueProcessorReselected);
+}
+
+VOID
+NTAPI
+KdpReportCommandStringStateChange(IN PSTRING NameString,
+                                  IN PSTRING CommandString,
+                                  IN OUT PCONTEXT Context)
+{
+    STRING Header, Data;
+    DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
+    ULONG Length, ActualLength, TotalLength;
+    KCONTINUE_STATUS Status;
+
+    /* Start wait loop */
+    do
+    {
+        /* Build the architecture common parts of the message */
+        KdpSetCommonState(DbgKdCommandStringStateChange,
+                          Context,
+                          &WaitStateChange);
+
+        /* Set the context */
+        KdpSetContextState(&WaitStateChange, Context);
+
+        /* Clear the command string structure */
+        RtlZeroMemory(&WaitStateChange.u.CommandString,
+                      sizeof(DBGKD_COMMAND_STRING));
+
+        /* Normalize name string to max */
+        Length = min(128 - 1, NameString->Length);
+
+        /* Copy it to the message buffer */
+        KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer,
+                            KdpMessageBuffer,
+                            Length,
+                            0,
+                            MMDBG_COPY_UNSAFE,
+                            &ActualLength);
+
+        /* Null terminate and calculate the total length */
+        TotalLength = ActualLength;
+        KdpMessageBuffer[TotalLength++] = ANSI_NULL;
+
+        /* Check if the command string is too long */
+        Length = CommandString->Length;
+        if (Length > (PACKET_MAX_SIZE -
+                      sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength))
+        {
+            /* Use maximum possible size */
+            Length = (PACKET_MAX_SIZE -
+                      sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength);
+        }
+
+        /* Copy it to the message buffer */
+        KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer,
+                            KdpMessageBuffer + TotalLength,
+                            Length,
+                            0,
+                            MMDBG_COPY_UNSAFE,
+                            &ActualLength);
+
+        /* Null terminate and calculate the total length */
+        TotalLength += ActualLength;
+        KdpMessageBuffer[TotalLength++] = ANSI_NULL;
+
+        /* Now set up the header and the data */
+        Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
+        Header.Buffer = (PCHAR)&WaitStateChange;
+        Data.Length = TotalLength;
+        Data.Buffer = KdpMessageBuffer;
+
+        /* Send State Change packet and wait for a reply */
+        Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
+                                     &Header,
+                                     &Data,
+                                     Context);
+    } while (Status == ContinueProcessorReselected);
+}
+
+BOOLEAN
+NTAPI
+KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
+                              IN OUT PCONTEXT Context,
+                              IN BOOLEAN SecondChanceException)
+{
+    STRING Header, Data;
+    DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
+    KCONTINUE_STATUS Status;
+
+    /* Start report loop */
+    do
+    {
+        /* Build the architecture common parts of the message */
+        KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
+
+        /* Copy the Exception Record and set First Chance flag */
+#if !defined(_WIN64)
+        ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
+                              &WaitStateChange.u.Exception.ExceptionRecord);
+#else
+        RtlCopyMemory(&WaitStateChange.u.Exception.ExceptionRecord,
+                      ExceptionRecord,
+                      sizeof(EXCEPTION_RECORD));
+#endif
+        WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
+
+        /* Now finish creating the structure */
+        KdpSetContextState(&WaitStateChange, Context);
+
+        /* Setup the actual header to send to KD */
+        Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
+        Header.Buffer = (PCHAR)&WaitStateChange;
+
+        /* Setup the trace data */
+        DumpTraceData(&Data);
+
+        /* Send State Change packet and wait for a reply */
+        Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
+                                     &Header,
+                                     &Data,
+                                     Context);
+    } while (Status == ContinueProcessorReselected);
+
+    /* Return */
+    return Status;
+}
+
+VOID
+NTAPI
+KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
+                      IN PVOID DeferredContext,
+                      IN PVOID SystemArgument1,
+                      IN PVOID SystemArgument2)
+{
+    LONG OldSlip, NewSlip, PendingSlip;
+
+    /* Get the current pending slip */
+    PendingSlip = KdpTimeSlipPending;
+    do
+    {
+        /* Save the old value and either disable or enable it now. */
+        OldSlip = PendingSlip;
+        NewSlip = OldSlip > 1 ? 1 : 0;
+
+        /* Try to change the value */
+    } while (InterlockedCompareExchange(&KdpTimeSlipPending,
+                                        NewSlip,
+                                        OldSlip) != OldSlip);
+
+    /* If the New Slip value is 1, then do the Time Slipping */
+    if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
+}
+
+VOID
+NTAPI
+KdpTimeSlipWork(IN PVOID Context)
+{
+    KIRQL OldIrql;
+    LARGE_INTEGER DueTime;
+
+    /* Update the System time from the CMOS */
+    ExAcquireTimeRefreshLock(FALSE);
+    ExUpdateSystemTimeFromCmos(FALSE, 0);
+    ExReleaseTimeRefreshLock();
+
+    /* Check if we have a registered Time Slip Event and signal it */
+    KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
+    if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
+    KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
+
+    /* Delay the DPC until it runs next time */
+    DueTime.QuadPart = -1800000000;
+    KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
+}
+
+BOOLEAN
+NTAPI
+KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
+                   IN OUT PCONTEXT ContextRecord,
+                   IN BOOLEAN SecondChanceException)
+{
+    BOOLEAN Status;
+
+    /* Save the port data */
+    KdSave(FALSE);
+
+    /* Report a state change */
+    Status = KdpReportExceptionStateChange(ExceptionRecord,
+                                           ContextRecord,
+                                           SecondChanceException);
+
+    /* Restore the port data and return */
+    KdRestore(FALSE);
+    return Status;
+}
+
+LARGE_INTEGER
+NTAPI
+KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
+{
+    LARGE_INTEGER Null = {{0}};
+
+    /* Check if interrupts were disabled */
+    if (!KeGetTrapFrameInterruptState(TrapFrame))
+    {
+        /* Nothing to return */
+        return Null;
+    }
+
+    /* Otherwise, do the call */
+    return KeQueryPerformanceCounter(NULL);
+}
+
+NTSTATUS
+NTAPI
+KdpAllowDisable(VOID)
+{
+    /* Check if we are on MP */
+    if (KeNumberProcessors > 1)
+    {
+        /* TODO */
+        KdpDprintf("KdpAllowDisable: SMP UNHANDLED\n");
+        while (TRUE);
+    }
+
+    /* Allow disable */
+    return STATUS_SUCCESS;
+}
+
+BOOLEAN
+NTAPI
+KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
+                IN PKEXCEPTION_FRAME ExceptionFrame)
+{
+    BOOLEAN Entered;
+
+    /* Check if we have a trap frame */
+    if (TrapFrame)
+    {
+        /* Calculate the time difference for the enter */
+        KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
+        KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
+                                     KdTimerStart.QuadPart;
+    }
+    else
+    {
+        /* No trap frame, so can't calculate */
+        KdTimerStop.QuadPart = 0;
+    }
+
+    /* Save the current IRQL */
+    KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
+
+    /* Freeze all CPUs */
+    Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
+
+    /* Lock the port, save the state and set debugger entered */
+    KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
+    KdSave(FALSE);
+    KdEnteredDebugger = TRUE;
+
+    /* Check freeze flag */
+    if (KiFreezeFlag & 1)
+    {
+        /* Print out errror */
+        KdpDprintf("FreezeLock was jammed!  Backup SpinLock was used!\n");
+    }
+
+    /* Check processor state */
+    if (KiFreezeFlag & 2)
+    {
+        /* Print out errror */
+        KdpDprintf("Some processors not frozen in debugger!\n");
+    }
+
+    /* Make sure we acquired the port */
+    if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
+
+    /* Return enter state */
+    return Entered;
+}
+
+VOID
+NTAPI
+KdExitDebugger(IN BOOLEAN Entered)
+{
+    ULONG TimeSlip;
+
+    /* Restore the state and unlock the port */
+    KdRestore(FALSE);
+    if (KdpPortLocked) KdpPortUnlock();
+
+    /* Unfreeze the CPUs */
+    KeThawExecution(Entered);
+
+    /* Compare time with the one from KdEnterDebugger */
+    if (!KdTimerStop.QuadPart)
+    {
+        /* We didn't get a trap frame earlier in so never got the time */
+        KdTimerStart = KdTimerStop;
+    }
+    else
+    {
+        /* Query the timer */
+        KdTimerStart = KeQueryPerformanceCounter(NULL);
+    }
+
+    /* Check if a Time Slip was on queue */
+    TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
+    if (TimeSlip == 1)
+    {
+        /* Queue a DPC for the time slip */
+        InterlockedIncrement(&KdpTimeSlipPending);
+        KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
+    }
+}
+
+NTSTATUS
+NTAPI
+KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
+{
+    KIRQL OldIrql;
+
+#if defined(__GNUC__)
+    /* Make gcc happy */
+    OldIrql = PASSIVE_LEVEL;
+#endif
+
+    /* Check if enabling the debugger is blocked */
+    if (KdBlockEnable)
+    {
+        /* It is, fail the enable */
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Check if we need to acquire the lock */
+    if (NeedLock)
+    {
+        /* Lock the port */
+        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+        KdpPortLock();
+    }
+
+    /* Check if we're not disabled */
+    if (!KdDisableCount)
+    {
+        /* Check if we had locked the port before */
+        if (NeedLock)
+        {
+            /* Do the unlock */
+            KeLowerIrql(OldIrql);
+            KdpPortUnlock();
+
+            /* Fail: We're already enabled */
+            return STATUS_INVALID_PARAMETER;
+        }
+        else
+        {
+            /*
+             * This can only happen if we are called from a bugcheck
+             * and were never initialized, so initialize the debugger now.
+             */
+            KdInitSystem(0, NULL);
+
+            /* Return success since we initialized */
+            return STATUS_SUCCESS;
+        }
+    }
+
+    /* Decrease the disable count */
+    if (!(--KdDisableCount))
+    {
+        /* We're now enabled again! Were we enabled before, too? */
+        if (KdPreviouslyEnabled)
+        {
+            /* Reinitialize the Debugger */
+            KdInitSystem(0, NULL) ;
+            KdpRestoreAllBreakpoints();
+        }
+    }
+
+    /* Check if we had locked the port before */
+    if (NeedLock)
+    {
+        /* Yes, now unlock it */
+        KeLowerIrql(OldIrql);
+        KdpPortUnlock();
+    }
+
+    /* We're done */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
+{
+    KIRQL OldIrql;
+    NTSTATUS Status;
+
+#if defined(__GNUC__)
+    /* Make gcc happy */
+    OldIrql = PASSIVE_LEVEL;
+#endif
+
+    /*
+     * If enabling the debugger is blocked
+     * then there is nothing to disable (duh)
+     */
+    if (KdBlockEnable)
+    {
+        /* Fail */
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Check if we need to acquire the lock */
+    if (NeedLock)
+    {
+        /* Lock the port */
+        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+        KdpPortLock();
+    }
+
+    /* Check if we're not disabled */
+    if (!KdDisableCount)
+    {
+        /* Check if the debugger was never actually initialized */
+        if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
+        {
+            /* It wasn't, so don't re-enable it later */
+            KdPreviouslyEnabled = FALSE;
+        }
+        else
+        {
+            /* It was, so we will re-enable it later */
+            KdPreviouslyEnabled = TRUE;
+        }
+
+        /* Check if we were called from the exported API and are enabled */
+        if ((NeedLock) && (KdPreviouslyEnabled))
+        {
+            /* Check if it is safe to disable the debugger */
+            Status = KdpAllowDisable();
+            if (!NT_SUCCESS(Status))
+            {
+                /* Release the lock and fail */
+                KeLowerIrql(OldIrql);
+                KdpPortUnlock();
+                return Status;
+            }
+        }
+
+        /* Only disable the debugger if it is enabled */
+        if (KdDebuggerEnabled)
+        {
+            /*
+             * Disable the debugger; suspend breakpoints
+             * and reset the debug stub
+             */
+            KdpSuspendAllBreakPoints();
+            KiDebugRoutine = KdpStub;
+
+            /* We are disabled now */
+            KdDebuggerEnabled = FALSE;
+#undef KdDebuggerEnabled
+            SharedUserData->KdDebuggerEnabled = FALSE;
+#define KdDebuggerEnabled _KdDebuggerEnabled
+        }
+     }
+
+    /* Increment the disable count */
+    KdDisableCount++;
+
+    /* Check if we had locked the port before */
+    if (NeedLock)
+    {
+        /* Yes, now unlock it */
+        KeLowerIrql(OldIrql);
+        KdpPortUnlock();
+    }
+
+    /* We're done */
+    return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KdEnableDebugger(VOID)
+{
+    /* Use the internal routine */
+    return KdEnableDebuggerWithLock(TRUE);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KdDisableDebugger(VOID)
+{
+    /* Use the internal routine */
+    return KdDisableDebuggerWithLock(TRUE);
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KdSystemDebugControl(IN SYSDBG_COMMAND Command,
+                     IN PVOID InputBuffer,
+                     IN ULONG InputBufferLength,
+                     OUT PVOID OutputBuffer,
+                     IN ULONG OutputBufferLength,
+                     IN OUT PULONG ReturnLength,
+                     IN KPROCESSOR_MODE PreviousMode)
+{
+    /* Local kernel debugging is not yet supported */
+    DbgPrint("KdSystemDebugControl is unimplemented!\n");
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KdChangeOption(IN KD_OPTION Option,
+               IN ULONG InBufferBytes OPTIONAL,
+               IN PVOID InBuffer,
+               IN ULONG OutBufferBytes OPTIONAL,
+               OUT PVOID OutBuffer,
+               OUT PULONG OutBufferNeeded OPTIONAL)
+{
+    /* Fail if there is no debugger */
+    if (KdPitchDebugger)
+    {
+        /* No debugger, no options */
+        return STATUS_DEBUGGER_INACTIVE;
+    }
+
+    /* Do we recognize this option? */
+    if (Option != KD_OPTION_SET_BLOCK_ENABLE)
+    {
+        /* We don't, clear the output length and fail */
+        if (OutBufferNeeded) *OutBufferNeeded = 0;
+        return STATUS_INVALID_INFO_CLASS;
+    }
+
+    /* Verify parameters */
+    if ((InBufferBytes != sizeof(BOOLEAN)) ||
+        (OutBufferBytes != 0) ||
+        (OutBuffer != NULL))
+    {
+        /* Invalid parameters for this option, fail */
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /*
+     * Check if the high bit is set, meaning we don't
+     * allow the debugger to be enabled
+     */
+    if (KdBlockEnable & 0x80)
+    {
+        /* Fail regardless of what state the caller tried to set */
+        return STATUS_ACCESS_VIOLATION;
+    }
+
+    /* Set the new block enable state */
+    KdBlockEnable = *(PBOOLEAN)InBuffer;
+
+    /* No output buffer required for this option */
+    if (OutBufferNeeded) *OutBufferNeeded = 0;
+
+    /* We are done */
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KdPowerTransition(IN DEVICE_POWER_STATE NewState)
+{
+    /* Check what power state this is */
+    if (NewState == PowerDeviceD0)
+    {
+        /* Wake up the debug port */
+        KdD0Transition();
+        return STATUS_SUCCESS;
+    }
+    else if ((NewState == PowerDeviceD1) ||
+             (NewState == PowerDeviceD2) ||
+             (NewState == PowerDeviceD3))
+    {
+        /* Power down the debug port */
+        KdD3Transition();
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        /* Invalid state! */
+        return STATUS_INVALID_PARAMETER_1;
+    }
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+KdRefreshDebuggerNotPresent(VOID)
+{
+    BOOLEAN Entered, DebuggerNotPresent;
+
+    /* Check if the debugger is completely disabled */
+    if (KdPitchDebugger)
+    {
+        /* Don't try to refresh then -- fail early */
+        return TRUE;
+    }
+
+    /* Enter the debugger */
+    Entered = KdEnterDebugger(NULL, NULL);
+
+    /*
+     * Attempt to send a string to the debugger to refresh the
+     * connection state
+     */
+    KdpDprintf("KDTARGET: Refreshing KD connection\n");
+
+    /* Save the state while we are holding the lock */
+    DebuggerNotPresent = KdDebuggerNotPresent;
+
+    /* Exit the debugger and return the state */
+    KdExitDebugger(Entered);
+    return DebuggerNotPresent;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtQueryDebugFilterState(IN ULONG ComponentId,
+                        IN ULONG Level)
+{
+    PULONG Mask;
+
+    /* Check if the ID fits in the component table */
+    if (ComponentId < KdComponentTableSize)
+    {
+        /* It does, so get the mask from there */
+        Mask = KdComponentTable[ComponentId];
+    }
+    else if (ComponentId == MAXULONG)
+    {
+        /*
+         * This is the internal ID used for DbgPrint messages without ID and
+         * Level. Use the system-wide mask for those.
+         */
+        Mask = &Kd_WIN2000_Mask;
+    }
+    else
+    {
+        /* Invalid ID, fail */
+        return STATUS_INVALID_PARAMETER_1;
+    }
+
+    /* Convert Level to bit field if necessary */
+    if (Level < 32) Level = 1 << Level;
+
+    /* Determine if this Level is filtered out */
+    if ((Kd_WIN2000_Mask & Level) ||
+        (*Mask & Level))
+    {
+        /* This mask will get through to the debugger */
+        return (NTSTATUS)TRUE;
+    }
+    else
+    {
+        /* This mask is filtered out */
+        return (NTSTATUS)FALSE;
+    }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtSetDebugFilterState(IN ULONG ComponentId,
+                      IN ULONG Level,
+                      IN BOOLEAN State)
+{
+    PULONG Mask;
+
+    /* Modifying debug filters requires the debug privilege */
+    if (!SeSinglePrivilegeCheck(SeDebugPrivilege,
+                                ExGetPreviousMode()))
+    {
+        /* Fail */
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Check if the ID fits in the component table */
+    if (ComponentId < KdComponentTableSize)
+    {
+        /* It does, so get the mask from there */
+        Mask = KdComponentTable[ComponentId];
+    }
+    else if (ComponentId == MAXULONG)
+    {
+        /*
+         * This is the internal ID used for DbgPrint messages without ID and
+         * Level. Use the system-wide mask for those.
+         */
+        Mask = &Kd_WIN2000_Mask;
+    }
+    else
+    {
+        /* Invalid ID, fail */
+        return STATUS_INVALID_PARAMETER_1;
+    }
+
+    /* Convert Level to bit field if required */
+    if (Level < 32) Level = 1 << Level;
+
+    /* Check what kind of operation this is */
+    if (State)
+    {
+        /* Set the Level */
+        *Mask |= Level;
+    }
+    else
+    {
+        /* Remove the Level */
+        *Mask &= ~Level;
+    }
+
+    /* Success */
+    return STATUS_SUCCESS;
+}