-/*\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(IN 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
- IN 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 = (ULONG)(LONG_PTR)KeGetCurrentThread();\r
-#if defined(_M_X86_)\r
- WaitStateChange->ProgramCounter = (ULONG)(LONG_PTR)Context->Eip;\r
-#elif defined(_AMD64)\r
- WaitStateChange->ProgramCounter = (ULONG)(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
- /* 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
- 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
-\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);\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
-\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
-\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)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+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)
+{
+ /* FIXME: STUB */
+ KdpDprintf("KdpSearchMemory called\n");
+ while (TRUE);
+}
+
+VOID
+NTAPI
+KdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State,
+ IN PSTRING Data,
+ IN PCONTEXT Context)
+{
+ /* FIXME: STUB */
+ KdpDprintf("KdpFillMemory called\n");
+ while (TRUE);
+}
+
+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)
+{
+ /* FIXME: STUB */
+ KdpDprintf("KdpWriteBreakPointEx called\n");
+ while (TRUE);
+ return STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+KdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
+ IN PSTRING Data,
+ IN PCONTEXT Context)
+{
+ /* FIXME: STUB */
+ KdpDprintf("KdpRestoreBreakPointEx called\n");
+ while (TRUE);
+}
+
+VOID
+NTAPI
+DumpTraceData(OUT 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,
+ OUT PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)
+{
+ USHORT 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 Control Report */
+ RtlZeroMemory(&WaitStateChange->ControlReport,
+ sizeof(DBGKD_CONTROL_REPORT));
+
+ /* Now copy the instruction stream and set the count */
+ RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
+ (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
+ DBGKD_MAXSTREAM);
+ InstructionCount = DBGKD_MAXSTREAM;
+ 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 */
+ RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
+ (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
+ WaitStateChange->ControlReport.InstructionCount);
+ }
+}
+
+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)
+{
+ STRING Header;
+ ULONG Length = State->u.ReadMemory.TransferCount;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG64 TargetBaseAddress = State->u.ReadMemory.TargetBaseAddress;
+
+ /* 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);
+ }
+
+#if 0
+ if (!MmIsAddressValid((PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress))
+ {
+ KdpDprintf("Tried to read invalid address %p\n",
+ (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress);
+ while (TRUE);
+ }
+#endif
+
+ // HACK for x64, until KD stops sending bogus addresses to WinDbg
+ if (TargetBaseAddress < (ULONG_PTR)MM_LOWEST_SYSTEM_ADDRESS)
+ {
+ FrLdrDbgPrint("Trying to read memory at 0x%p\n", TargetBaseAddress);
+// DPRINT1("Trying to read memory at 0x%p\n", TargetBaseAddress);
+ TargetBaseAddress = 0;
+ }
+
+ if (!TargetBaseAddress)
+ {
+ Length = 0;
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ RtlCopyMemory(Data->Buffer,
+ (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,
+ Length);
+ }
+
+ /* Fill out the header */
+ Data->Length = Length;
+ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+ Header.Buffer = (PCHAR)State;
+
+ /* Fill out the state */
+ State->ReturnStatus = Status;
+ State->u.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)
+{
+ /* FIXME: STUB */
+ KdpDprintf("KdpWriteVirtualMemory called for Address: %p Length %x\n",
+ (PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,
+ State->u.ReadMemory.TransferCount);
+ while (TRUE);
+}
+
+VOID
+NTAPI
+KdpReadPhysicalmemory(IN PDBGKD_MANIPULATE_STATE64 State,
+ IN PSTRING Data,
+ IN PCONTEXT Context)
+{
+ STRING Header;
+
+ /* FIXME: STUB */
+ KdpDprintf("KdpWritePhysicalMemory called for Address %I64x Length: %x\n",
+ State->u.ReadMemory.TargetBaseAddress,
+ State->u.ReadMemory.TransferCount);
+
+ /* Setup an empty message, with failure */
+ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+ Header.Buffer = (PCHAR)State;
+ Data->Length = 0;
+ State->ReturnStatus = STATUS_UNSUCCESSFUL;
+
+ /* Send it */
+ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+ &Header,
+ Data,
+ &KdpContext);
+}
+
+VOID
+NTAPI
+KdpWritePhysicalmemory(IN PDBGKD_MANIPULATE_STATE64 State,
+ IN PSTRING Data,
+ IN PCONTEXT Context)
+{
+ STRING Header;
+
+ /* FIXME: STUB */
+ KdpDprintf("KdpWritePhysicalMemory called for Address %I64x Length: %x\n",
+ State->u.ReadMemory.TargetBaseAddress,
+ State->u.ReadMemory.TransferCount);
+
+ /* Setup an empty message, with failure */
+ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
+ Header.Buffer = (PCHAR)State;
+ Data->Length = 0;
+ State->ReturnStatus = STATUS_UNSUCCESSFUL;
+
+ /* Send it */
+ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+ &Header,
+ Data,
+ &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;
+ ULONG Length;
+
+ /* 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,
+ &Length);
+
+ /* Return the length written */
+ WriteMemory->ActualBytesWritten = Length;
+
+ /* 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;
+ PVOID ControlStart;
+
+ /* 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 */
+ ControlStart = Context;
+ }
+ else
+ {
+ /* SMP not yet handled */
+ KdpDprintf("SMP UNHANDLED\n");
+ ControlStart = NULL;
+ while (TRUE);
+ }
+
+ /* Copy the memory */
+ RtlCopyMemory(Data->Buffer, ControlStart, sizeof(CONTEXT));
+ Data->Length = 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,
+ Data,
+ &KdpContext);
+}
+
+VOID
+NTAPI
+KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
+ IN PSTRING Data,
+ IN PCONTEXT Context)
+{
+ STRING Header;
+ PVOID ControlStart;
+
+ /* 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)
+ {
+ /* Check if the request is for this CPU */
+ if (State->Processor == KeGetCurrentPrcb()->Number)
+ {
+ /* We're just copying our own context */
+ ControlStart = Context;
+ }
+ else
+ {
+ /* SMP not yet handled */
+ KdpDprintf("SMP UNHANDLED\n");
+ ControlStart = NULL;
+ while (TRUE);
+ }
+
+ /* Copy the memory */
+ RtlCopyMemory(ControlStart, 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,
+ Data,
+ &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,
+ Data->Buffer,
+ GetBusData->Offset,
+ 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,
+ Data->Buffer,
+ SetBusData->Offset,
+ SetBusData->Length,
+ &Length);
+
+ /* Return the actual length written */
+ SetBusData->Length = Length;
+
+ /* Send the reply */
+ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
+ &Header,
+ Data,
+ &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(0x4);
+
+ /* Send the reply */
+ 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;
+ //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:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdQuerySpecialCallsApi called\n");
+ while (TRUE);
+ break;
+
+ case DbgKdSetSpecialCallApi:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdSetSpecialCallApi called\n");
+ while (TRUE);
+ break;
+
+ case DbgKdClearSpecialCallsApi:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdClearSpecialCallsApi called\n");
+ while (TRUE);
+ break;
+
+ case DbgKdSetInternalBreakPointApi:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdSetInternalBreakPointApi called\n");
+ while (TRUE);
+ break;
+
+ case DbgKdGetInternalBreakPointApi:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdGetInternalBreakPointApi called\n");
+ while (TRUE);
+ 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:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdSwitchProcessor called\n");
+ while (TRUE);
+ break;
+
+ case DbgKdPageInApi:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdPageInApi called\n");
+ while (TRUE);
+ 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:
+
+ /* FIXME: TODO */
+ KdpDprintf("DbgKdSwitchPartition called\n");
+ while (TRUE);
+ 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;
+ }
+ }
+}
+
+BOOLEAN
+NTAPI
+KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
+ IN PKD_SYMBOLS_INFO SymbolInfo,
+ IN BOOLEAN Unload,
+ IN OUT PCONTEXT Context)
+{
+ PSTRING ExtraData;
+ STRING Data, Header;
+ DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
+ 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 symbol name */
+ if (PathName)
+ {
+ /* Setup the information */
+ WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
+ RtlCopyMemory(KdpPathBuffer, PathName->Buffer, PathName->Length);
+ Data.Buffer = KdpPathBuffer;
+ Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
+ ExtraData = &Data;
+ }
+ else
+ {
+ /* No name */
+ WaitStateChange.u.LoadSymbols.PathNameLength = 0;
+ ExtraData = NULL;
+ }
+
+ /* Setup the header */
+ Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
+ Header.Buffer = (PCHAR)&WaitStateChange;
+
+ /* Send the packet */
+ Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
+ &Header,
+ ExtraData,
+ Context);
+ } while (Status == ContinueProcessorReselected);
+
+ /* Return status */
+ return Status;
+}
+
+BOOLEAN
+NTAPI
+KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
+ IN OUT PCONTEXT Context,
+ IN BOOLEAN SecondChanceException)
+{
+ STRING Header, Data;
+ DBGKD_WAIT_STATE_CHANGE64 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 */
+ CopyExceptionRecord(ExceptionRecord,
+ &WaitStateChange.u.Exception.ExceptionRecord);
+ 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_WAIT_STATE_CHANGE64) - sizeof(CONTEXT);
+ 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);
+}
+
+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 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;
+ }
+
+ /* 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;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KdEnableDebugger(VOID)
+{
+ /* Use the internal routine */
+ KdpDprintf("KdEnableDebugger called\n");
+ while (TRUE);
+ return KdEnableDebuggerWithLock(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)
+{
+ /* HACK */
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @unimplemented
+ */
+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)
+{
+ /* HACK */
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KdPowerTransition(IN DEVICE_POWER_STATE NewState)
+{
+ /* HACK */
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KdDisableDebugger(VOID)
+{
+ /* HACK */
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+KdRefreshDebuggerNotPresent(VOID)
+{
+ /* HACK */
+ return KdDebuggerNotPresent;
+}
+
+NTSTATUS
+NTAPI
+NtQueryDebugFilterState(ULONG ComponentId,
+ ULONG Level)
+{
+ /* HACK */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+NtSetDebugFilterState(ULONG ComponentId,
+ ULONG Level,
+ BOOLEAN State)
+{
+ /* HACK */
+ return STATUS_SUCCESS;
+}
+