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