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 #include "kd.h"
15 #include "kdterminal.h"
16 #ifdef KDBG
17 #include "../kdbg/kdb.h"
18 #endif
19
20 #define NDEBUG
21 #include <debug.h>
22
23 #undef KdSendPacket
24 #undef KdReceivePacket
25
26 /* GLOBALS *******************************************************************/
27
28 #define KdpBufferSize (1024 * 512)
29 static BOOLEAN KdpLoggingEnabled = FALSE;
30 static PCHAR KdpDebugBuffer = NULL;
31 static volatile ULONG KdpCurrentPosition = 0;
32 static volatile ULONG KdpFreeBytes = 0;
33 static KSPIN_LOCK KdpDebugLogSpinLock;
34 static KEVENT KdpLoggerThreadEvent;
35 static HANDLE KdpLogFileHandle;
36 ANSI_STRING KdpLogFileName = RTL_CONSTANT_STRING("\\SystemRoot\\debug.log");
37
38 static KSPIN_LOCK KdpSerialSpinLock;
39 ULONG SerialPortNumber = DEFAULT_DEBUG_PORT;
40 CPPORT SerialPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0};
41
42 #define KdpScreenLineLengthDefault 80
43 static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = "";
44 static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0;
45
46 KDP_DEBUG_MODE KdpDebugMode;
47 LIST_ENTRY KdProviders = {&KdProviders, &KdProviders};
48 KD_DISPATCH_TABLE DispatchTable[KdMax] = {0};
49
50 PKDP_INIT_ROUTINE InitRoutines[KdMax] =
51 {
52 KdpScreenInit,
53 KdpSerialInit,
54 KdpDebugLogInit,
55 #ifdef KDBG // See kdb_cli.c
56 KdpKdbgInit
57 #endif
58 };
59
60 /* LOCKING FUNCTIONS *********************************************************/
61
62 KIRQL
63 NTAPI
KdbpAcquireLock(_In_ PKSPIN_LOCK SpinLock)64 KdbpAcquireLock(
65 _In_ PKSPIN_LOCK SpinLock)
66 {
67 KIRQL OldIrql;
68
69 /* Acquire the spinlock without waiting at raised IRQL */
70 while (TRUE)
71 {
72 /* Loop until the spinlock becomes available */
73 while (!KeTestSpinLock(SpinLock));
74
75 /* Spinlock is free, raise IRQL to high level */
76 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
77
78 /* Try to get the spinlock */
79 if (KeTryToAcquireSpinLockAtDpcLevel(SpinLock))
80 break;
81
82 /* Someone else got the spinlock, lower IRQL back */
83 KeLowerIrql(OldIrql);
84 }
85
86 return OldIrql;
87 }
88
89 VOID
90 NTAPI
KdbpReleaseLock(_In_ PKSPIN_LOCK SpinLock,_In_ KIRQL OldIrql)91 KdbpReleaseLock(
92 _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
KdpLoggerThread(PVOID Context)107 KdpLoggerThread(PVOID Context)
108 {
109 ULONG beg, end, num;
110 IO_STATUS_BLOCK Iosb;
111
112 ASSERT(ExGetPreviousMode() == KernelMode);
113
114 KdpLoggingEnabled = TRUE;
115
116 while (TRUE)
117 {
118 KeWaitForSingleObject(&KdpLoggerThreadEvent, Executive, KernelMode, FALSE, NULL);
119
120 /* Bug */
121 /* Keep KdpCurrentPosition and KdpFreeBytes values in local
122 * variables to avoid their possible change from Producer part,
123 * KdpPrintToLogFile function
124 */
125 end = KdpCurrentPosition;
126 num = KdpFreeBytes;
127
128 /* Now securely calculate values, based on local variables */
129 beg = (end + num) % KdpBufferSize;
130 num = KdpBufferSize - num;
131
132 /* Nothing to do? */
133 if (num == 0)
134 continue;
135
136 if (end > beg)
137 {
138 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
139 KdpDebugBuffer + beg, num, NULL, NULL);
140 }
141 else
142 {
143 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
144 KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL);
145
146 NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
147 KdpDebugBuffer, end, NULL, NULL);
148 }
149
150 (VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num);
151 }
152 }
153
154 static VOID
155 NTAPI
KdpPrintToLogFile(_In_ PCCH String,_In_ ULONG Length)156 KdpPrintToLogFile(
157 _In_ PCCH String,
158 _In_ ULONG Length)
159 {
160 KIRQL OldIrql;
161 ULONG beg, end, num;
162
163 if (KdpDebugBuffer == NULL) return;
164
165 /* Acquire the printing spinlock without waiting at raised IRQL */
166 OldIrql = KdbpAcquireLock(&KdpDebugLogSpinLock);
167
168 beg = KdpCurrentPosition;
169 num = min(Length, KdpFreeBytes);
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 KdbpReleaseLock(&KdpDebugLogSpinLock, OldIrql);
189
190 /* Signal the logger thread */
191 if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled)
192 KeSetEvent(&KdpLoggerThreadEvent, IO_NO_INCREMENT, FALSE);
193 }
194
195 NTSTATUS
196 NTAPI
KdpDebugLogInit(_In_ PKD_DISPATCH_TABLE DispatchTable,_In_ ULONG BootPhase)197 KdpDebugLogInit(
198 _In_ PKD_DISPATCH_TABLE DispatchTable,
199 _In_ ULONG BootPhase)
200 {
201 NTSTATUS Status = STATUS_SUCCESS;
202
203 if (!KdpDebugMode.File)
204 return STATUS_PORT_DISCONNECTED;
205
206 if (BootPhase == 0)
207 {
208 /* Write out the functions that we support for now */
209 DispatchTable->KdpPrintRoutine = KdpPrintToLogFile;
210
211 /* Register for BootPhase 1 initialization and as a Provider */
212 DispatchTable->KdpInitRoutine = KdpDebugLogInit;
213 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
214 }
215 else if (BootPhase == 1)
216 {
217 /* Allocate a buffer for debug log */
218 KdpDebugBuffer = ExAllocatePoolZero(NonPagedPool,
219 KdpBufferSize,
220 TAG_KDBG);
221 if (!KdpDebugBuffer)
222 {
223 KdpDebugMode.File = FALSE;
224 RemoveEntryList(&DispatchTable->KdProvidersList);
225 return STATUS_NO_MEMORY;
226 }
227 KdpFreeBytes = KdpBufferSize;
228
229 /* Initialize spinlock */
230 KeInitializeSpinLock(&KdpDebugLogSpinLock);
231
232 /* Register for later BootPhase 2 reinitialization */
233 DispatchTable->KdpInitRoutine = KdpDebugLogInit;
234
235 /* Announce ourselves */
236 HalDisplayString(" File log debugging enabled\r\n");
237 }
238 else if (BootPhase >= 2)
239 {
240 UNICODE_STRING FileName;
241 OBJECT_ATTRIBUTES ObjectAttributes;
242 IO_STATUS_BLOCK Iosb;
243 HANDLE ThreadHandle;
244 KPRIORITY Priority;
245
246 /* If we have already successfully opened the log file, bail out */
247 if (KdpLogFileHandle != NULL)
248 return STATUS_SUCCESS;
249
250 /* Setup the log name */
251 Status = RtlAnsiStringToUnicodeString(&FileName, &KdpLogFileName, TRUE);
252 if (!NT_SUCCESS(Status))
253 goto Failure;
254
255 InitializeObjectAttributes(&ObjectAttributes,
256 &FileName,
257 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
258 NULL,
259 NULL);
260
261 /* Create the log file */
262 Status = ZwCreateFile(&KdpLogFileHandle,
263 FILE_APPEND_DATA | SYNCHRONIZE,
264 &ObjectAttributes,
265 &Iosb,
266 NULL,
267 FILE_ATTRIBUTE_NORMAL,
268 FILE_SHARE_READ,
269 FILE_OPEN_IF,
270 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
271 FILE_SEQUENTIAL_ONLY | FILE_WRITE_THROUGH,
272 NULL,
273 0);
274
275 RtlFreeUnicodeString(&FileName);
276
277 if (!NT_SUCCESS(Status))
278 {
279 DPRINT1("Failed to open log file: 0x%08lx\n", Status);
280
281 /* Schedule an I/O reinitialization if needed */
282 if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
283 Status == STATUS_OBJECT_PATH_NOT_FOUND)
284 {
285 DispatchTable->KdpInitRoutine = KdpDebugLogInit;
286 return Status;
287 }
288 goto Failure;
289 }
290
291 /** HACK for FILE_APPEND_DATA **
292 ** Remove once CORE-18789 is fixed. **
293 ** Enforce to go to the end of file **/
294 {
295 FILE_STANDARD_INFORMATION FileInfo;
296 FILE_POSITION_INFORMATION FilePosInfo;
297
298 Status = ZwQueryInformationFile(KdpLogFileHandle,
299 &Iosb,
300 &FileInfo,
301 sizeof(FileInfo),
302 FileStandardInformation);
303 DPRINT("Status: 0x%08lx - EOF offset: %I64d\n",
304 Status, FileInfo.EndOfFile.QuadPart);
305
306 Status = ZwQueryInformationFile(KdpLogFileHandle,
307 &Iosb,
308 &FilePosInfo,
309 sizeof(FilePosInfo),
310 FilePositionInformation);
311 DPRINT("Status: 0x%08lx - Position: %I64d\n",
312 Status, FilePosInfo.CurrentByteOffset.QuadPart);
313
314 FilePosInfo.CurrentByteOffset.QuadPart = FileInfo.EndOfFile.QuadPart;
315 Status = ZwSetInformationFile(KdpLogFileHandle,
316 &Iosb,
317 &FilePosInfo,
318 sizeof(FilePosInfo),
319 FilePositionInformation);
320 DPRINT("ZwSetInformationFile(FilePositionInfo) returned: 0x%08lx\n", Status);
321 }
322 /** END OF HACK **/
323
324 KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE);
325
326 /* Create the logger thread */
327 Status = PsCreateSystemThread(&ThreadHandle,
328 THREAD_ALL_ACCESS,
329 NULL,
330 NULL,
331 NULL,
332 KdpLoggerThread,
333 NULL);
334 if (!NT_SUCCESS(Status))
335 {
336 DPRINT1("Failed to create log file thread: 0x%08lx\n", Status);
337 ZwClose(KdpLogFileHandle);
338 goto Failure;
339 }
340
341 Priority = HIGH_PRIORITY;
342 ZwSetInformationThread(ThreadHandle,
343 ThreadPriority,
344 &Priority,
345 sizeof(Priority));
346
347 ZwClose(ThreadHandle);
348 return Status;
349
350 Failure:
351 KdpFreeBytes = 0;
352 ExFreePoolWithTag(KdpDebugBuffer, TAG_KDBG);
353 KdpDebugBuffer = NULL;
354 KdpDebugMode.File = FALSE;
355 RemoveEntryList(&DispatchTable->KdProvidersList);
356 }
357
358 return Status;
359 }
360
361 /* SERIAL FUNCTIONS **********************************************************/
362
363 static VOID
364 NTAPI
KdpSerialPrint(_In_ PCCH String,_In_ ULONG Length)365 KdpSerialPrint(
366 _In_ PCCH String,
367 _In_ ULONG Length)
368 {
369 PCCH pch = String;
370 KIRQL OldIrql;
371
372 /* Acquire the printing spinlock without waiting at raised IRQL */
373 OldIrql = KdbpAcquireLock(&KdpSerialSpinLock);
374
375 /* Output the string */
376 while (pch < String + Length && *pch)
377 {
378 if (*pch == '\n')
379 {
380 KdPortPutByteEx(&SerialPortInfo, '\r');
381 }
382 KdPortPutByteEx(&SerialPortInfo, *pch);
383 ++pch;
384 }
385
386 /* Release the spinlock */
387 KdbpReleaseLock(&KdpSerialSpinLock, OldIrql);
388 }
389
390 NTSTATUS
391 NTAPI
KdpSerialInit(_In_ PKD_DISPATCH_TABLE DispatchTable,_In_ ULONG BootPhase)392 KdpSerialInit(
393 _In_ PKD_DISPATCH_TABLE DispatchTable,
394 _In_ ULONG BootPhase)
395 {
396 if (!KdpDebugMode.Serial)
397 return STATUS_PORT_DISCONNECTED;
398
399 if (BootPhase == 0)
400 {
401 /* Write out the functions that we support for now */
402 DispatchTable->KdpPrintRoutine = KdpSerialPrint;
403
404 /* Initialize the Port */
405 if (!KdPortInitializeEx(&SerialPortInfo, SerialPortNumber))
406 {
407 KdpDebugMode.Serial = FALSE;
408 return STATUS_DEVICE_DOES_NOT_EXIST;
409 }
410 KdComPortInUse = SerialPortInfo.Address;
411
412 /* Initialize spinlock */
413 KeInitializeSpinLock(&KdpSerialSpinLock);
414
415 /* Register for BootPhase 1 initialization and as a Provider */
416 DispatchTable->KdpInitRoutine = KdpSerialInit;
417 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
418 }
419 else if (BootPhase == 1)
420 {
421 /* Announce ourselves */
422 HalDisplayString(" Serial debugging enabled\r\n");
423 }
424
425 return STATUS_SUCCESS;
426 }
427
428 /* SCREEN FUNCTIONS **********************************************************/
429
430 VOID
KdpScreenAcquire(VOID)431 KdpScreenAcquire(VOID)
432 {
433 if (InbvIsBootDriverInstalled() /* &&
434 !InbvCheckDisplayOwnership() */)
435 {
436 /* Acquire ownership and reset the display */
437 InbvAcquireDisplayOwnership();
438 InbvResetDisplay();
439 InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
440 InbvSetTextColor(BV_COLOR_WHITE);
441 InbvInstallDisplayStringFilter(NULL);
442 InbvEnableDisplayString(TRUE);
443 InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
444 }
445 }
446
447 // extern VOID NTAPI InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned);
448
449 VOID
KdpScreenRelease(VOID)450 KdpScreenRelease(VOID)
451 {
452 if (InbvIsBootDriverInstalled()&&
453 InbvCheckDisplayOwnership())
454 {
455 /* Release the display */
456 // InbvSetDisplayOwnership(FALSE);
457 InbvNotifyDisplayOwnershipLost(NULL);
458 }
459 }
460
461 static VOID
462 NTAPI
KdpScreenPrint(_In_ PCCH String,_In_ ULONG Length)463 KdpScreenPrint(
464 _In_ PCCH String,
465 _In_ ULONG Length)
466 {
467 PCCH pch = String;
468
469 while (pch < String + Length && *pch)
470 {
471 if (*pch == '\b')
472 {
473 /* HalDisplayString does not support '\b'. Workaround it and use '\r' */
474 if (KdpScreenLineLength > 0)
475 {
476 /* Remove last character from buffer */
477 KdpScreenLineBuffer[--KdpScreenLineLength] = '\0';
478 KdpScreenLineBufferPos = KdpScreenLineLength;
479
480 /* Clear row and print line again */
481 HalDisplayString("\r");
482 HalDisplayString(KdpScreenLineBuffer);
483 }
484 }
485 else
486 {
487 KdpScreenLineBuffer[KdpScreenLineLength++] = *pch;
488 KdpScreenLineBuffer[KdpScreenLineLength] = '\0';
489 }
490
491 if (*pch == '\n' || KdpScreenLineLength == KdpScreenLineLengthDefault)
492 {
493 /* Print buffered characters */
494 if (KdpScreenLineBufferPos != KdpScreenLineLength)
495 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
496
497 /* Clear line buffer */
498 KdpScreenLineBuffer[0] = '\0';
499 KdpScreenLineLength = KdpScreenLineBufferPos = 0;
500 }
501
502 ++pch;
503 }
504
505 /* Print buffered characters */
506 if (KdpScreenLineBufferPos != KdpScreenLineLength)
507 {
508 HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
509 KdpScreenLineBufferPos = KdpScreenLineLength;
510 }
511 }
512
513 NTSTATUS
514 NTAPI
KdpScreenInit(_In_ PKD_DISPATCH_TABLE DispatchTable,_In_ ULONG BootPhase)515 KdpScreenInit(
516 _In_ PKD_DISPATCH_TABLE DispatchTable,
517 _In_ ULONG BootPhase)
518 {
519 if (!KdpDebugMode.Screen)
520 return STATUS_PORT_DISCONNECTED;
521
522 if (BootPhase == 0)
523 {
524 /* Write out the functions that we support for now */
525 DispatchTable->KdpPrintRoutine = KdpScreenPrint;
526
527 /* Register for BootPhase 1 initialization and as a Provider */
528 DispatchTable->KdpInitRoutine = KdpScreenInit;
529 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
530 }
531 else if (BootPhase == 1)
532 {
533 /* Take control of the display */
534 KdpScreenAcquire();
535
536 /* Announce ourselves */
537 HalDisplayString(" Screen debugging enabled\r\n");
538 }
539
540 return STATUS_SUCCESS;
541 }
542
543
544 /* GENERAL FUNCTIONS *********************************************************/
545
546 static VOID
KdIoPrintString(_In_ PCCH String,_In_ ULONG Length)547 KdIoPrintString(
548 _In_ PCCH String,
549 _In_ ULONG Length)
550 {
551 PLIST_ENTRY CurrentEntry;
552 PKD_DISPATCH_TABLE CurrentTable;
553
554 /* Call the registered providers */
555 for (CurrentEntry = KdProviders.Flink;
556 CurrentEntry != &KdProviders;
557 CurrentEntry = CurrentEntry->Flink)
558 {
559 CurrentTable = CONTAINING_RECORD(CurrentEntry,
560 KD_DISPATCH_TABLE,
561 KdProvidersList);
562
563 CurrentTable->KdpPrintRoutine(String, Length);
564 }
565 }
566
567 VOID
KdIoPuts(_In_ PCSTR String)568 KdIoPuts(
569 _In_ PCSTR String)
570 {
571 KdIoPrintString(String, (ULONG)strlen(String));
572 }
573
574 VOID
575 __cdecl
KdIoPrintf(_In_ PCSTR Format,...)576 KdIoPrintf(
577 _In_ PCSTR Format,
578 ...)
579 {
580 va_list ap;
581 ULONG Length;
582 CHAR Buffer[512];
583
584 /* Format the string */
585 va_start(ap, Format);
586 Length = (ULONG)_vsnprintf(Buffer,
587 sizeof(Buffer),
588 Format,
589 ap);
590 va_end(ap);
591
592 /* Send it to the display providers */
593 KdIoPrintString(Buffer, Length);
594 }
595
596 #ifdef KDBG
597 extern const CSTRING KdbPromptStr;
598 #endif
599
600 VOID
601 NTAPI
KdSendPacket(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_opt_ PSTRING MessageData,_Inout_ PKD_CONTEXT Context)602 KdSendPacket(
603 _In_ ULONG PacketType,
604 _In_ PSTRING MessageHeader,
605 _In_opt_ PSTRING MessageData,
606 _Inout_ PKD_CONTEXT Context)
607 {
608 PDBGKD_DEBUG_IO DebugIo;
609
610 if (PacketType != PACKET_TYPE_KD_DEBUG_IO)
611 {
612 KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
613 return;
614 }
615
616 DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
617
618 /* Validate API call */
619 if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO))
620 return;
621 if ((DebugIo->ApiNumber != DbgKdPrintStringApi) &&
622 (DebugIo->ApiNumber != DbgKdGetStringApi))
623 {
624 return;
625 }
626 if (!MessageData)
627 return;
628
629 /* NOTE: MessageData->Length should be equal to
630 * DebugIo.u.PrintString.LengthOfString, or to
631 * DebugIo.u.GetString.LengthOfPromptString */
632
633 if (!KdpDebugMode.Value)
634 return;
635
636 /* Print the string proper */
637 KdIoPrintString(MessageData->Buffer, MessageData->Length);
638 }
639
640 KDSTATUS
641 NTAPI
KdReceivePacket(_In_ ULONG PacketType,_Out_ PSTRING MessageHeader,_Out_ PSTRING MessageData,_Out_ PULONG DataLength,_Inout_ PKD_CONTEXT Context)642 KdReceivePacket(
643 _In_ ULONG PacketType,
644 _Out_ PSTRING MessageHeader,
645 _Out_ PSTRING MessageData,
646 _Out_ PULONG DataLength,
647 _Inout_ PKD_CONTEXT Context)
648 {
649 #ifdef KDBG
650 PDBGKD_DEBUG_IO DebugIo;
651 STRING ResponseString;
652 CHAR MessageBuffer[512];
653 #endif
654
655 if (PacketType != PACKET_TYPE_KD_DEBUG_IO)
656 {
657 KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
658 return KdPacketTimedOut;
659 }
660
661 #ifdef KDBG
662 DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
663
664 /* Validate API call */
665 if (MessageHeader->MaximumLength != sizeof(DBGKD_DEBUG_IO))
666 return KdPacketNeedsResend;
667 if (DebugIo->ApiNumber != DbgKdGetStringApi)
668 return KdPacketNeedsResend;
669
670 /* NOTE: We cannot use directly MessageData->Buffer here as it points
671 * to the temporary KdpMessageBuffer scratch buffer that is being
672 * shared with all the possible I/O KD operations that may happen. */
673 ResponseString.Buffer = MessageBuffer;
674 ResponseString.Length = 0;
675 ResponseString.MaximumLength = min(sizeof(MessageBuffer),
676 MessageData->MaximumLength);
677 ResponseString.MaximumLength = min(ResponseString.MaximumLength,
678 DebugIo->u.GetString.LengthOfStringRead);
679
680 /* The prompt string has been printed by KdSendPacket; go to
681 * new line and print the kdb prompt -- for SYSREG2 support. */
682 KdIoPrintString("\n", 1);
683 KdIoPuts(KdbPromptStr.Buffer); // Alternatively, use "Input> "
684
685 if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
686 KbdDisableMouse();
687
688 /*
689 * Read a NULL-terminated line of user input and retrieve its length.
690 * Official documentation states that DbgPrompt() includes a terminating
691 * newline character but does not NULL-terminate. However, experiments
692 * show that this behaviour is left at the discretion of WinDbg itself.
693 * WinDbg NULL-terminates the string unless its buffer is too short,
694 * in which case the string is simply truncated without NULL-termination.
695 */
696 ResponseString.Length =
697 (USHORT)KdIoReadLine(ResponseString.Buffer,
698 ResponseString.MaximumLength);
699
700 if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
701 KbdEnableMouse();
702
703 /* Adjust and return the string length */
704 *DataLength = min(ResponseString.Length + sizeof(ANSI_NULL),
705 DebugIo->u.GetString.LengthOfStringRead);
706 MessageData->Length = DebugIo->u.GetString.LengthOfStringRead = *DataLength;
707
708 /* Only now we can copy back the data into MessageData->Buffer */
709 RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength);
710 #endif
711
712 return KdPacketReceived;
713 }
714
715 /* EOF */
716