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