mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
b84f2a1cdc
Comply with the standard documented behaviour: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlequalmemory#return-value > RtlEqualMemory returns TRUE if Source1 and Source2 are equivalent; otherwise, it returns FALSE. and https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlcomparememory#return-value > [...] If all bytes match up to the specified Length value, the Length value is returned.
561 lines
14 KiB
C
561 lines
14 KiB
C
/*
|
|
* 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", 4) != 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;
|
|
}
|
|
|