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 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 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 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 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 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 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 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 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 237 KdD0Transition(VOID) 238 { 239 /* Nothing to do */ 240 return STATUS_SUCCESS; 241 } 242 243 NTSTATUS 244 NTAPI 245 KdD3Transition(VOID) 246 { 247 /* Nothing to do */ 248 return STATUS_SUCCESS; 249 } 250 251 NTSTATUS 252 NTAPI 253 KdSave( 254 _In_ BOOLEAN SleepTransition) 255 { 256 /* Nothing to do */ 257 return STATUS_SUCCESS; 258 } 259 260 NTSTATUS 261 NTAPI 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 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 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 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 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