xref: /reactos/drivers/base/kdvm/kdvm.c (revision b84f2a1c)
1 /*
2  * COPYRIGHT:       GPL, see COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            drivers/base/kdvm/kdvm.c
5  * PURPOSE:         VM independent function for kdvbox/kd
6  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 #include "kdvm.h"
10 
11 static CHAR KdVmCmdMagic[] = "~kdVMvA ";
12 static CHAR KdVmReplyMagic[] = "++kdVMvA ";
13 static const UCHAR KDVM_CMD_TestConnection = 't';
14 static const UCHAR KDVM_CMD_ReceivePacket = 'r';
15 static const UCHAR KDVM_CMD_SendPacket = 's';
16 static const UCHAR KDVM_CMD_VersionReport = 'v';
17 
18 UCHAR KdVmDataBuffer[KDVM_BUFFER_SIZE];
19 PHYSICAL_ADDRESS KdVmBufferPhysicalAddress;
20 ULONG KdVmBufferPos;
21 
22 PFNDBGPRNT KdpDbgPrint;
23 
24 
25 /* PRIVATE FUNCTIONS **********************************************************/
26 
27 static
28 VOID
KdVmDbgDumpRow(_In_ PUCHAR Buffer,_In_ ULONG Size)29 KdVmDbgDumpRow(
30     _In_ PUCHAR Buffer,
31     _In_ ULONG Size)
32 {
33     ULONG i;
34     for (i = 0;i < Size; i++)
35     {
36         KdpDbgPrint("%02x ", Buffer[i]);
37     }
38     KdpDbgPrint("\n");
39 }
40 
41 VOID
42 NTAPI
KdVmDbgDumpBuffer(_In_ PVOID Buffer,_In_ ULONG Size)43 KdVmDbgDumpBuffer(
44     _In_ PVOID Buffer,
45     _In_ ULONG Size)
46 {
47     PUCHAR CurrentRow;
48     ULONG i;
49 
50     CurrentRow = Buffer;
51     for (i = 0; i < (Size / 16); i++)
52     {
53         KdVmDbgDumpRow(CurrentRow, 16);
54         CurrentRow += 16;
55     }
56     KdVmDbgDumpRow(CurrentRow, (Size % 16));
57 }
58 
59 static
60 BOOLEAN
KdVmAddToBuffer(_In_ PVOID Data,_In_ ULONG DataSize)61 KdVmAddToBuffer(
62     _In_ PVOID Data,
63     _In_ ULONG DataSize)
64 {
65     if (((KdVmBufferPos + DataSize) > KDVM_BUFFER_SIZE) ||
66         ((KdVmBufferPos + DataSize) < KdVmBufferPos))
67     {
68         KDDBGPRINT("KdVmAddToBuffer: Buffer overflow! Need %lu, remaining: %lu\n",
69                    DataSize, KDVM_BUFFER_SIZE - KdVmBufferPos);
70         return FALSE;
71     }
72 
73     RtlCopyMemory(&KdVmDataBuffer[KdVmBufferPos], Data, DataSize);
74     KdVmBufferPos += DataSize;
75     return TRUE;
76 }
77 
78 static
79 BOOLEAN
KdVmAddCommandToBuffer(_In_ UCHAR Command,_In_ PVOID Buffer,_In_ SIZE_T BufferSize)80 KdVmAddCommandToBuffer(
81     _In_ UCHAR Command,
82     _In_ PVOID Buffer,
83     _In_ SIZE_T BufferSize)
84 {
85     KDVM_CMD_HEADER Header;
86 
87     RtlCopyMemory(&Header.Magic, KdVmCmdMagic, sizeof(Header.Magic));
88     Header.Command = Command;
89 
90     if (!KdVmAddToBuffer(&Header, sizeof(Header)))
91         return FALSE;
92 
93     if (!KdVmAddToBuffer(Buffer, BufferSize))
94         return FALSE;
95 
96     return TRUE;
97 }
98 
99 static
100 PVOID
KdVmSendReceive(_Out_ PULONG ReceiveDataSize)101 KdVmSendReceive(
102     _Out_ PULONG ReceiveDataSize)
103 {
104     PVOID ReceiveData;
105     PKDVM_RECEIVE_HEADER ReceiveHeader;
106 
107     KdVmKdVmExchangeData(&ReceiveData, ReceiveDataSize);
108     ReceiveHeader = ReceiveData;
109 
110     if (*ReceiveDataSize < sizeof(*ReceiveHeader))
111     {
112         KDDBGPRINT("KdVmSendReceive: received data too small: 0x%x\n", *ReceiveDataSize);
113         *ReceiveDataSize = 0;
114         return NULL;
115     }
116 
117     if (ReceiveHeader->Id != 0x2031 /* '01' */)
118     {
119         KDDBGPRINT("KdVmSendReceive: got invalid Id: 0x%x\n", ReceiveHeader->Id);
120         *ReceiveDataSize = 0;
121         return NULL;
122     }
123 
124     if (!RtlEqualMemory(ReceiveHeader->Magic, KdVmReplyMagic, 9))
125     {
126         KDDBGPRINT("KdVmSendReceive: got invalid Magic: '%*s'\n",
127                    sizeof(KdVmReplyMagic), ReceiveHeader->Magic);
128         *ReceiveDataSize = 0;
129         return NULL;
130     }
131 
132     *ReceiveDataSize -= sizeof(*ReceiveHeader);
133     return (PVOID)(ReceiveHeader + 1);
134 }
135 
136 static
137 NTSTATUS
KdVmNegotiateProtocolVersions(VOID)138 KdVmNegotiateProtocolVersions(VOID)
139 {
140     ULONG Version = KDRPC_PROTOCOL_VERSION;
141     ULONG ReceivedSize;
142     PULONG ReceivedVersion;
143     KDDBGPRINT("KdVmNegotiateProtocolVersions()\n");
144 
145     /* Prepare the buffer */
146     KdVmPrepareBuffer();
147 
148     if (!KdVmAddCommandToBuffer(KDVM_CMD_VersionReport, &Version, sizeof(Version)))
149     {
150         KDDBGPRINT("Failed to do VersionReport\n");
151         return STATUS_CONNECTION_REFUSED;
152     }
153 
154     ReceivedVersion = KdVmSendReceive(&ReceivedSize);
155     if (ReceivedSize != sizeof(ULONG))
156     {
157         KDDBGPRINT("Invalid size for VersionReport: %lx\n", ReceivedSize);
158         return STATUS_CONNECTION_REFUSED;
159     }
160 
161     if (*ReceivedVersion != KDRPC_PROTOCOL_VERSION)
162     {
163         KDDBGPRINT("Invalid Version: %lx\n", *ReceivedVersion);
164         return STATUS_CONNECTION_REFUSED; //STATUS_PROTOCOL_NOT_SUPPORTED;
165     }
166 
167     return STATUS_SUCCESS;
168 }
169 
170 static
171 BOOLEAN
TestConnectionOnChannel(VOID)172 TestConnectionOnChannel(VOID)
173 {
174     UCHAR TestBuffer[KDRPC_TEST_BUFFER_SIZE];
175     PUCHAR ReceivedBuffer;
176     ULONG i, ReceivedSize;
177 
178     /* Prepare the buffer */
179     KdVmPrepareBuffer();
180 
181     for (i = 0; i < sizeof(TestBuffer); i++)
182         TestBuffer[i] = (UCHAR)i;
183 
184     if (!KdVmAddCommandToBuffer(KDVM_CMD_TestConnection, TestBuffer, sizeof(TestBuffer)))
185     {
186         KDDBGPRINT("Failed to do TestConnection\n");
187         return FALSE;
188     }
189 
190     ReceivedBuffer = KdVmSendReceive(&ReceivedSize);
191     if (ReceivedSize != sizeof(TestBuffer))
192     {
193         KDDBGPRINT("Invalid size for TestConnection: %lx\n", ReceivedSize);
194         return FALSE;
195     }
196 
197     for (i = 0; i < sizeof(TestBuffer); i++)
198     {
199         if (ReceivedBuffer[i] != (UCHAR)(i ^ 0x55))
200         {
201             KDDBGPRINT("Wrong test data @ %lx, expected %x, got %x\n",
202                        i, (UCHAR)(i ^ 0x55), TestBuffer[i]);
203             return FALSE;
204         }
205     }
206 
207     KDDBGPRINT("TestConnectionOnChannel: success\n");
208     return TRUE;
209 }
210 
211 static
212 BOOLEAN
KdVmTestConnectionWithHost(VOID)213 KdVmTestConnectionWithHost(VOID)
214 {
215     ULONG i, j;
216     KDDBGPRINT("KdVmTestConnectionWithHost()\n");
217 
218     for (j = 0; j < 2; j++)
219     {
220         //VMWareRPC::OpenChannel
221         for (i = 0; i < CONNECTION_TEST_ROUNDS / 2; i++)
222         {
223             if (!TestConnectionOnChannel())
224             {
225                 return FALSE;
226             }
227         }
228     }
229 
230     return TRUE;
231 }
232 
233 /* PUBLIC FUNCTIONS ***********************************************************/
234 
235 NTSTATUS
236 NTAPI
KdD0Transition(VOID)237 KdD0Transition(VOID)
238 {
239     /* Nothing to do */
240     return STATUS_SUCCESS;
241 }
242 
243 NTSTATUS
244 NTAPI
KdD3Transition(VOID)245 KdD3Transition(VOID)
246 {
247     /* Nothing to do */
248     return STATUS_SUCCESS;
249 }
250 
251 NTSTATUS
252 NTAPI
KdSave(_In_ BOOLEAN SleepTransition)253 KdSave(
254     _In_ BOOLEAN SleepTransition)
255 {
256     /* Nothing to do */
257     return STATUS_SUCCESS;
258 }
259 
260 NTSTATUS
261 NTAPI
KdRestore(_In_ BOOLEAN SleepTransition)262 KdRestore(
263     _In_ BOOLEAN SleepTransition)
264 {
265     /* Nothing to do */
266     return STATUS_SUCCESS;
267 }
268 
269 /******************************************************************************
270  * \name KdDebuggerInitialize0
271  * \brief Phase 0 initialization.
272  * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
273  * \return Status
274  */
275 NTSTATUS
276 NTAPI
KdDebuggerInitialize0(_In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock)277 KdDebuggerInitialize0(
278     _In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock)
279 {
280     PCHAR CommandLine, PortString;
281     NTSTATUS Status;
282 
283     /* Check if we have a LoaderBlock */
284     if (LoaderBlock != NULL)
285     {
286         /* HACK */
287         KdpDbgPrint = LoaderBlock->u.I386.CommonDataArea;
288         KDDBGPRINT("KdDebuggerInitialize0\n");
289 
290         /* Get the Command Line */
291         CommandLine = LoaderBlock->LoadOptions;
292 
293         /* Upcase it */
294         _strupr(CommandLine);
295 
296         /* Check if we got the /DEBUGPORT parameter */
297         PortString = strstr(CommandLine, "DEBUGPORT");
298         if (PortString)
299         {
300             /* Move past the actual string, to reach the port*/
301             PortString += strlen("DEBUGPORT");
302 
303             /* Now get past any spaces and skip the equal sign */
304             while (*PortString == ' ') PortString++;
305             PortString++;
306 
307             /* Do we have a serial port? */
308             if (strncmp(PortString, "VBOX", 4) != 0)
309             {
310                 KDDBGPRINT("Invalid debugport: '%s'\n", CommandLine);
311                 return STATUS_INVALID_PARAMETER;
312             }
313         }
314     }
315 
316     /* Get the physical address of the data buffer */
317     KdVmBufferPhysicalAddress = MmGetPhysicalAddress(KdVmDataBuffer);
318     KDDBGPRINT("KdVmBufferPhysicalAddress = %llx\n", KdVmBufferPhysicalAddress.QuadPart);
319 
320     Status = KdVmNegotiateProtocolVersions();
321     if (!NT_SUCCESS(Status))
322         return Status;
323 
324     if (!KdVmTestConnectionWithHost())
325         return STATUS_CONNECTION_REFUSED;
326 
327     return STATUS_SUCCESS;
328 }
329 
330 /******************************************************************************
331  * \name KdDebuggerInitialize1
332  * \brief Phase 1 initialization.
333  * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
334  * \return Status
335  */
336 NTSTATUS
337 NTAPI
KdDebuggerInitialize1(_In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock)338 KdDebuggerInitialize1(
339     _In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock)
340 {
341     /* Nothing to do */
342     KDDBGPRINT("KdDebuggerInitialize1()\n");
343     return STATUS_SUCCESS;
344 }
345 
346 VOID
347 NTAPI
KdSendPacket(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData,_Inout_ PKD_CONTEXT KdContext)348 KdSendPacket(
349     _In_ ULONG PacketType,
350     _In_ PSTRING MessageHeader,
351     _In_ PSTRING MessageData,
352     _Inout_ PKD_CONTEXT KdContext)
353 {
354     KDVM_SEND_PKT_REQUEST SendPktRequest;
355     PKDVM_SEND_PKT_RESULT SendPktResult;
356     ULONG ReceivedSize;
357     KDDBGPRINT("KdSendPacket(0x%lx, ...)\n", PacketType);
358 
359     do
360     {
361 
362         RtlZeroMemory(&SendPktRequest, sizeof(SendPktRequest));
363 
364         SendPktRequest.PacketType = PacketType;
365         SendPktRequest.Info.KdDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
366         SendPktRequest.Info.KdDebuggerEnabledAvailable = 1;
367         SendPktRequest.Info.KdDebuggerEnabled = SharedUserData->KdDebuggerEnabled;
368 
369         if (MessageHeader != NULL)
370         {
371             SendPktRequest.MessageHeader.Length = MessageHeader->Length;
372             SendPktRequest.MessageHeader.MaximumLength = MessageHeader->MaximumLength;
373             SendPktRequest.HeaderSize = MessageHeader->Length;
374         }
375 
376         if (MessageData != NULL)
377         {
378             SendPktRequest.MessageData.Length = MessageData->Length;
379             SendPktRequest.MessageData.MaximumLength = MessageData->MaximumLength;
380             SendPktRequest.DataSize = MessageData->Length;
381         }
382 
383         if (KdContext != NULL)
384         {
385             RtlCopyMemory(&SendPktRequest.KdContext,
386                           KdContext,
387                           sizeof(SendPktRequest.KdContext));
388         }
389 
390 
391         /* Prepare the buffer */
392         KdVmPrepareBuffer();
393 
394         if (!KdVmAddCommandToBuffer(KDVM_CMD_SendPacket, &SendPktRequest, sizeof(SendPktRequest)))
395         {
396             KDDBGPRINT("KdSendPacket: Failed to add SendPacket command\n");
397             return;
398         }
399 
400         if (MessageHeader != NULL)
401         {
402             if (!KdVmAddToBuffer(MessageHeader->Buffer, MessageHeader->Length))
403             {
404                 KDDBGPRINT("KdSendPacket: Failed to add MessageHeader\n");
405                 return;
406             }
407         }
408 
409         if (MessageData != NULL)
410         {
411             if (!KdVmAddToBuffer(MessageData->Buffer, MessageData->Length))
412             {
413                 KDDBGPRINT("KdSendPacket: Failed to add MessageData\n");
414                 return;
415             }
416         }
417 
418         SendPktResult = KdVmSendReceive(&ReceivedSize);
419         if (ReceivedSize != sizeof(*SendPktResult))
420         {
421             KDDBGPRINT("KdSendPacket: Invalid size for SendPktResult: %lx\n", ReceivedSize);
422             return;
423         }
424 
425         if (KdContext != NULL)
426         {
427             RtlCopyMemory(KdContext,
428                           &SendPktResult->KdContext,
429                           sizeof(SendPktResult->KdContext));
430         }
431 
432         KD_DEBUGGER_NOT_PRESENT = SendPktResult->Info.KdDebuggerNotPresent;
433         if (SendPktResult->Info.KdDebuggerEnabledAvailable)
434             SharedUserData->KdDebuggerEnabled = SendPktResult->Info.KdDebuggerEnabled != 0;
435 
436         if (SendPktResult->Info.RetryKdSendPacket)
437         {
438             KDDBGPRINT("KdSendPacket: RetryKdSendPacket!\n");
439         }
440 
441     } while (SendPktResult->Info.RetryKdSendPacket);
442 
443     KDDBGPRINT("KdSendPacket: Success!\n");
444 }
445 
446 
447 KDP_STATUS
448 NTAPI
KdReceivePacket(_In_ ULONG PacketType,_Out_ PSTRING MessageHeader,_Out_ PSTRING MessageData,_Out_ PULONG DataLength,_Inout_opt_ PKD_CONTEXT KdContext)449 KdReceivePacket(
450     _In_ ULONG PacketType,
451     _Out_ PSTRING MessageHeader,
452     _Out_ PSTRING MessageData,
453     _Out_ PULONG DataLength,
454     _Inout_opt_ PKD_CONTEXT KdContext)
455 {
456     KDVM_RECV_PKT_REQUEST RecvPktRequest;
457     PKDVM_RECV_PKT_RESULT RecvPktResult;
458     ULONG ReceivedSize, ExpectedSize;
459     PUCHAR Buffer;
460     KDDBGPRINT("KdReceivePacket(0x%lx, ...)\n", PacketType);
461 
462     /* Prepare the buffer */
463     KdVmPrepareBuffer();
464 
465     RtlZeroMemory(&RecvPktRequest, sizeof(RecvPktRequest));
466 
467     RecvPktRequest.PacketType = PacketType;
468     RecvPktRequest.Info.KdDebuggerNotPresent = KD_DEBUGGER_NOT_PRESENT;
469     RecvPktRequest.Info.KdDebuggerEnabledAvailable = 1;
470     RecvPktRequest.Info.KdDebuggerEnabled = SharedUserData->KdDebuggerEnabled;
471 
472     if (MessageHeader != NULL)
473     {
474         RecvPktRequest.MessageHeader.Length = MessageHeader->Length;
475         RecvPktRequest.MessageHeader.MaximumLength = MessageHeader->MaximumLength;
476     }
477 
478     if (MessageData != NULL)
479     {
480         RecvPktRequest.MessageData.Length = MessageData->Length;
481         RecvPktRequest.MessageData.MaximumLength = MessageData->MaximumLength;
482     }
483 
484     if (KdContext != NULL)
485     {
486         RtlCopyMemory(&RecvPktRequest.KdContext,
487                       KdContext,
488                       sizeof(RecvPktRequest.KdContext));
489     }
490 
491     if (!KdVmAddCommandToBuffer(KDVM_CMD_ReceivePacket, &RecvPktRequest, sizeof(RecvPktRequest)))
492     {
493         KDDBGPRINT("KdReceivePacket: Failed to add SendPacket command\n");
494         return KDP_PACKET_RESEND;
495     }
496 
497     RecvPktResult = KdVmSendReceive(&ReceivedSize);
498     if (ReceivedSize < sizeof(*RecvPktResult))
499     {
500         KDDBGPRINT("KdReceivePacket: Invalid size for RecvPktResult: %lx\n", ReceivedSize);
501         return KDP_PACKET_RESEND;
502     }
503 
504     ExpectedSize = sizeof(*RecvPktResult) +
505                    RecvPktResult->HeaderSize +
506                    RecvPktResult->DataSize;
507     if (ReceivedSize != ExpectedSize)
508     {
509         KDDBGPRINT("KdReceivePacket: Invalid size for RecvPktResult: %lu, expected %lu\n",
510                    ReceivedSize, ExpectedSize);
511         return KDP_PACKET_RESEND;
512     }
513 
514     if (KdContext != NULL)
515     {
516         RtlCopyMemory(KdContext,
517                       &RecvPktResult->KdContext,
518                       sizeof(RecvPktResult->KdContext));
519     }
520 
521     Buffer = (PUCHAR)(RecvPktResult + 1);
522     if (MessageHeader != NULL)
523     {
524         MessageHeader->Length = RecvPktResult->MessageHeader.Length;
525         if ((MessageHeader->Buffer != NULL) &&
526             (MessageHeader->MaximumLength >= RecvPktResult->HeaderSize))
527         {
528             RtlCopyMemory(MessageHeader->Buffer,
529                           Buffer,
530                           RecvPktResult->HeaderSize);
531         }
532         else
533         {
534             KDDBGPRINT("MessageHeader not good\n");
535         }
536     }
537 
538     Buffer += RecvPktResult->HeaderSize;
539     if (MessageData != NULL)
540     {
541         MessageData->Length = RecvPktResult->MessageData.Length;
542         if ((MessageData->Buffer != NULL) &&
543             (MessageData->MaximumLength >= RecvPktResult->DataSize))
544         {
545             RtlCopyMemory(MessageData->Buffer,
546                           Buffer,
547                           RecvPktResult->DataSize);
548         }
549         else
550         {
551             KDDBGPRINT("MessageData not good\n");
552         }
553     }
554 
555     if (DataLength != NULL)
556         *DataLength = RecvPktResult->FullSize;
557 
558     KDDBGPRINT("KdReceivePacket: returning status %u\n", RecvPktResult->KdStatus);
559     return RecvPktResult->KdStatus;
560 }
561 
562