From 69512e2d9ba0ad685ff2680c7fe13bf21a4aef92 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Tue, 23 Dec 2014 17:48:16 +0000 Subject: [PATCH] [KDVBOX] Implement a virtualkd compatible kernel debugger transport DLL. I started this, because I didn't manage to get the original one working, but it turned out, the original one works, you only need to use the correct virtualkd version. Anyway, it's there now. A virtualkd version that works with VBox 4.3.16+ can be found here: http://forum.sysprogs.com/viewtopic.php?f=4&t=3370 or here: http://public.avast.com/~hnanicek/VirtualKd.zip The folder is called kdvm, since I thought about adding support for VMWare as well, but here the original one probably works as well. Also fix my email address in some files. svn path=/trunk/; revision=65813 --- reactos/base/setup/usetup/bootsup.c | 8 +- reactos/boot/bootdata/txtsetup.sif | 1 + reactos/drivers/base/CMakeLists.txt | 1 + reactos/drivers/base/kdcom/kdcom.c | 2 +- reactos/drivers/base/kdcom/kddll.c | 2 +- reactos/drivers/base/kdcom/kddll.h | 2 +- reactos/drivers/base/kdcom/kdserial.c | 2 +- reactos/drivers/base/kdvm/CMakeLists.txt | 15 + reactos/drivers/base/kdvm/kdvbox.c | 60 +++ reactos/drivers/base/kdvm/kdvbox_asm.S | 24 + reactos/drivers/base/kdvm/kdvm.c | 561 +++++++++++++++++++++++ reactos/drivers/base/kdvm/kdvm.h | 150 ++++++ reactos/drivers/base/kdvm/kdvm.rc | 5 + reactos/drivers/base/kdvm/kdvm.spec | 8 + 14 files changed, 836 insertions(+), 5 deletions(-) create mode 100644 reactos/drivers/base/kdvm/CMakeLists.txt create mode 100644 reactos/drivers/base/kdvm/kdvbox.c create mode 100644 reactos/drivers/base/kdvm/kdvbox_asm.S create mode 100644 reactos/drivers/base/kdvm/kdvm.c create mode 100644 reactos/drivers/base/kdvm/kdvm.h create mode 100644 reactos/drivers/base/kdvm/kdvm.rc create mode 100644 reactos/drivers/base/kdvm/kdvm.spec diff --git a/reactos/base/setup/usetup/bootsup.c b/reactos/base/setup/usetup/bootsup.c index 183641cfca0..b7f3e6e46fa 100644 --- a/reactos/base/setup/usetup/bootsup.c +++ b/reactos/base/setup/usetup/bootsup.c @@ -477,7 +477,13 @@ CreateFreeLoaderIniForReactos( L"ReactOS_Debug", L"\"ReactOS (Debug)\"", L"Windows2003", ArcPath, L"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /SOS"); - +#ifdef _WINKD_ + /* ReactOS_VBoxDebug */ + CreateFreeLoaderEntry(IniCache, IniSection, + L"ReactOS_VBoxDebug", L"\"ReactOS (VBoxDebug)\"", + L"Windows2003", ArcPath, + L"/DEBUG /DEBUGPORT=VBOX /SOS"); +#endif #if DBG #ifndef _WINKD_ /* ReactOS_KdSerial */ diff --git a/reactos/boot/bootdata/txtsetup.sif b/reactos/boot/bootdata/txtsetup.sif index c458d52419f..a2050b84183 100644 --- a/reactos/boot/bootdata/txtsetup.sif +++ b/reactos/boot/bootdata/txtsetup.sif @@ -30,6 +30,7 @@ cdrom.sys=,,,,,,x,,,,,,4 class2.sys=,,,,,,x,,,,,,4 isapnp.sys=,,,,,,,,,,,,4 kdcom.dll=,,,,,,,,,,,,2 +kdvbox.dll=,,,,,,,,,,,,2 disk.sys=,,,,,,x,,,,,,4 floppy.sys=,,,,,,x,,,,,,4 i8042prt.sys=,,,,,,,,,,,,4 diff --git a/reactos/drivers/base/CMakeLists.txt b/reactos/drivers/base/CMakeLists.txt index 7d84024299a..fd190949276 100644 --- a/reactos/drivers/base/CMakeLists.txt +++ b/reactos/drivers/base/CMakeLists.txt @@ -8,6 +8,7 @@ if(_WINKD_) add_subdirectory(kdgdb) else() add_subdirectory(kdcom) + add_subdirectory(kdvm) endif() else() add_subdirectory(kdrosdbg) diff --git a/reactos/drivers/base/kdcom/kdcom.c b/reactos/drivers/base/kdcom/kdcom.c index f7e86b632f9..ddf3a5ac8ea 100644 --- a/reactos/drivers/base/kdcom/kdcom.c +++ b/reactos/drivers/base/kdcom/kdcom.c @@ -3,7 +3,7 @@ * PROJECT: ReactOS kernel * FILE: drivers/base/kddll/kdcom.c * PURPOSE: COM port functions for the kernel debugger. - * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) */ #include "kddll.h" diff --git a/reactos/drivers/base/kdcom/kddll.c b/reactos/drivers/base/kdcom/kddll.c index 7ea2812e7e9..9827a507867 100644 --- a/reactos/drivers/base/kdcom/kddll.c +++ b/reactos/drivers/base/kdcom/kddll.c @@ -3,7 +3,7 @@ * PROJECT: ReactOS kernel * FILE: drivers/base/kddll/kddll.c * PURPOSE: Base functions for the kernel debugger. - * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) */ #include "kddll.h" diff --git a/reactos/drivers/base/kdcom/kddll.h b/reactos/drivers/base/kdcom/kddll.h index 73536899dc7..8179477703f 100644 --- a/reactos/drivers/base/kdcom/kddll.h +++ b/reactos/drivers/base/kdcom/kddll.h @@ -3,7 +3,7 @@ * PROJECT: ReactOS kernel * FILE: drivers/base/kddll/kddll.h * PURPOSE: Base definitions for the kernel debugger. - * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) */ #ifndef _KDDLL_H_ diff --git a/reactos/drivers/base/kdcom/kdserial.c b/reactos/drivers/base/kdcom/kdserial.c index bb37a3d9228..87e8f28f4fd 100644 --- a/reactos/drivers/base/kdcom/kdserial.c +++ b/reactos/drivers/base/kdcom/kdserial.c @@ -3,7 +3,7 @@ * PROJECT: ReactOS kernel * FILE: drivers/base/kddll/kdserial.c * PURPOSE: Serial communication functions for the kernel debugger. - * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) */ #include "kddll.h" diff --git a/reactos/drivers/base/kdvm/CMakeLists.txt b/reactos/drivers/base/kdvm/CMakeLists.txt new file mode 100644 index 00000000000..856cc6b92a7 --- /dev/null +++ b/reactos/drivers/base/kdvm/CMakeLists.txt @@ -0,0 +1,15 @@ + +spec2def(kdvbox.dll kdvm.spec) + +add_library(kdvbox SHARED + kdvm.c + kdvbox.c + kdvbox_asm.S + kdvm.rc + ${CMAKE_CURRENT_BINARY_DIR}/kdvbox.def) + +set_module_type(kdvbox module IMAGEBASE 0x00010000) +set_subsystem(kdvbox native) +add_importlibs(kdvbox ntoskrnl hal) +add_dependencies(kdvbox psdk bugcodes) +add_cd_file(TARGET kdvbox DESTINATION reactos/system32 NO_CAB FOR all) diff --git a/reactos/drivers/base/kdvm/kdvbox.c b/reactos/drivers/base/kdvm/kdvbox.c new file mode 100644 index 00000000000..977097e760e --- /dev/null +++ b/reactos/drivers/base/kdvm/kdvbox.c @@ -0,0 +1,60 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kdvm/kdvbox.c + * PURPOSE: VBOX data exchange function for kdvbox + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +#include "kdvm.h" + +typedef struct +{ + ULONG SendSize; + ULONG BufferSize; +} KDVBOX_SEND_HEADER, *PKDVBOX_SEND_HEADER; + +typedef struct +{ + ULONG ReceivedDataSize; +} KDVBOX_RECEIVE_HEADER, *PKDVBOX_RECEIVE_HEADER; + +VOID +NTAPI +KdVmPrepareBuffer(VOID) +{ + KdVmBufferPos = sizeof(KDVBOX_SEND_HEADER); +} + +VOID +NTAPI +KdVmKdVmExchangeData( + _Out_ PVOID* ReceiveData, + _Out_ PULONG ReceiveDataSize) +{ + PKDVBOX_SEND_HEADER SendHeader; + PKDVBOX_RECEIVE_HEADER ReceiveHeader; + + /* Setup the send-header */ + SendHeader = (PKDVBOX_SEND_HEADER)KdVmDataBuffer; + SendHeader->SendSize = KdVmBufferPos - sizeof(KDVBOX_SEND_HEADER); + SendHeader->BufferSize = KDVM_BUFFER_SIZE; + + //KdpDbgPrint("Sending buffer:\n"); + //KdVmDbgDumpBuffer(KdVmDataBuffer, KdVmBufferPos); + + /* Do the data exchange */ + KdVmExchange((ULONG_PTR)KdVmBufferPhysicalAddress.QuadPart, 0); + + /* Reset the buffer position */ + KdVmBufferPos = sizeof(KDVBOX_SEND_HEADER); + + /* Get the receive-header and return information about the received data */ + ReceiveHeader = (PKDVBOX_RECEIVE_HEADER)KdVmDataBuffer; + *ReceiveData = KdVmDataBuffer + sizeof(KDVBOX_RECEIVE_HEADER); + *ReceiveDataSize = ReceiveHeader->ReceivedDataSize; + + //KdpDbgPrint("got data:\n"); + //KdVmDbgDumpBuffer(KdVmDataBuffer, *ReceiveDataSize + sizeof(*ReceiveHeader)); + +} diff --git a/reactos/drivers/base/kdvm/kdvbox_asm.S b/reactos/drivers/base/kdvm/kdvbox_asm.S new file mode 100644 index 00000000000..5adda24f5f3 --- /dev/null +++ b/reactos/drivers/base/kdvm/kdvbox_asm.S @@ -0,0 +1,24 @@ + +#include + +.code + +#ifdef _M_IX86 +PUBLIC @KdVmExchange@8 +FUNC @KdVmExchange@8 + xchg eax, ecx + mov edx, HEX(5659) + out dx, eax + ret +ENDFUNC +#else +PUBLIC KdVmExchange +FUNC KdVmExchange + xchg rax, rcx + mov edx, HEX(5659) + out dx, rax + ret +ENDFUNC +#endif + +END diff --git a/reactos/drivers/base/kdvm/kdvm.c b/reactos/drivers/base/kdvm/kdvm.c new file mode 100644 index 00000000000..39e77313a82 --- /dev/null +++ b/reactos/drivers/base/kdvm/kdvm.c @@ -0,0 +1,561 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kdvm/kdvm.c + * PURPOSE: VM independent function for kdvbox/kd + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +#include "kdvm.h" + +static CHAR KdVmCmdMagic[] = "~kdVMvA "; +static CHAR KdVmReplyMagic[] = "++kdVMvA "; +static const UCHAR KDVM_CMD_TestConnection = 't'; +static const UCHAR KDVM_CMD_ReceivePacket = 'r'; +static const UCHAR KDVM_CMD_SendPacket = 's'; +static const UCHAR KDVM_CMD_VersionReport = 'v'; + +UCHAR KdVmDataBuffer[KDVM_BUFFER_SIZE]; +PHYSICAL_ADDRESS KdVmBufferPhysicalAddress; +ULONG KdVmBufferPos; + +PFNDBGPRNT KdpDbgPrint; + + +/* PRIVATE FUNCTIONS **********************************************************/ + +static +VOID +KdVmDbgDumpRow( + _In_ PUCHAR Buffer, + _In_ ULONG Size) +{ + ULONG i; + for (i = 0;i < Size; i++) + { + KdpDbgPrint("%02x ", Buffer[i]); + } + KdpDbgPrint("\n"); +} + +VOID +NTAPI +KdVmDbgDumpBuffer( + _In_ PVOID Buffer, + _In_ ULONG Size) +{ + PUCHAR CurrentRow; + ULONG i; + + CurrentRow = Buffer; + for (i = 0; i < (Size / 16); i++) + { + KdVmDbgDumpRow(CurrentRow, 16); + CurrentRow += 16; + } + KdVmDbgDumpRow(CurrentRow, (Size % 16)); +} + +static +BOOLEAN +KdVmAddToBuffer( + _In_ PVOID Data, + _In_ ULONG DataSize) +{ + if (((KdVmBufferPos + DataSize) > KDVM_BUFFER_SIZE) || + ((KdVmBufferPos + DataSize) < KdVmBufferPos)) + { + KDDBGPRINT("KdVmAddToBuffer: Buffer overflow! Need %lu, remaining: %lu\n", + DataSize, KDVM_BUFFER_SIZE - KdVmBufferPos); + return FALSE; + } + + RtlCopyMemory(&KdVmDataBuffer[KdVmBufferPos], Data, DataSize); + KdVmBufferPos += DataSize; + return TRUE; +} + +static +BOOLEAN +KdVmAddCommandToBuffer( + _In_ UCHAR Command, + _In_ PVOID Buffer, + _In_ SIZE_T BufferSize) +{ + KDVM_CMD_HEADER Header; + + RtlCopyMemory(&Header.Magic, KdVmCmdMagic, sizeof(Header.Magic)); + Header.Command = Command; + + if (!KdVmAddToBuffer(&Header, sizeof(Header))) + return FALSE; + + if (!KdVmAddToBuffer(Buffer, BufferSize)) + return FALSE; + + return TRUE; +} + +static +PVOID +KdVmSendReceive( + _Out_ PULONG ReceiveDataSize) +{ + PVOID ReceiveData; + PKDVM_RECEIVE_HEADER ReceiveHeader; + + KdVmKdVmExchangeData(&ReceiveData, ReceiveDataSize); + ReceiveHeader = ReceiveData; + + if (*ReceiveDataSize < sizeof(*ReceiveHeader)) + { + KDDBGPRINT("KdVmSendReceive: received data too small: 0x%x\n", *ReceiveDataSize); + *ReceiveDataSize = 0; + return NULL; + } + + if (ReceiveHeader->Id != 0x2031 /* '01' */) + { + KDDBGPRINT("KdVmSendReceive: got invalid Id: 0x%x\n", ReceiveHeader->Id); + *ReceiveDataSize = 0; + return NULL; + } + + if (RtlEqualMemory(ReceiveHeader->Magic, KdVmReplyMagic, 9)) + { + KDDBGPRINT("KdVmSendReceive: got invalid Magic: '%*s'\n", + sizeof(KdVmReplyMagic), ReceiveHeader->Magic); + *ReceiveDataSize = 0; + return NULL; + } + + *ReceiveDataSize -= sizeof(*ReceiveHeader); + return (PVOID)(ReceiveHeader + 1); +} + +static +NTSTATUS +KdVmNegotiateProtocolVersions(VOID) +{ + ULONG Version = KDRPC_PROTOCOL_VERSION; + ULONG ReceivedSize; + PULONG ReceivedVersion; + KDDBGPRINT("KdVmNegotiateProtocolVersions()\n"); + + /* Prepare the buffer */ + KdVmPrepareBuffer(); + + if (!KdVmAddCommandToBuffer(KDVM_CMD_VersionReport, &Version, sizeof(Version))) + { + KDDBGPRINT("Failed to do VersionReport\n"); + return STATUS_CONNECTION_REFUSED; + } + + ReceivedVersion = KdVmSendReceive(&ReceivedSize); + if (ReceivedSize != sizeof(ULONG)) + { + KDDBGPRINT("Invalid size for VersionReport: %lx\n", ReceivedSize); + return STATUS_CONNECTION_REFUSED; + } + + if (*ReceivedVersion != KDRPC_PROTOCOL_VERSION) + { + KDDBGPRINT("Invalid Version: %lx\n", *ReceivedVersion); + return STATUS_CONNECTION_REFUSED; //STATUS_PROTOCOL_NOT_SUPPORTED; + } + + return STATUS_SUCCESS; +} + +static +BOOLEAN +TestConnectionOnChannel(VOID) +{ + UCHAR TestBuffer[KDRPC_TEST_BUFFER_SIZE]; + PUCHAR ReceivedBuffer; + ULONG i, ReceivedSize; + + /* Prepare the buffer */ + KdVmPrepareBuffer(); + + for (i = 0; i < sizeof(TestBuffer); i++) + TestBuffer[i] = (UCHAR)i; + + if (!KdVmAddCommandToBuffer(KDVM_CMD_TestConnection, TestBuffer, sizeof(TestBuffer))) + { + KDDBGPRINT("Failed to do TestConnection\n"); + return FALSE; + } + + ReceivedBuffer = KdVmSendReceive(&ReceivedSize); + if (ReceivedSize != sizeof(TestBuffer)) + { + KDDBGPRINT("Invalid size for TestConnection: %lx\n", ReceivedSize); + return FALSE; + } + + for (i = 0; i < sizeof(TestBuffer); i++) + { + if (ReceivedBuffer[i] != (UCHAR)(i ^ 0x55)) + { + KDDBGPRINT("Wrong test data @ %lx, expected %x, got %x\n", + i, (UCHAR)(i ^ 0x55), TestBuffer[i]); + return FALSE; + } + } + + KDDBGPRINT("TestConnectionOnChannel: success\n"); + return TRUE; +} + +static +BOOLEAN +KdVmTestConnectionWithHost(VOID) +{ + ULONG i, j; + KDDBGPRINT("KdVmTestConnectionWithHost()\n"); + + for (j = 0; j < 2; j++) + { + //VMWareRPC::OpenChannel + for (i = 0; i < CONNECTION_TEST_ROUNDS / 2; i++) + { + if (!TestConnectionOnChannel()) + { + return FALSE; + } + } + } + + return TRUE; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +NTSTATUS +NTAPI +KdD0Transition(VOID) +{ + /* Nothing to do */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +KdD3Transition(VOID) +{ + /* Nothing to do */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +KdSave( + _In_ BOOLEAN SleepTransition) +{ + /* Nothing to do */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +KdRestore( + _In_ BOOLEAN SleepTransition) +{ + /* Nothing to do */ + return STATUS_SUCCESS; +} + +/****************************************************************************** + * \name KdDebuggerInitialize0 + * \brief Phase 0 initialization. + * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL. + * \return Status + */ +NTSTATUS +NTAPI +KdDebuggerInitialize0( + _In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PCHAR CommandLine, PortString; + NTSTATUS Status; + + /* Check if we have a LoaderBlock */ + if (LoaderBlock != NULL) + { + /* HACK */ + KdpDbgPrint = LoaderBlock->u.I386.CommonDataArea; + KDDBGPRINT("KdDebuggerInitialize0\n"); + + /* Get the Command Line */ + CommandLine = LoaderBlock->LoadOptions; + + /* Upcase it */ + _strupr(CommandLine); + + /* Check if we got the /DEBUGPORT parameter */ + PortString = strstr(CommandLine, "DEBUGPORT"); + if (PortString) + { + /* Move past the actual string, to reach the port*/ + PortString += strlen("DEBUGPORT"); + + /* Now get past any spaces and skip the equal sign */ + while (*PortString == ' ') PortString++; + PortString++; + + /* Do we have a serial port? */ + if (strncmp(PortString, "VBOX", 3) != 0) + { + KDDBGPRINT("Invalid debugport: '%s'\n", CommandLine); + return STATUS_INVALID_PARAMETER; + } + } + } + + /* Get the physical address of the data buffer */ + KdVmBufferPhysicalAddress = MmGetPhysicalAddress(KdVmDataBuffer); + KDDBGPRINT("KdVmBufferPhysicalAddress = %llx\n", KdVmBufferPhysicalAddress.QuadPart); + + Status = KdVmNegotiateProtocolVersions(); + if (!NT_SUCCESS(Status)) + return Status; + + if (!KdVmTestConnectionWithHost()) + return STATUS_CONNECTION_REFUSED; + + return STATUS_SUCCESS; +} + +/****************************************************************************** + * \name KdDebuggerInitialize1 + * \brief Phase 1 initialization. + * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL. + * \return Status + */ +NTSTATUS +NTAPI +KdDebuggerInitialize1( + _In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + /* Nothing to do */ + KDDBGPRINT("KdDebuggerInitialize1()\n"); + return STATUS_SUCCESS; +} + +VOID +NTAPI +KdSendPacket( + _In_ ULONG PacketType, + _In_ PSTRING MessageHeader, + _In_ PSTRING MessageData, + _Inout_ PKD_CONTEXT KdContext) +{ + KDVM_SEND_PKT_REQUEST SendPktRequest; + PKDVM_SEND_PKT_RESULT SendPktResult; + ULONG ReceivedSize; + KDDBGPRINT("KdSendPacket(0x%lx, ...)\n", PacketType); + + do + { + + RtlZeroMemory(&SendPktRequest, sizeof(SendPktRequest)); + + SendPktRequest.PacketType = PacketType; + SendPktRequest.Info.KdDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT; + SendPktRequest.Info.KdDebuggerEnabledAvailable = 1; + SendPktRequest.Info.KdDebuggerEnabled = SharedUserData->KdDebuggerEnabled; + + if (MessageHeader != NULL) + { + SendPktRequest.MessageHeader.Length = MessageHeader->Length; + SendPktRequest.MessageHeader.MaximumLength = MessageHeader->MaximumLength; + SendPktRequest.HeaderSize = MessageHeader->Length; + } + + if (MessageData != NULL) + { + SendPktRequest.MessageData.Length = MessageData->Length; + SendPktRequest.MessageData.MaximumLength = MessageData->MaximumLength; + SendPktRequest.DataSize = MessageData->Length; + } + + if (KdContext != NULL) + { + RtlCopyMemory(&SendPktRequest.KdContext, + KdContext, + sizeof(SendPktRequest.KdContext)); + } + + + /* Prepare the buffer */ + KdVmPrepareBuffer(); + + if (!KdVmAddCommandToBuffer(KDVM_CMD_SendPacket, &SendPktRequest, sizeof(SendPktRequest))) + { + KDDBGPRINT("KdSendPacket: Failed to add SendPacket command\n"); + return; + } + + if (MessageHeader != NULL) + { + if (!KdVmAddToBuffer(MessageHeader->Buffer, MessageHeader->Length)) + { + KDDBGPRINT("KdSendPacket: Failed to add MessageHeader\n"); + return; + } + } + + if (MessageData != NULL) + { + if (!KdVmAddToBuffer(MessageData->Buffer, MessageData->Length)) + { + KDDBGPRINT("KdSendPacket: Failed to add MessageData\n"); + return; + } + } + + SendPktResult = KdVmSendReceive(&ReceivedSize); + if (ReceivedSize != sizeof(*SendPktResult)) + { + KDDBGPRINT("KdSendPacket: Invalid size for SendPktResult: %lx\n", ReceivedSize); + return; + } + + if (KdContext != NULL) + { + RtlCopyMemory(KdContext, + &SendPktResult->KdContext, + sizeof(SendPktResult->KdContext)); + } + + KD_DEBUGGER_NOT_PRESENT = SendPktResult->Info.KdDebuggerNotPresent; + if (SendPktResult->Info.KdDebuggerEnabledAvailable) + SharedUserData->KdDebuggerEnabled = SendPktResult->Info.KdDebuggerEnabled != 0; + + if (SendPktResult->Info.RetryKdSendPacket) + { + KDDBGPRINT("KdSendPacket: RetryKdSendPacket!\n"); + } + + } while (SendPktResult->Info.RetryKdSendPacket); + + KDDBGPRINT("KdSendPacket: Success!\n"); +} + + +KDP_STATUS +NTAPI +KdReceivePacket( + _In_ ULONG PacketType, + _Out_ PSTRING MessageHeader, + _Out_ PSTRING MessageData, + _Out_ PULONG DataLength, + _Inout_opt_ PKD_CONTEXT KdContext) +{ + KDVM_RECV_PKT_REQUEST RecvPktRequest; + PKDVM_RECV_PKT_RESULT RecvPktResult; + ULONG ReceivedSize, ExpectedSize; + PUCHAR Buffer; + KDDBGPRINT("KdReceivePacket(0x%lx, ...)\n", PacketType); + + /* Prepare the buffer */ + KdVmPrepareBuffer(); + + RtlZeroMemory(&RecvPktRequest, sizeof(RecvPktRequest)); + + RecvPktRequest.PacketType = PacketType; + RecvPktRequest.Info.KdDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT; + RecvPktRequest.Info.KdDebuggerEnabledAvailable = 1; + RecvPktRequest.Info.KdDebuggerEnabled = SharedUserData->KdDebuggerEnabled; + + if (MessageHeader != NULL) + { + RecvPktRequest.MessageHeader.Length = MessageHeader->Length; + RecvPktRequest.MessageHeader.MaximumLength = MessageHeader->MaximumLength; + } + + if (MessageData != NULL) + { + RecvPktRequest.MessageData.Length = MessageData->Length; + RecvPktRequest.MessageData.MaximumLength = MessageData->MaximumLength; + } + + if (KdContext != NULL) + { + RtlCopyMemory(&RecvPktRequest.KdContext, + KdContext, + sizeof(RecvPktRequest.KdContext)); + } + + if (!KdVmAddCommandToBuffer(KDVM_CMD_ReceivePacket, &RecvPktRequest, sizeof(RecvPktRequest))) + { + KDDBGPRINT("KdReceivePacket: Failed to add SendPacket command\n"); + return KDP_PACKET_RESEND; + } + + RecvPktResult = KdVmSendReceive(&ReceivedSize); + if (ReceivedSize < sizeof(*RecvPktResult)) + { + KDDBGPRINT("KdReceivePacket: Invalid size for RecvPktResult: %lx\n", ReceivedSize); + return KDP_PACKET_RESEND; + } + + ExpectedSize = sizeof(*RecvPktResult) + + RecvPktResult->HeaderSize + + RecvPktResult->DataSize; + if (ReceivedSize != ExpectedSize) + { + KDDBGPRINT("KdReceivePacket: Invalid size for RecvPktResult: %lu, expected %lu\n", + ReceivedSize, ExpectedSize); + return KDP_PACKET_RESEND; + } + + if (KdContext != NULL) + { + RtlCopyMemory(KdContext, + &RecvPktResult->KdContext, + sizeof(RecvPktResult->KdContext)); + } + + Buffer = (PUCHAR)(RecvPktResult + 1); + if (MessageHeader != NULL) + { + MessageHeader->Length = RecvPktResult->MessageHeader.Length; + if ((MessageHeader->Buffer != NULL) && + (MessageHeader->MaximumLength >= RecvPktResult->HeaderSize)) + { + RtlCopyMemory(MessageHeader->Buffer, + Buffer, + RecvPktResult->HeaderSize); + } + else + { + KDDBGPRINT("MessageHeader not good\n"); + } + } + + Buffer += RecvPktResult->HeaderSize; + if (MessageData != NULL) + { + MessageData->Length = RecvPktResult->MessageData.Length; + if ((MessageData->Buffer != NULL) && + (MessageData->MaximumLength >= RecvPktResult->DataSize)) + { + RtlCopyMemory(MessageData->Buffer, + Buffer, + RecvPktResult->DataSize); + } + else + { + KDDBGPRINT("MessageData not good\n"); + } + } + + if (DataLength != NULL) + *DataLength = RecvPktResult->FullSize; + + KDDBGPRINT("KdReceivePacket: returning status %u\n", RecvPktResult->KdStatus); + return RecvPktResult->KdStatus; +} + diff --git a/reactos/drivers/base/kdvm/kdvm.h b/reactos/drivers/base/kdvm/kdvm.h new file mode 100644 index 00000000000..2636577ec6f --- /dev/null +++ b/reactos/drivers/base/kdvm/kdvm.h @@ -0,0 +1,150 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kdvm/kdvm.h + * PURPOSE: Base definitions for the kernel debugger. + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +#ifndef _KDDLL_H_ +#define _KDDLL_H_ + +#define NOEXTAPI +#include +#include +#include + +#undef RtlEqualMemory +#define RtlEqualMemory(a, b, c) (RtlCompareMemory(a, b, c) != c) + +//#define KDDEBUG /* uncomment to enable debugging this dll */ + +typedef ULONG (*PFNDBGPRNT)(const char *Format, ...); +extern PFNDBGPRNT KdpDbgPrint; + +#ifndef KDDEBUG +#define KDDBGPRINT(...) +#else +#define KDDBGPRINT KdpDbgPrint +#endif + +#define KDRPC_PROTOCOL_VERSION 0x101 +#define CONNECTION_TEST_ROUNDS 2 /*100*/ +#define KDVM_BUFFER_SIZE (131072 + 1024) +#define KDRPC_TEST_BUFFER_SIZE 512 + +extern UCHAR KdVmDataBuffer[KDVM_BUFFER_SIZE]; +extern PHYSICAL_ADDRESS KdVmBufferPhysicalAddress; +extern ULONG KdVmBufferPos; + +typedef enum +{ + KDP_PACKET_RECEIVED = 0, + KDP_PACKET_TIMEOUT = 1, + KDP_PACKET_RESEND = 2 +} KDP_STATUS; + +typedef struct _KDVM_MARSHAL_STRING +{ + USHORT Length; + USHORT MaximumLength; +} KDVM_MARSHAL_STRING; + +#pragma pack(push,1) +typedef struct +{ + CHAR Magic[8]; + UCHAR Command; +} KDVM_CMD_HEADER; + +typedef struct +{ + USHORT Id; + CHAR Magic[9]; +} KDVM_RECEIVE_HEADER, *PKDVM_RECEIVE_HEADER; + +typedef struct _KDVM_CONTEXT +{ + ULONG RetryCount; + BOOLEAN BreakInRequested; + UCHAR align; +} KDVM_CONTEXT, *PKDVM_CONTEXT; + +typedef struct +{ + struct + { + UCHAR KdDebuggerNotPresent : 1; + UCHAR RetryKdSendPacket : 1; + UCHAR KdDebuggerEnabledAvailable : 1; + }; + BOOLEAN KdDebuggerEnabled; + USHORT Unused; +} KDVM_SENDPACKET_INFO; + +typedef struct _KDVM_SEND_PKT_REQUEST +{ + KDVM_MARSHAL_STRING MessageHeader; + KDVM_MARSHAL_STRING MessageData; + KDVM_CONTEXT KdContext; + ULONG PacketType; + ULONG HeaderSize; + ULONG DataSize; + KDVM_SENDPACKET_INFO Info; +} KDVM_SEND_PKT_REQUEST, *PKDVM_SEND_PKT_REQUEST; + +typedef struct _KDVM_SEND_PKT_RESULT +{ + UCHAR CommandType; + KDVM_CONTEXT KdContext; + KDVM_SENDPACKET_INFO Info; +} KDVM_SEND_PKT_RESULT, *PKDVM_SEND_PKT_RESULT; + +typedef struct +{ + ULONG PacketType; + KDVM_SENDPACKET_INFO Info; + KDVM_MARSHAL_STRING MessageHeader; + KDVM_MARSHAL_STRING MessageData; + KDVM_CONTEXT KdContext; +} KDVM_RECV_PKT_REQUEST; + +typedef struct +{ + UCHAR CommandType; + KDVM_MARSHAL_STRING MessageHeader; + KDVM_MARSHAL_STRING MessageData; + KDVM_CONTEXT KdContext; + KDP_STATUS KdStatus; + ULONG FullSize; + ULONG HeaderSize; + ULONG DataSize; + KDVM_SENDPACKET_INFO Info; +} KDVM_RECV_PKT_RESULT, *PKDVM_RECV_PKT_RESULT; +#pragma pack(pop) + +VOID +NTAPI +KdVmDbgDumpBuffer( + _In_ PVOID Buffer, + _In_ ULONG Size); + +VOID +FASTCALL +KdVmExchange( + _In_ ULONG_PTR PhysicalAddress, + _In_ SIZE_T BufferSize); + +VOID +NTAPI +KdVmPrepareBuffer( + VOID); + +VOID +NTAPI +KdVmKdVmExchangeData( + _Out_ PVOID* ReceiveData, + _Out_ PULONG ReceiveDataSize); + + +#endif /* _KDDLL_H_ */ diff --git a/reactos/drivers/base/kdvm/kdvm.rc b/reactos/drivers/base/kdvm/kdvm.rc new file mode 100644 index 00000000000..e050dad115b --- /dev/null +++ b/reactos/drivers/base/kdvm/kdvm.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Kernel Debugger COM Extension DLL" +#define REACTOS_STR_INTERNAL_NAME "kdcom" +#define REACTOS_STR_ORIGINAL_FILENAME "kdcom.dll" +#include diff --git a/reactos/drivers/base/kdvm/kdvm.spec b/reactos/drivers/base/kdvm/kdvm.spec new file mode 100644 index 00000000000..4098dd6e2ad --- /dev/null +++ b/reactos/drivers/base/kdvm/kdvm.spec @@ -0,0 +1,8 @@ +@ stdcall KdD0Transition() +@ stdcall KdD3Transition() +@ stdcall KdDebuggerInitialize0(ptr) +@ stdcall KdDebuggerInitialize1(ptr) +@ stdcall KdReceivePacket(long ptr ptr ptr ptr) +@ stdcall KdRestore(long) +@ stdcall KdSave(long) +@ stdcall KdSendPacket(long ptr ptr ptr)