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 /* Load symbols. Currently implemented only for KDBG! */ 584 if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry)) 585 { 586 KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols); 587 } 588 #endif 589 return; 590 } 591 else if (WaitStateChange->NewState == DbgKdExceptionStateChange) 592 { 593 KdbgNextApiNumber = DbgKdGetContextApi; 594 KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord; 595 KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance; 596 return; 597 } 598 } 599 else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 600 { 601 PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 602 if (ManipulateState->ApiNumber == DbgKdGetContextApi) 603 { 604 KD_CONTINUE_TYPE Result; 605 606 #ifdef KDBG 607 /* Check if this is an assertion failure */ 608 if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE) 609 { 610 /* Bump EIP to the instruction following the int 2C */ 611 KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2); 612 } 613 614 Result = KdbEnterDebuggerException(&KdbgExceptionRecord, 615 KdbgContext.SegCs & 1, 616 &KdbgContext, 617 KdbgFirstChanceException); 618 #else 619 /* We'll manually dump the stack for the user... */ 620 KeRosDumpStackFrames(NULL, 0); 621 Result = kdHandleException; 622 #endif 623 if (Result != kdHandleException) 624 KdbgContinueStatus = STATUS_SUCCESS; 625 else 626 KdbgContinueStatus = STATUS_UNSUCCESSFUL; 627 KdbgNextApiNumber = DbgKdSetContextApi; 628 return; 629 } 630 else if (ManipulateState->ApiNumber == DbgKdSetContextApi) 631 { 632 KdbgNextApiNumber = DbgKdContinueApi; 633 return; 634 } 635 } 636 UNIMPLEMENTED; 637 } 638 639 KDSTATUS 640 NTAPI 641 KdReceivePacket( 642 IN ULONG PacketType, 643 OUT PSTRING MessageHeader, 644 OUT PSTRING MessageData, 645 OUT PULONG DataLength, 646 IN OUT PKD_CONTEXT Context) 647 { 648 #ifdef KDBG 649 KIRQL OldIrql; 650 STRING StringChar; 651 CHAR Response; 652 USHORT i; 653 ULONG DummyScanCode; 654 CHAR MessageBuffer[100]; 655 STRING ResponseString; 656 #endif 657 658 if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) 659 { 660 PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer; 661 RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength); 662 if (KdbgNextApiNumber == DbgKdGetContextApi) 663 { 664 ManipulateState->ApiNumber = DbgKdGetContextApi; 665 MessageData->Length = 0; 666 MessageData->Buffer = (PCHAR)&KdbgContext; 667 return KdPacketReceived; 668 } 669 else if (KdbgNextApiNumber == DbgKdSetContextApi) 670 { 671 ManipulateState->ApiNumber = DbgKdSetContextApi; 672 MessageData->Length = sizeof(KdbgContext); 673 MessageData->Buffer = (PCHAR)&KdbgContext; 674 return KdPacketReceived; 675 } 676 else if (KdbgNextApiNumber != DbgKdContinueApi) 677 { 678 UNIMPLEMENTED; 679 } 680 ManipulateState->ApiNumber = DbgKdContinueApi; 681 ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus; 682 683 /* Prepare for next time */ 684 KdbgNextApiNumber = DbgKdContinueApi; 685 KdbgContinueStatus = STATUS_SUCCESS; 686 687 return KdPacketReceived; 688 } 689 690 if (PacketType != PACKET_TYPE_KD_DEBUG_IO) 691 return KdPacketTimedOut; 692 693 #ifdef KDBG 694 ResponseString.Buffer = MessageBuffer; 695 ResponseString.Length = 0; 696 ResponseString.MaximumLength = min(sizeof(MessageBuffer), MessageData->MaximumLength); 697 StringChar.Buffer = &Response; 698 StringChar.Length = StringChar.MaximumLength = sizeof(Response); 699 700 /* Display the string and print a new line for log neatness */ 701 *StringChar.Buffer = '\n'; 702 KdpPrintString(&StringChar); 703 704 /* Print the kdb prompt */ 705 KdpPrintString(&KdbPromptString); 706 707 // TODO: Use an improved KdbpReadCommand() function for our purposes. 708 709 /* Acquire the printing spinlock without waiting at raised IRQL */ 710 OldIrql = KdpAcquireLock(&KdpSerialSpinLock); 711 712 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 713 KbdDisableMouse(); 714 715 /* Loop the whole string */ 716 for (i = 0; i < ResponseString.MaximumLength; i++) 717 { 718 /* Check if this is serial debugging mode */ 719 if (KdbDebugState & KD_DEBUG_KDSERIAL) 720 { 721 /* Get the character from serial */ 722 do 723 { 724 Response = KdbpTryGetCharSerial(MAXULONG); 725 } while (Response == -1); 726 } 727 else 728 { 729 /* Get the response from the keyboard */ 730 do 731 { 732 Response = KdbpTryGetCharKeyboard(&DummyScanCode, MAXULONG); 733 } while (Response == -1); 734 } 735 736 /* Check for return */ 737 if (Response == '\r') 738 { 739 /* 740 * We might need to discard the next '\n'. 741 * Wait a bit to make sure we receive it. 742 */ 743 KeStallExecutionProcessor(100000); 744 745 /* Check the mode */ 746 if (KdbDebugState & KD_DEBUG_KDSERIAL) 747 { 748 /* Read and discard the next character, if any */ 749 KdbpTryGetCharSerial(5); 750 } 751 else 752 { 753 /* Read and discard the next character, if any */ 754 KdbpTryGetCharKeyboard(&DummyScanCode, 5); 755 } 756 757 /* 758 * Null terminate the output string -- documentation states that 759 * DbgPrompt does not null terminate, but it does 760 */ 761 *(PCHAR)(ResponseString.Buffer + i) = 0; 762 break; 763 } 764 765 /* Write it back and print it to the log */ 766 *(PCHAR)(ResponseString.Buffer + i) = Response; 767 KdpReleaseLock(&KdpSerialSpinLock, OldIrql); 768 KdpPrintString(&StringChar); 769 OldIrql = KdpAcquireLock(&KdpSerialSpinLock); 770 } 771 772 /* Release the spinlock */ 773 KdpReleaseLock(&KdpSerialSpinLock, OldIrql); 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 #endif 787 return KdPacketReceived; 788 } 789 790 /* EOF */ 791