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