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