https://git.reactos.org/?p=reactos.git;a=commitdiff;h=84e32e4e90109b3bce75ddb3eee2d3dfc42ab4be

commit 84e32e4e90109b3bce75ddb3eee2d3dfc42ab4be
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Sun Nov 27 19:58:56 2022 +0100
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Fri Jan 6 18:57:32 2023 +0100

    [NTOS:KD] Revisit KdSendPacket() and KdReceivePacket() for DBGKD_DEBUG_IO. 
(#4914)
    
    - Use SAL2 annotations.
    - KdSendPacket(): Validate DEBUG_IO API call.
    - KdReceivePacket(): Take the LengthOfStringRead into account; use
      KdbpReadCommand() to read the input, so that correct line edition
      is available (backspace, etc.)
---
 ntoskrnl/kd/kdio.c  | 163 ++++++++++++++++++++--------------------------------
 ntoskrnl/kdbg/kdb.h |   5 ++
 2 files changed, 68 insertions(+), 100 deletions(-)

diff --git a/ntoskrnl/kd/kdio.c b/ntoskrnl/kd/kdio.c
index 3f39e20c173..45733e0b3ca 100644
--- a/ntoskrnl/kd/kdio.c
+++ b/ntoskrnl/kd/kdio.c
@@ -37,7 +37,7 @@ CPPORT SerialPortInfo   = {0, DEFAULT_DEBUG_BAUD_RATE, 0};
 static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = "";
 static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0;
 
-const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; // 5*1024*1024;
+const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024;
 PCHAR KdpDmesgBuffer = NULL;
 volatile ULONG KdpDmesgCurrentPosition = 0;
 volatile ULONG KdpDmesgFreeBytes = 0;
@@ -576,18 +576,34 @@ extern STRING KdbPromptString;
 VOID
 NTAPI
 KdSendPacket(
-    IN ULONG PacketType,
-    IN PSTRING MessageHeader,
-    IN PSTRING MessageData,
-    IN OUT PKD_CONTEXT Context)
+    _In_ ULONG PacketType,
+    _In_ PSTRING MessageHeader,
+    _In_opt_ PSTRING MessageData,
+    _Inout_ PKD_CONTEXT Context)
 {
     if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
     {
-        PSTRING Output = MessageData;
+        ULONG ApiNumber = ((PDBGKD_DEBUG_IO)MessageHeader->Buffer)->ApiNumber;
         PLIST_ENTRY CurrentEntry;
         PKD_DISPATCH_TABLE CurrentTable;
 
-        if (!KdpDebugMode.Value) return;
+        /* Validate API call */
+        if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO))
+            return;
+        if ((ApiNumber != DbgKdPrintStringApi) &&
+            (ApiNumber != DbgKdGetStringApi))
+        {
+            return;
+        }
+        if (!MessageData)
+            return;
+
+        /* NOTE: MessageData->Length should be equal to
+         * DebugIo.u.PrintString.LengthOfString, or to
+         * DebugIo.u.GetString.LengthOfPromptString */
+
+        if (!KdpDebugMode.Value)
+            return;
 
         /* Call the registered handlers */
         CurrentEntry = KdProviders.Flink;
@@ -599,7 +615,7 @@ KdSendPacket(
                                              KdProvidersList);
 
             /* Call it */
-            CurrentTable->KdpPrintRoutine(Output->Buffer, Output->Length);
+            CurrentTable->KdpPrintRoutine(MessageData->Buffer, 
MessageData->Length);
 
             /* Next Table */
             CurrentEntry = CurrentEntry->Flink;
@@ -672,20 +688,17 @@ KdSendPacket(
 KDSTATUS
 NTAPI
 KdReceivePacket(
-    IN ULONG PacketType,
-    OUT PSTRING MessageHeader,
-    OUT PSTRING MessageData,
-    OUT PULONG DataLength,
-    IN OUT PKD_CONTEXT Context)
+    _In_ ULONG PacketType,
+    _Out_ PSTRING MessageHeader,
+    _Out_ PSTRING MessageData,
+    _Out_ PULONG DataLength,
+    _Inout_ PKD_CONTEXT Context)
 {
 #ifdef KDBG
-    KIRQL OldIrql;
-    STRING StringChar;
-    CHAR Response;
-    USHORT i;
-    ULONG DummyScanCode;
-    CHAR MessageBuffer[100];
+    STRING NewLine = RTL_CONSTANT_STRING("\n");
     STRING ResponseString;
+    PDBGKD_DEBUG_IO DebugIo;
+    CHAR MessageBuffer[512];
 #endif
 
     if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
@@ -724,99 +737,49 @@ KdReceivePacket(
         return KdPacketTimedOut;
 
 #ifdef KDBG
-    ResponseString.Buffer = MessageBuffer;
-    ResponseString.Length = 0;
-    ResponseString.MaximumLength = min(sizeof(MessageBuffer), 
MessageData->MaximumLength);
-    StringChar.Buffer = &Response;
-    StringChar.Length = StringChar.MaximumLength = sizeof(Response);
-
-    /* Display the string and print a new line for log neatness */
-    *StringChar.Buffer = '\n';
-    KdpPrintString(&StringChar);
+    DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
 
-    /* Print the kdb prompt */
-    KdpPrintString(&KdbPromptString);
+    /* Validate API call */
+    if (MessageHeader->MaximumLength != sizeof(DBGKD_DEBUG_IO))
+        return KdPacketNeedsResend;
+    if (DebugIo->ApiNumber != DbgKdGetStringApi)
+        return KdPacketNeedsResend;
 
-    // TODO: Use an improved KdbpReadCommand() function for our purposes.
+    /* NOTE: We cannot use directly MessageData->Buffer here as it points
+     * to the temporary KdpMessageBuffer scratch buffer that is being
+     * shared with all the possible I/O KD operations that may happen. */
+    ResponseString.Buffer = MessageBuffer;
+    ResponseString.Length = 0;
+    ResponseString.MaximumLength = min(sizeof(MessageBuffer),
+                                       MessageData->MaximumLength);
+    ResponseString.MaximumLength = min(ResponseString.MaximumLength,
+                                       
DebugIo->u.GetString.LengthOfStringRead);
 
-    /* Acquire the printing spinlock without waiting at raised IRQL */
-    OldIrql = KdbpAcquireLock(&KdpSerialSpinLock);
+    /* The prompt string has been printed by KdSendPacket; go to
+     * new line and print the kdb prompt -- for SYSREG2 support. */
+    KdpPrintString(&NewLine);
+    KdpPrintString(&KdbPromptString); // Alternatively, use "Input> "
 
     if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
         KbdDisableMouse();
 
-    /* Loop the whole string */
-    for (i = 0; i < ResponseString.MaximumLength; i++)
-    {
-        /* Check if this is serial debugging mode */
-        if (KdbDebugState & KD_DEBUG_KDSERIAL)
-        {
-            /* Get the character from serial */
-            do
-            {
-                Response = KdbpTryGetCharSerial(MAXULONG);
-            } while (Response == -1);
-        }
-        else
-        {
-            /* Get the response from the keyboard */
-            do
-            {
-                Response = KdbpTryGetCharKeyboard(&DummyScanCode, MAXULONG);
-            } while (Response == -1);
-        }
-
-        /* Check for return */
-        if (Response == '\r')
-        {
-            /*
-             * We might need to discard the next '\n'.
-             * Wait a bit to make sure we receive it.
-             */
-            KeStallExecutionProcessor(100000);
-
-            /* Check the mode */
-            if (KdbDebugState & KD_DEBUG_KDSERIAL)
-            {
-                /* Read and discard the next character, if any */
-                KdbpTryGetCharSerial(5);
-            }
-            else
-            {
-                /* Read and discard the next character, if any */
-                KdbpTryGetCharKeyboard(&DummyScanCode, 5);
-            }
-
-            /*
-             * Null terminate the output string -- documentation states that
-             * DbgPrompt does not null terminate, but it does
-             */
-            *(PCHAR)(ResponseString.Buffer + i) = 0;
-            break;
-        }
-
-        /* Write it back and print it to the log */
-        *(PCHAR)(ResponseString.Buffer + i) = Response;
-        KdbpReleaseLock(&KdpSerialSpinLock, OldIrql);
-        KdpPrintString(&StringChar);
-        OldIrql = KdbpAcquireLock(&KdpSerialSpinLock);
-    }
-
-    /* Release the spinlock */
-    KdbpReleaseLock(&KdpSerialSpinLock, OldIrql);
-
-    /* Print a new line */
-    *StringChar.Buffer = '\n';
-    KdpPrintString(&StringChar);
-
-    /* Return the length */
-    RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, i);
-    *DataLength = i;
+    /* Read a line of user input and retrieve the length.
+     * The output string is NULL-terminated -- documentation states
+     * that DbgPrompt() does not NULL-terminate, but it does. */
+    *DataLength = KdbpReadCommand(ResponseString.Buffer,
+                                  ResponseString.MaximumLength);
 
     if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
         KbdEnableMouse();
 
+    /* Return the length */
+    *DataLength = min(*DataLength, DebugIo->u.GetString.LengthOfStringRead);
+    MessageData->Length = DebugIo->u.GetString.LengthOfStringRead = 
*DataLength;
+
+    /* Only now we can copy back the data into MessageData->Buffer */
+    RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength);
 #endif
+
     return KdPacketReceived;
 }
 
diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h
index d78e2696cdd..8d1e9af2a47 100644
--- a/ntoskrnl/kdbg/kdb.h
+++ b/ntoskrnl/kdbg/kdb.h
@@ -98,6 +98,11 @@ KdbpCliMainLoop(
 VOID
 KdbpCliInterpretInitFile(VOID);
 
+SIZE_T
+KdbpReadCommand(
+    _Out_ PCHAR Buffer,
+    _In_ SIZE_T Size);
+
 VOID
 KdbpPager(
     _In_ PCHAR Buffer,

Reply via email to