* 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 ******************************************************************/
/* PRIVATE FUNCTIONS *********************************************************/
+NTSTATUS
+NTAPI
+KdpCopyMemoryChunks(IN ULONG64 Address,
+ IN PVOID Buffer,
+ IN ULONG TotalSize,
+ IN ULONG ChunkSize,
+ IN ULONG Flags,
+ OUT PULONG ActualSize OPTIONAL)
+{
+ ULONG Length;
+ NTSTATUS Status;
+
+ /* Check if this is physical or virtual copy */
+ if (Flags & MMDBG_COPY_PHYSICAL)
+ {
+ /* Fail physical memory read/write for now */
+ if (Flags & MMDBG_COPY_WRITE)
+ {
+ KdpDprintf("KdpCopyMemoryChunks: Failing write for Physical Address 0x%I64x Length: %x\n",
+ Address,
+ TotalSize);
+ }
+ else
+ {
+ KdpDprintf("KdpCopyMemoryChunks: Failing read for Physical Address 0x%I64x Length: %x\n",
+ Address,
+ TotalSize);
+ }
+
+ /* Return an error */
+ Length = 0;
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ /* Protect against NULL */
+ if (!Address)
+ {
+ if (ActualSize) *ActualSize = 0;
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Check if this is read or write */
+ if (Flags & MMDBG_COPY_WRITE)
+ {
+ /* Do the write */
+ RtlCopyMemory((PVOID)(ULONG_PTR)Address,
+ Buffer,
+ TotalSize);
+ }
+ else
+ {
+ /* Do the read */
+ RtlCopyMemory(Buffer,
+ (PVOID)(ULONG_PTR)Address,
+ TotalSize);
+ }
+
+ /* Set size and status */
+ Length = TotalSize;
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Return the actual length if requested */
+ if (ActualSize) *ActualSize = Length;
+
+ /* Return status */
+ return Status;
+}
+
VOID
NTAPI
KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,
VOID
NTAPI
-DumpTraceData(IN PSTRING TraceData)
+DumpTraceData(OUT PSTRING TraceData)
{
/* Update the buffer */
TraceDataBuffer[0] = TraceDataBufferPosition;
NTAPI
KdpSetCommonState(IN ULONG NewState,
IN PCONTEXT Context,
- IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)
+ IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange)
{
USHORT InstructionCount;
BOOLEAN HadBreakpoints;
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));
+ /* Zero out the entire Control Report */
+ RtlZeroMemory(&WaitStateChange->AnyControlReport,
+ sizeof(DBGKD_ANY_CONTROL_REPORT));
/* Now copy the instruction stream and set the count */
RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
IN PSTRING Data,
IN PCONTEXT Context)
{
+ PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
STRING Header;
- ULONG Length = State->u.ReadMemory.TransferCount;
- NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Length = ReadMemory->TransferCount;
+ ULONG64 TargetBaseAddress = State->u.ReadMemory.TargetBaseAddress;
+
+ /* 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)))
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
-
- if (!State->u.ReadMemory.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;
+ /* Do the read */
+ State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
+ Data->Buffer,
+ Length,
+ 0,
+ MMDBG_COPY_UNSAFE,
+ &Length);
- /* Fill out the state */
- State->ReturnStatus = Status;
- State->u.ReadMemory.ActualBytesRead = Length;
+ /* Return the actual length read */
+ Data->Length = ReadMemory->ActualBytesRead = Length;
/* Send the packet */
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
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);
+ 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
IN PSTRING Data,
IN PCONTEXT Context)
{
+ PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
STRING Header;
+ ULONG Length = ReadMemory->TransferCount;
+ ULONG Flags, CacheFlags;
- /* 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 */
+ /* Setup the header */
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
Header.Buffer = (PCHAR)State;
- Data->Length = 0;
- State->ReturnStatus = STATUS_UNSUCCESSFUL;
+ ASSERT(Data->Length == 0);
- /* Send it */
+ /* 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,
IN PSTRING Data,
IN PCONTEXT Context)
{
+ PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
STRING Header;
+ ULONG Flags, CacheFlags;
- /* 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 */
+ /* Setup the header */
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
Header.Buffer = (PCHAR)State;
- Data->Length = 0;
- State->ReturnStatus = STATUS_UNSUCCESSFUL;
- /* Send it */
+ /* 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,
- Data,
+ NULL,
&KdpContext);
}
{
PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
STRING Header;
- ULONG Length;
/* Setup the header */
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
WriteMemory->TargetBaseAddress,
Data->Buffer,
Data->Length,
- &Length);
-
- /* Return the length written */
- WriteMemory->ActualBytesWritten = Length;
+ &WriteMemory->ActualBytesWritten);
/* Send the reply */
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
else
{
/* SMP not yet handled */
- KdpDprintf("SMP UNHANDLED\n");
+ KdpDprintf("KdpGetContext: SMP UNHANDLED\n");
ControlStart = NULL;
while (TRUE);
}
else
{
/* SMP not yet handled */
- KdpDprintf("SMP UNHANDLED\n");
+ KdpDprintf("KdpSetContext: SMP UNHANDLED\n");
ControlStart = NULL;
while (TRUE);
}
State->ReturnStatus = KdpSysReadBusData(GetBusData->BusDataType,
GetBusData->BusNumber,
GetBusData->SlotNumber,
- Data->Buffer,
GetBusData->Offset,
+ Data->Buffer,
Length,
&Length);
State->ReturnStatus = KdpSysWriteBusData(SetBusData->BusDataType,
SetBusData->BusNumber,
SetBusData->SlotNumber,
- Data->Buffer,
SetBusData->Offset,
+ Data->Buffer,
SetBusData->Length,
&Length);
Header.Buffer = (PCHAR)State;
/* Call the internal routine */
- State->ReturnStatus = KdpSysCheckLowMemory(0x4);
+ State->ReturnStatus = KdpSysCheckLowMemory(MMDBG_COPY_UNSAFE);
/* Send the reply */
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
{
PSTRING ExtraData;
STRING Data, Header;
- DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
+ DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
KCONTINUE_STATUS Status;
/* Start wait loop */
}
/* Setup the header */
- Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
+ Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
Header.Buffer = (PCHAR)&WaitStateChange;
/* Send the packet */
IN BOOLEAN SecondChanceException)
{
STRING Header, Data;
- DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
+ DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
KCONTINUE_STATUS Status;
/* Start report loop */
KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
/* Copy the Exception Record and set First Chance flag */
- CopyExceptionRecord(ExceptionRecord,
- &WaitStateChange.u.Exception.ExceptionRecord);
+#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_WAIT_STATE_CHANGE64);
+ Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
Header.Buffer = (PCHAR)&WaitStateChange;
/* Setup the trace data */
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,
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)
{
/* Do the unlock */
KeLowerIrql(OldIrql);
KdpPortUnlock();
- }
- /* Fail: We're already enabled */
- return STATUS_INVALID_PARAMETER;
+ /* 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 */
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 **********************************************************/
/*
KdEnableDebugger(VOID)
{
/* Use the internal routine */
- KdpDprintf("KdEnableDebugger called\n");
- while (TRUE);
return KdEnableDebuggerWithLock(TRUE);
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+KdDisableDebugger(VOID)
+{
+ /* Use the internal routine */
+ return KdDisableDebuggerWithLock(TRUE);
+}
+
/*
* @unimplemented
*/
return STATUS_SUCCESS;
}
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-KdDisableDebugger(VOID)
-{
- /* HACK */
- return STATUS_SUCCESS;
-}
-
/*
* @unimplemented
*/
return KdDebuggerNotPresent;
}
+/*
+ * @unimplemented
+ */
NTSTATUS
NTAPI
-NtQueryDebugFilterState(ULONG ComponentId,
- ULONG Level)
+NtQueryDebugFilterState(IN ULONG ComponentId,
+ IN ULONG Level)
{
/* HACK */
return STATUS_SUCCESS;
}
+/*
+ * @unimplemented
+ */
NTSTATUS
NTAPI
-NtSetDebugFilterState(ULONG ComponentId,
- ULONG Level,
- BOOLEAN State)
+NtSetDebugFilterState(IN ULONG ComponentId,
+ IN ULONG Level,
+ IN BOOLEAN State)
{
/* HACK */
return STATUS_SUCCESS;
}
-