1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/kd/kdio.c 5 * PURPOSE: NT Kernel Debugger Input/Output Functions 6 * 7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #include <reactos/buildno.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* GLOBALS *******************************************************************/ 19 20 #define KdpBufferSize (1024 * 512) 21 static BOOLEAN KdpLoggingEnabled = FALSE; 22 static BOOLEAN KdpLoggingStarting = FALSE; 23 static PCHAR KdpDebugBuffer = NULL; 24 static volatile ULONG KdpCurrentPosition = 0; 25 static volatile ULONG KdpFreeBytes = 0; 26 static KSPIN_LOCK KdpDebugLogSpinLock; 27 static KEVENT KdpLoggerThreadEvent; 28 static HANDLE KdpLogFileHandle; 29 ANSI_STRING KdpLogFileName = RTL_CONSTANT_STRING("\\SystemRoot\\debug.log"); 30 extern ULONG ExpInitializationPhase; 31 32 static KSPIN_LOCK KdpSerialSpinLock; 33 ULONG SerialPortNumber = DEFAULT_DEBUG_PORT; 34 CPPORT SerialPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0}; 35 36 #define KdpScreenLineLengthDefault 80 37 static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = ""; 38 static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0; 39 40 const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; 41 PCHAR KdpDmesgBuffer = NULL; 42 volatile ULONG KdpDmesgCurrentPosition = 0; 43 volatile ULONG KdpDmesgFreeBytes = 0; 44 volatile ULONG KdbDmesgTotalWritten = 0; 45 volatile BOOLEAN KdbpIsInDmesgMode = FALSE; 46 static KSPIN_LOCK KdpDmesgLogSpinLock; 47 48 KDP_DEBUG_MODE KdpDebugMode; 49 LIST_ENTRY KdProviders = {&KdProviders, &KdProviders}; 50 KD_DISPATCH_TABLE DispatchTable[KdMax]; 51 52 PKDP_INIT_ROUTINE InitRoutines[KdMax] = 53 { 54 KdpScreenInit, 55 KdpSerialInit, 56 KdpDebugLogInit, 57 #ifdef KDBG 58 KdpKdbgInit 59 #endif 60 }; 61 62 static ULONG KdbgNextApiNumber = DbgKdContinueApi; 63 static CONTEXT KdbgContext; 64 static EXCEPTION_RECORD64 KdbgExceptionRecord; 65 static BOOLEAN KdbgFirstChanceException; 66 static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS; 67 68 /* LOCKING FUNCTIONS *********************************************************/ 69 70 KIRQL 71 NTAPI 72 KdbpAcquireLock( 73 _In_ PKSPIN_LOCK SpinLock) 74 { 75 KIRQL OldIrql; 76 77 /* Acquire the spinlock without waiting at raised IRQL */ 78 while (TRUE) 79 { 80 /* Loop until the spinlock becomes available */ 81 while (!KeTestSpinLock(SpinLock)); 82 83 /* Spinlock is free, raise IRQL to high level */ 84 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 85 86 /* Try to get the spinlock */ 87 if (KeTryToAcquireSpinLockAtDpcLevel(SpinLock)) 88 break; 89 90 /* Someone else got the spinlock, lower IRQL back */ 91 KeLowerIrql(OldIrql); 92 } 93 94 return OldIrql; 95 } 96 97 VOID 98 NTAPI 99 KdbpReleaseLock( 100 _In_ PKSPIN_LOCK SpinLock, 101 _In_ KIRQL OldIrql) 102 { 103 /* Release the spinlock */ 104 KiReleaseSpinLock(SpinLock); 105 // KeReleaseSpinLockFromDpcLevel(SpinLock); 106 107 /* Restore the old IRQL */ 108 KeLowerIrql(OldIrql); 109 } 110 111 /* FILE DEBUG LOG FUNCTIONS **************************************************/ 112 113 static VOID 114 NTAPI 115 KdpLoggerThread(PVOID Context) 116 { 117 ULONG beg, end, num; 118 IO_STATUS_BLOCK Iosb; 119 120 ASSERT(ExGetPreviousMode() == KernelMode); 121 122 KdpLoggingEnabled = TRUE; 123 124 while (TRUE) 125 { 126 KeWaitForSingleObject(&KdpLoggerThreadEvent, Executive, KernelMode, FALSE, NULL); 127 128 /* Bug */ 129 /* Keep KdpCurrentPosition and KdpFreeBytes values in local 130 * variables to avoid their possible change from Producer part, 131 * KdpPrintToLogFile function 132 */ 133 end = KdpCurrentPosition; 134 num = KdpFreeBytes; 135 136 /* Now securely calculate values, based on local variables */ 137 beg = (end + num) % KdpBufferSize; 138 num = KdpBufferSize - num; 139 140 /* Nothing to do? */ 141 if (num == 0) 142 continue; 143 144 if (end > beg) 145 { 146 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 147 KdpDebugBuffer + beg, num, NULL, NULL); 148 } 149 else 150 { 151 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 152 KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL); 153 154 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb, 155 KdpDebugBuffer, end, NULL, NULL); 156 } 157 158 (VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num); 159 } 160 } 161 162 static VOID 163 NTAPI 164 KdpPrintToLogFile(PCHAR String, 165 ULONG Length) 166 { 167 KIRQL OldIrql; 168 ULONG beg, end, num; 169 BOOLEAN DoReinit = FALSE; 170 171 if (KdpDebugBuffer == NULL) return; 172 173 /* Acquire the printing spinlock without waiting at raised IRQL */ 174 OldIrql = KdbpAcquireLock(&KdpDebugLogSpinLock); 175 176 beg = KdpCurrentPosition; 177 num = KdpFreeBytes; 178 if (Length < num) 179 num = Length; 180 181 if (num != 0) 182 { 183 end = (beg + num) % KdpBufferSize; 184 KdpCurrentPosition = end; 185 KdpFreeBytes -= num; 186 187 if (end > beg) 188 { 189 RtlCopyMemory(KdpDebugBuffer + beg, String, num); 190 } 191 else 192 { 193 RtlCopyMemory(KdpDebugBuffer + beg, String, KdpBufferSize - beg); 194 RtlCopyMemory(KdpDebugBuffer, String + KdpBufferSize - beg, end); 195 } 196 } 197 198 /* Release the spinlock */ 199 if (OldIrql == PASSIVE_LEVEL && !KdpLoggingStarting && !KdpLoggingEnabled && ExpInitializationPhase >= 2) 200 { 201 DoReinit = TRUE; 202 } 203 KdbpReleaseLock(&KdpDebugLogSpinLock, OldIrql); 204 205 if (DoReinit) 206 { 207 KdpLoggingStarting = TRUE; 208 KdpDebugLogInit(NULL, 3); 209 } 210 211 /* Signal the logger thread */ 212 if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled) 213 KeSetEvent(&KdpLoggerThreadEvent, IO_NO_INCREMENT, FALSE); 214 } 215 216 VOID 217 NTAPI 218 KdpDebugLogInit(PKD_DISPATCH_TABLE DispatchTable, 219 ULONG BootPhase) 220 { 221 NTSTATUS Status; 222 UNICODE_STRING FileName; 223 OBJECT_ATTRIBUTES ObjectAttributes; 224 IO_STATUS_BLOCK Iosb; 225 HANDLE ThreadHandle; 226 KPRIORITY Priority; 227 228 if (!KdpDebugMode.File) return; 229 230 if (BootPhase == 0) 231 { 232 /* Write out the functions that we support for now */ 233 DispatchTable->KdpInitRoutine = KdpDebugLogInit; 234 DispatchTable->KdpPrintRoutine = KdpPrintToLogFile; 235 236 /* Register as a Provider */ 237 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 238 } 239 else if (BootPhase == 1) 240 { 241 /* Allocate a buffer for debug log */ 242 KdpDebugBuffer = ExAllocatePoolZero(NonPagedPool, 243 KdpBufferSize, 244 TAG_KDBG); 245 if (!KdpDebugBuffer) 246 { 247 KdpDebugMode.File = FALSE; 248 return; 249 } 250 KdpFreeBytes = KdpBufferSize; 251 252 /* Initialize spinlock */ 253 KeInitializeSpinLock(&KdpDebugLogSpinLock); 254 255 HalDisplayString("\r\n File log debugging enabled\r\n\r\n"); 256 } 257 else if (BootPhase == 3) 258 { 259 /* Setup the log name */ 260 Status = RtlAnsiStringToUnicodeString(&FileName, &KdpLogFileName, TRUE); 261 if (!NT_SUCCESS(Status)) return; 262 263 InitializeObjectAttributes(&ObjectAttributes, 264 &FileName, 265 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 266 NULL, 267 NULL); 268 269 /* Create the log file */ 270 Status = ZwCreateFile(&KdpLogFileHandle, 271 FILE_APPEND_DATA | SYNCHRONIZE, 272 &ObjectAttributes, 273 &Iosb, 274 NULL, 275 FILE_ATTRIBUTE_NORMAL, 276 FILE_SHARE_READ, 277 FILE_SUPERSEDE, 278 FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT, 279 NULL, 280 0); 281 282 RtlFreeUnicodeString(&FileName); 283 284 if (!NT_SUCCESS(Status)) 285 { 286 DPRINT1("Failed to open log file: 0x%08x\n", Status); 287 return; 288 } 289 290 KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE); 291 292 /* Create the logger thread */ 293 Status = PsCreateSystemThread(&ThreadHandle, 294 THREAD_ALL_ACCESS, 295 NULL, 296 NULL, 297 NULL, 298 KdpLoggerThread, 299 NULL); 300 if (!NT_SUCCESS(Status)) 301 { 302 ZwClose(KdpLogFileHandle); 303 return; 304 } 305 306 Priority = 7; 307 ZwSetInformationThread(ThreadHandle, 308 ThreadPriority, 309 &Priority, 310 sizeof(Priority)); 311 312 ZwClose(ThreadHandle); 313 } 314 } 315 316 /* SERIAL FUNCTIONS **********************************************************/ 317 318 static VOID 319 NTAPI 320 KdpSerialPrint(PCHAR String, 321 ULONG Length) 322 { 323 PCHAR pch = String; 324 KIRQL OldIrql; 325 326 /* Acquire the printing spinlock without waiting at raised IRQL */ 327 OldIrql = KdbpAcquireLock(&KdpSerialSpinLock); 328 329 /* Output the string */ 330 while (pch < String + Length && *pch) 331 { 332 if (*pch == '\n') 333 { 334 KdPortPutByteEx(&SerialPortInfo, '\r'); 335 } 336 KdPortPutByteEx(&SerialPortInfo, *pch); 337 pch++; 338 } 339 340 /* Release the spinlock */ 341 KdbpReleaseLock(&KdpSerialSpinLock, OldIrql); 342 } 343 344 VOID 345 NTAPI 346 KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable, 347 ULONG BootPhase) 348 { 349 if (!KdpDebugMode.Serial) return; 350 351 if (BootPhase == 0) 352 { 353 /* Write out the functions that we support for now */ 354 DispatchTable->KdpInitRoutine = KdpSerialInit; 355 DispatchTable->KdpPrintRoutine = KdpSerialPrint; 356 357 /* Initialize the Port */ 358 if (!KdPortInitializeEx(&SerialPortInfo, SerialPortNumber)) 359 { 360 KdpDebugMode.Serial = FALSE; 361 return; 362 } 363 KdComPortInUse = SerialPortInfo.Address; 364 365 /* Initialize spinlock */ 366 KeInitializeSpinLock(&KdpSerialSpinLock); 367 368 /* Register as a Provider */ 369 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 370 } 371 else if (BootPhase == 1) 372 { 373 HalDisplayString("\r\n Serial debugging enabled\r\n\r\n"); 374 } 375 } 376 377 /* SCREEN FUNCTIONS **********************************************************/ 378 379 VOID 380 KdpScreenAcquire(VOID) 381 { 382 if (InbvIsBootDriverInstalled() /* && 383 !InbvCheckDisplayOwnership() */) 384 { 385 /* Acquire ownership and reset the display */ 386 InbvAcquireDisplayOwnership(); 387 InbvResetDisplay(); 388 InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK); 389 InbvSetTextColor(BV_COLOR_WHITE); 390 InbvInstallDisplayStringFilter(NULL); 391 InbvEnableDisplayString(TRUE); 392 InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); 393 } 394 } 395 396 // extern VOID NTAPI InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned); 397 398 VOID 399 KdpScreenRelease(VOID) 400 { 401 if (InbvIsBootDriverInstalled()&& 402 InbvCheckDisplayOwnership()) 403 { 404 /* Release the display */ 405 // InbvSetDisplayOwnership(FALSE); 406 InbvNotifyDisplayOwnershipLost(NULL); 407 } 408 } 409 410 /* 411 * Screen debug logger function KdpScreenPrint() writes text strings into 412 * KdpDmesgBuffer, using it as a circular buffer. KdpDmesgBuffer contents could 413 * be later (re)viewed using dmesg command of kdbg. KdpScreenPrint() protects 414 * KdpDmesgBuffer from simultaneous writes by use of KdpDmesgLogSpinLock. 415 */ 416 static VOID 417 NTAPI 418 KdpScreenPrint(PCHAR String, 419 ULONG Length) 420 { 421 PCHAR pch = String; 422 KIRQL OldIrql; 423 ULONG beg, end, num; 424 425 while (pch < String + Length && *pch) 426 { 427 if (*pch == '\b') 428 { 429 /* HalDisplayString does not support '\b'. Workaround it and use '\r' */ 430 if (KdpScreenLineLength > 0) 431 { 432 /* Remove last character from buffer */ 433 KdpScreenLineBuffer[--KdpScreenLineLength] = '\0'; 434 KdpScreenLineBufferPos = KdpScreenLineLength; 435 436 /* Clear row and print line again */ 437 HalDisplayString("\r"); 438 HalDisplayString(KdpScreenLineBuffer); 439 } 440 } 441 else 442 { 443 KdpScreenLineBuffer[KdpScreenLineLength++] = *pch; 444 KdpScreenLineBuffer[KdpScreenLineLength] = '\0'; 445 } 446 447 if (*pch == '\n' || KdpScreenLineLength == KdpScreenLineLengthDefault) 448 { 449 /* Print buffered characters */ 450 if (KdpScreenLineBufferPos != KdpScreenLineLength) 451 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); 452 453 /* Clear line buffer */ 454 KdpScreenLineBuffer[0] = '\0'; 455 KdpScreenLineLength = KdpScreenLineBufferPos = 0; 456 } 457 458 ++pch; 459 } 460 461 /* Print buffered characters */ 462 if (KdpScreenLineBufferPos != KdpScreenLineLength) 463 { 464 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); 465 KdpScreenLineBufferPos = KdpScreenLineLength; 466 } 467 468 /* Dmesg: store the string in the buffer to show it later */ 469 if (KdbpIsInDmesgMode) 470 return; 471 472 if (KdpDmesgBuffer == NULL) 473 return; 474 475 /* Acquire the printing spinlock without waiting at raised IRQL */ 476 OldIrql = KdbpAcquireLock(&KdpDmesgLogSpinLock); 477 478 /* Invariant: always_true(KdpDmesgFreeBytes == KdpDmesgBufferSize); 479 * set num to min(KdpDmesgFreeBytes, Length). 480 */ 481 num = (Length < KdpDmesgFreeBytes) ? Length : KdpDmesgFreeBytes; 482 beg = KdpDmesgCurrentPosition; 483 if (num != 0) 484 { 485 end = (beg + num) % KdpDmesgBufferSize; 486 if (end > beg) 487 { 488 RtlCopyMemory(KdpDmesgBuffer + beg, String, Length); 489 } 490 else 491 { 492 RtlCopyMemory(KdpDmesgBuffer + beg, String, KdpDmesgBufferSize - beg); 493 RtlCopyMemory(KdpDmesgBuffer, String + (KdpDmesgBufferSize - beg), end); 494 } 495 KdpDmesgCurrentPosition = end; 496 497 /* Counting the total bytes written */ 498 KdbDmesgTotalWritten += num; 499 } 500 501 /* Release the spinlock */ 502 KdbpReleaseLock(&KdpDmesgLogSpinLock, OldIrql); 503 504 /* Optional step(?): find out a way to notify about buffer exhaustion, 505 * and possibly fall into kbd to use dmesg command: user will read 506 * debug strings before they will be wiped over by next writes. 507 */ 508 } 509 510 VOID 511 NTAPI 512 KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable, 513 ULONG BootPhase) 514 { 515 if (!KdpDebugMode.Screen) return; 516 517 if (BootPhase == 0) 518 { 519 /* Write out the functions that we support for now */ 520 DispatchTable->KdpInitRoutine = KdpScreenInit; 521 DispatchTable->KdpPrintRoutine = KdpScreenPrint; 522 523 /* Register as a Provider */ 524 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); 525 } 526 else if (BootPhase == 1) 527 { 528 /* Allocate a buffer for dmesg log buffer. +1 for terminating null, 529 * see kdbp_cli.c:KdbpCmdDmesg()/2 530 */ 531 KdpDmesgBuffer = ExAllocatePoolZero(NonPagedPool, 532 KdpDmesgBufferSize + 1, 533 TAG_KDBG); 534 /* Ignore failure if KdpDmesgBuffer is NULL */ 535 KdpDmesgFreeBytes = KdpDmesgBufferSize; 536 KdbDmesgTotalWritten = 0; 537 538 /* Take control of the display */ 539 KdpScreenAcquire(); 540 541 /* Initialize spinlock */ 542 KeInitializeSpinLock(&KdpDmesgLogSpinLock); 543 544 HalDisplayString("\r\n Screen debugging enabled\r\n\r\n"); 545 } 546 } 547 548 #ifdef KDBG 549 /* KDBG FUNCTIONS ************************************************************/ 550 551 /* NOTE: This may be moved completely into kdb_symbols.c */ 552 VOID NTAPI 553 KdbInitialize(PKD_DISPATCH_TABLE DispatchTable, ULONG BootPhase); 554 555 VOID 556 NTAPI 557 KdpKdbgInit( 558 PKD_DISPATCH_TABLE DispatchTable, 559 ULONG BootPhase) 560 { 561 /* Forward the call */ 562 KdbInitialize(DispatchTable, BootPhase); 563 } 564 #endif 565 566 567 /* GENERAL FUNCTIONS *********************************************************/ 568 569 BOOLEAN 570 NTAPI 571 KdpPrintString( 572 _In_ PSTRING Output); 573 574 extern STRING KdbPromptString; 575 576 VOID 577 NTAPI 578 KdSendPacket( 579 _In_ ULONG PacketType, 580 _In_ PSTRING MessageHeader, 581 _In_opt_ PSTRING MessageData, 582 _Inout_ PKD_CONTEXT Context) 583 { 584 if (PacketType == PACKET_TYPE_KD_DEBUG_IO) 585 { 586 ULONG ApiNumber = ((PDBGKD_DEBUG_IO)MessageHeader->Buffer)->ApiNumber; 587 PLIST_ENTRY CurrentEntry; 588 PKD_DISPATCH_TABLE CurrentTable; 589 590 /* Validate API call */ 591 if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO)) 592 return; 593 if ((ApiNumber != DbgKdPrintStringApi) && 594 (ApiNumber != DbgKdGetStringApi)) 595 { 596 return; 597 } 598 if (!MessageData) 599 return; 600 601 /* NOTE: MessageData->Length should be equal to 602 * DebugIo.u.PrintString.LengthOfString, or to 603 * DebugIo.u.GetString.LengthOfPromptString */ 604 605 if (!KdpDebugMode.Value) 606 return; 607 608 /* Call the registered handlers */ 609 CurrentEntry = KdProviders.Flink; 610 while (CurrentEntry != &KdProviders) 611 { 612 /* Get the current table */ 613 CurrentTable = CONTAINING_RECORD(CurrentEntry, 614 KD_DISPATCH_TABLE, 615 KdProvidersList); 616 617 /* Call it */ 618 CurrentTable->KdpPrintRoutine(MessageData->Buffer, MessageData->Length); 619 620 /* Next Table */ 621 CurrentEntry = CurrentEntry->Flink; 622 } 623 return; 624 } 625 else if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64) 626 { 627 PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer; 628 if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange) 629 { 630 #ifdef KDBG 631 PLDR_DATA_TABLE_ENTRY LdrEntry; 632 /* Load symbols. Currently implemented only for KDBG! */ 633 if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry)) 634 { 635 KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols); 636 } 637 #endif 638 return; 639 } 640 else if (WaitStateChange->NewState == DbgKdExceptionStateChange) 641 { 642 KdbgNextApiNumber = DbgKdGetContextApi; 643 KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord; 644 KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance; 645 return; 646 } 647 } 648 else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 649 { 650 PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 651 if (ManipulateState->ApiNumber == DbgKdGetContextApi) 652 { 653 KD_CONTINUE_TYPE Result; 654 655 #ifdef KDBG 656 /* Check if this is an assertion failure */ 657 if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE) 658 { 659 /* Bump EIP to the instruction following the int 2C */ 660 KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2); 661 } 662 663 Result = KdbEnterDebuggerException(&KdbgExceptionRecord, 664 KdbgContext.SegCs & 1, 665 &KdbgContext, 666 KdbgFirstChanceException); 667 #else 668 /* We'll manually dump the stack for the user... */ 669 KeRosDumpStackFrames(NULL, 0); 670 Result = kdHandleException; 671 #endif 672 if (Result != kdHandleException) 673 KdbgContinueStatus = STATUS_SUCCESS; 674 else 675 KdbgContinueStatus = STATUS_UNSUCCESSFUL; 676 KdbgNextApiNumber = DbgKdSetContextApi; 677 return; 678 } 679 else if (ManipulateState->ApiNumber == DbgKdSetContextApi) 680 { 681 KdbgNextApiNumber = DbgKdContinueApi; 682 return; 683 } 684 } 685 UNIMPLEMENTED; 686 } 687 688 KDSTATUS 689 NTAPI 690 KdReceivePacket( 691 _In_ ULONG PacketType, 692 _Out_ PSTRING MessageHeader, 693 _Out_ PSTRING MessageData, 694 _Out_ PULONG DataLength, 695 _Inout_ PKD_CONTEXT Context) 696 { 697 #ifdef KDBG 698 STRING NewLine = RTL_CONSTANT_STRING("\n"); 699 STRING ResponseString; 700 PDBGKD_DEBUG_IO DebugIo; 701 CHAR MessageBuffer[512]; 702 #endif 703 704 if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 705 { 706 PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 707 RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength); 708 if (KdbgNextApiNumber == DbgKdGetContextApi) 709 { 710 ManipulateState->ApiNumber = DbgKdGetContextApi; 711 MessageData->Length = 0; 712 MessageData->Buffer = (PCHAR)&KdbgContext; 713 return KdPacketReceived; 714 } 715 else if (KdbgNextApiNumber == DbgKdSetContextApi) 716 { 717 ManipulateState->ApiNumber = DbgKdSetContextApi; 718 MessageData->Length = sizeof(KdbgContext); 719 MessageData->Buffer = (PCHAR)&KdbgContext; 720 return KdPacketReceived; 721 } 722 else if (KdbgNextApiNumber != DbgKdContinueApi) 723 { 724 UNIMPLEMENTED; 725 } 726 ManipulateState->ApiNumber = DbgKdContinueApi; 727 ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus; 728 729 /* Prepare for next time */ 730 KdbgNextApiNumber = DbgKdContinueApi; 731 KdbgContinueStatus = STATUS_SUCCESS; 732 733 return KdPacketReceived; 734 } 735 736 if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 737 return KdPacketTimedOut; 738 739 #ifdef KDBG 740 DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer; 741 742 /* Validate API call */ 743 if (MessageHeader->MaximumLength != sizeof(DBGKD_DEBUG_IO)) 744 return KdPacketNeedsResend; 745 if (DebugIo->ApiNumber != DbgKdGetStringApi) 746 return KdPacketNeedsResend; 747 748 /* NOTE: We cannot use directly MessageData->Buffer here as it points 749 * to the temporary KdpMessageBuffer scratch buffer that is being 750 * shared with all the possible I/O KD operations that may happen. */ 751 ResponseString.Buffer = MessageBuffer; 752 ResponseString.Length = 0; 753 ResponseString.MaximumLength = min(sizeof(MessageBuffer), 754 MessageData->MaximumLength); 755 ResponseString.MaximumLength = min(ResponseString.MaximumLength, 756 DebugIo->u.GetString.LengthOfStringRead); 757 758 /* The prompt string has been printed by KdSendPacket; go to 759 * new line and print the kdb prompt -- for SYSREG2 support. */ 760 KdpPrintString(&NewLine); 761 KdpPrintString(&KdbPromptString); // Alternatively, use "Input> " 762 763 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 764 KbdDisableMouse(); 765 766 /* Read a line of user input and retrieve the length. 767 * The output string is NULL-terminated -- documentation states 768 * that DbgPrompt() does not NULL-terminate, but it does. */ 769 *DataLength = KdbpReadCommand(ResponseString.Buffer, 770 ResponseString.MaximumLength); 771 772 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 773 KbdEnableMouse(); 774 775 /* Return the length */ 776 *DataLength = min(*DataLength, DebugIo->u.GetString.LengthOfStringRead); 777 MessageData->Length = DebugIo->u.GetString.LengthOfStringRead = *DataLength; 778 779 /* Only now we can copy back the data into MessageData->Buffer */ 780 RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength); 781 #endif 782 783 return KdPacketReceived; 784 } 785 786 /* EOF */ 787