https://git.reactos.org/?p=reactos.git;a=commitdiff;h=35180b3ad23e5ac357b7e…
commit 35180b3ad23e5ac357b7e7c7495d29cf13f7bd74
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Wed Mar 29 02:06:35 2023 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Mar 29 02:42:31 2023 +0200
[NTOS:KDBG] Isolate terminal and input-related routines from the rest of KDBG.
(#5188)
This is done in preparation for moving all this functionality in a
separate KDTERM "KD Terminal Driver" DLL.
Additionally:
- Flush the terminal input before sending ANSI escape sequences.
- In KDBG pager, always use the correct reading-key function (the
same used also for reading keys for a line of user input), and not
the simplistic two-call KdbpGetCharSerial + KdbpTryGetCharSerial
that would split the \r \n across calls.
- Call KdbpGetCommandLineSettings() in KdbInitialize() at BootPhase 0,
which is indirectly called by KdDebuggerInitialize0(). And fix its
command-line parsing too.
---
ntoskrnl/kd/kd.h | 5 +
ntoskrnl/kd/kdmain.c | 36 ++++++-
ntoskrnl/kd/kdprompt.c | 59 +---------
ntoskrnl/kd/kdterminal.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++
ntoskrnl/kd/kdterminal.h | 39 ++++++-
ntoskrnl/kdbg/kdb.c | 24 ++---
ntoskrnl/kdbg/kdb.h | 24 +----
ntoskrnl/kdbg/kdb_cli.c | 207 ++++++++---------------------------
ntoskrnl/ntos.cmake | 3 +-
9 files changed, 407 insertions(+), 266 deletions(-)
diff --git a/ntoskrnl/kd/kd.h b/ntoskrnl/kd/kd.h
index 4440b183626..0e10f0c90b0 100644
--- a/ntoskrnl/kd/kd.h
+++ b/ntoskrnl/kd/kd.h
@@ -26,6 +26,11 @@ KdIoPrintf(
_In_ PCSTR Format,
...);
+SIZE_T
+KdIoReadLine(
+ _Out_ PCHAR Buffer,
+ _In_ SIZE_T Size);
+
/* INIT ROUTINES *************************************************************/
diff --git a/ntoskrnl/kd/kdmain.c b/ntoskrnl/kd/kdmain.c
index aaed45432db..8120ab52e5d 100644
--- a/ntoskrnl/kd/kdmain.c
+++ b/ntoskrnl/kd/kdmain.c
@@ -9,14 +9,42 @@
#include <ntoskrnl.h>
#include "kd.h"
+#include "kdterminal.h"
#define NDEBUG
#include <debug.h>
/* PUBLIC FUNCTIONS *********************************************************/
+static VOID
+KdpGetTerminalSettings(
+ _In_ PCSTR p1)
+{
+#define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
+
+ while (p1 && *p1)
+ {
+ /* Skip leading whitespace */
+ while (*p1 == ' ') ++p1;
+
+ if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
+ {
+ p1 += CONST_STR_LEN("KDSERIAL");
+ KdbDebugState |= KD_DEBUG_KDSERIAL;
+ KdpDebugMode.Serial = TRUE;
+ }
+ else if (!_strnicmp(p1, "KDNOECHO",
CONST_STR_LEN("KDNOECHO")))
+ {
+ p1 += CONST_STR_LEN("KDNOECHO");
+ KdbDebugState |= KD_DEBUG_KDNOECHO;
+ }
+
+ /* Move on to the next option */
+ p1 = strchr(p1, ' ');
+ }
+}
+
static PCHAR
-NTAPI
KdpGetDebugMode(
_In_ PCHAR Currentp2)
{
@@ -95,10 +123,8 @@ KdDebuggerInitialize0(
/* Upcase it */
_strupr(CommandLine);
-#ifdef KDBG
- /* Get the KDBG Settings */
- KdbpGetCommandLineSettings(CommandLine);
-#endif
+ /* Get terminal settings */
+ KdpGetTerminalSettings(CommandLine);
/* Get the port */
Port = strstr(CommandLine, "DEBUGPORT");
diff --git a/ntoskrnl/kd/kdprompt.c b/ntoskrnl/kd/kdprompt.c
index f9ac04f6d03..8c93eb413de 100644
--- a/ntoskrnl/kd/kdprompt.c
+++ b/ntoskrnl/kd/kdprompt.c
@@ -36,72 +36,23 @@ KdIoReadLine(
PCHAR Orig = Buffer;
ULONG ScanCode = 0;
CHAR Key;
- static CHAR NextKey = ANSI_NULL;
- BOOLEAN EchoOn;
+ BOOLEAN EchoOn = !(KdbDebugState & KD_DEBUG_KDNOECHO);
LONG CmdHistIndex = -1; // Start at end of history.
+ /* Flush the input buffer */
+ KdpFlushTerminalInput();
+
/* Bail out if the buffer is zero-sized */
if (Size == 0)
return 0;
- EchoOn = ((KdbDebugState & KD_DEBUG_KDNOECHO) == 0);
-
for (;;)
{
- ScanCode = 0;
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- {
- Key = (!NextKey ? KdbpGetCharSerial() : NextKey);
- NextKey = ANSI_NULL;
- if (Key == KEY_ESC) /* ESC */
- {
- Key = KdbpGetCharSerial();
- if (Key == '[')
- {
- Key = KdbpGetCharSerial();
-
- switch (Key)
- {
- case 'A':
- ScanCode = KEY_SCAN_UP;
- break;
- case 'B':
- ScanCode = KEY_SCAN_DOWN;
- break;
- case 'C':
- break;
- case 'D':
- break;
- }
- }
- }
- }
- else
- {
- Key = (!NextKey ? KdbpGetCharKeyboard(&ScanCode) : NextKey);
- NextKey = ANSI_NULL;
- }
+ Key = KdpReadTermKey(&ScanCode);
/* Check for return or newline */
if ((Key == '\r') || (Key == '\n'))
{
- if (Key == '\r')
- {
- /*
- * We might need to discard the next '\n' which most clients
- * should send after \r. Wait a bit to make sure we receive it.
- */
- KeStallExecutionProcessor(100000);
-
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- NextKey = KdbpTryGetCharSerial(5);
- else
- NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5);
-
- if (NextKey == '\n' || NextKey == -1) /* \n or no response at all
*/
- NextKey = ANSI_NULL;
- }
-
*Buffer = ANSI_NULL;
KdIoPuts("\n");
return (SIZE_T)(Buffer - Orig);
diff --git a/ntoskrnl/kd/kdterminal.c b/ntoskrnl/kd/kdterminal.c
new file mode 100644
index 00000000000..00888230f1e
--- /dev/null
+++ b/ntoskrnl/kd/kdterminal.c
@@ -0,0 +1,276 @@
+/*
+ * PROJECT: ReactOS KDBG Kernel Debugger Terminal Driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: KD Terminal Management
+ * COPYRIGHT: Copyright 2005 Gregor Anich <blight(a)blight.eu.org>
+ * Copyright 2022-2023 Hermès Bélusca-Maïto
<hermes.belusca-maito(a)reactos.org>
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#include "kdterminal.h"
+
+#define KdbpGetCharKeyboard(ScanCode) KdbpTryGetCharKeyboard((ScanCode), 0)
+CHAR
+KdbpTryGetCharKeyboard(PULONG ScanCode, ULONG Retry);
+
+#define KdbpGetCharSerial() KdbpTryGetCharSerial(0)
+CHAR
+KdbpTryGetCharSerial(
+ _In_ ULONG Retry);
+
+VOID
+KdbpSendCommandSerial(
+ _In_ PCSTR Command);
+
+
+/* GLOBALS *******************************************************************/
+
+/* KD Controlling Terminal */
+ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
+SIZE KdTermSize = {0,0};
+BOOLEAN KdTermConnected = FALSE;
+BOOLEAN KdTermSerial = FALSE;
+BOOLEAN KdTermReportsSize = TRUE;
+
+static CHAR KdTermNextKey = ANSI_NULL; /* 1-character input queue buffer */
+
+
+/* FUNCTIONS *****************************************************************/
+
+/**
+ * @brief Initializes the controlling terminal.
+ *
+ * @return
+ * TRUE if the controlling terminal is serial and detected
+ * as being connected, or FALSE if not.
+ **/
+BOOLEAN
+KdpInitTerminal(VOID)
+{
+ /* Determine whether the controlling terminal is a serial terminal:
+ * serial output is enabled *and* KDSERIAL is set (i.e. user input
+ * through serial). */
+ KdTermSerial =
+#if 0
+ // Old logic where KDSERIAL also enables serial output.
+ (KdbDebugState & KD_DEBUG_KDSERIAL) ||
+ (KdpDebugMode.Serial && !KdpDebugMode.Screen);
+#else
+ // New logic where KDSERIAL does not necessarily enable serial output.
+ KdpDebugMode.Serial &&
+ ((KdbDebugState & KD_DEBUG_KDSERIAL) || !KdpDebugMode.Screen);
+#endif
+
+ /* Flush the input buffer */
+ KdpFlushTerminalInput();
+
+ if (KdTermSerial)
+ {
+ ULONG Length;
+
+ /* Enable line-wrap */
+ KdbpSendCommandSerial("\x1b[?7h");
+
+ /*
+ * Query terminal type.
+ * Historically it was done with CTRL-E ('\x05'), however nowadays
+ * terminals respond to it with an empty (or a user-configurable)
+ * string. Instead, use the VT52-compatible 'ESC Z' sequence or the
+ * VT100-compatible 'ESC[c' one.
+ */
+ KdbpSendCommandSerial("\x1b[c");
+ KeStallExecutionProcessor(100000);
+
+ Length = 0;
+ for (;;)
+ {
+ /* Verify we get an answer, but don't care about it */
+ if (KdbpTryGetCharSerial(5000) == -1)
+ break;
+ ++Length;
+ }
+
+ /* Terminal is connected (TRUE) or not connected (FALSE) */
+ KdTermConnected = (Length > 0);
+ }
+ else
+ {
+ /* Terminal is not serial, assume it's *not* connected */
+ KdTermConnected = FALSE;
+ }
+ return KdTermConnected;
+}
+
+BOOLEAN
+KdpUpdateTerminalSize(
+ _Out_ PSIZE TermSize)
+{
+ static CHAR Buffer[128];
+ CHAR c;
+ LONG NumberOfCols = -1; // Or initialize to TermSize->cx ??
+ LONG NumberOfRows = -1; // Or initialize to TermSize->cy ??
+
+ /* Retrieve the size of the controlling terminal only when it is serial */
+ if (KdTermConnected && KdTermSerial && KdTermReportsSize)
+ {
+ /* Flush the input buffer */
+ KdpFlushTerminalInput();
+
+ /* Try to query the terminal size. A reply looks like "\x1b[8;24;80t"
*/
+ KdTermReportsSize = FALSE;
+ KdbpSendCommandSerial("\x1b[18t");
+ KeStallExecutionProcessor(100000);
+
+ c = KdbpTryGetCharSerial(5000);
+ if (c == KEY_ESC)
+ {
+ c = KdbpTryGetCharSerial(5000);
+ if (c == '[')
+ {
+ ULONG Length = 0;
+ for (;;)
+ {
+ c = KdbpTryGetCharSerial(5000);
+ if (c == -1)
+ break;
+
+ Buffer[Length++] = c;
+ if (isalpha(c) || Length >= (sizeof(Buffer) - 1))
+ break;
+ }
+ Buffer[Length] = ANSI_NULL;
+
+ if (Buffer[0] == '8' && Buffer[1] == ';')
+ {
+ SIZE_T i;
+ for (i = 2; (i < Length) && (Buffer[i] != ';');
i++);
+
+ if (Buffer[i] == ';')
+ {
+ Buffer[i++] = ANSI_NULL;
+
+ /* Number of rows is now at Buffer + 2
+ * and number of columns at Buffer + i */
+ NumberOfRows = strtoul(Buffer + 2, NULL, 0);
+ NumberOfCols = strtoul(Buffer + i, NULL, 0);
+ KdTermReportsSize = TRUE;
+ }
+ }
+ }
+ /* Clear further characters */
+ while (KdbpTryGetCharSerial(5000) != -1);
+ }
+ }
+
+ if (NumberOfCols <= 0)
+ {
+ /* Set the number of columns to the default */
+ if (KdpDebugMode.Screen && !KdTermSerial)
+ NumberOfCols = (SCREEN_WIDTH / 8 /*BOOTCHAR_WIDTH*/);
+ else
+ NumberOfCols = 80;
+ }
+ if (NumberOfRows <= 0)
+ {
+ /* Set the number of rows to the default */
+ if (KdpDebugMode.Screen && !KdTermSerial)
+ NumberOfRows = (SCREEN_HEIGHT / (13 /*BOOTCHAR_HEIGHT*/ + 1));
+ else
+ NumberOfRows = 24;
+ }
+
+ TermSize->cx = NumberOfCols;
+ TermSize->cy = NumberOfRows;
+
+ // KdIoPrintf("Cols/Rows: %dx%d\n", TermSize->cx, TermSize->cy);
+
+ return KdTermReportsSize;
+}
+
+/**
+ * @brief Flushes terminal input (either serial or PS/2).
+ **/
+VOID
+KdpFlushTerminalInput(VOID)
+{
+ KdTermNextKey = ANSI_NULL;
+ if (KdbDebugState & KD_DEBUG_KDSERIAL)
+ {
+ while (KdbpTryGetCharSerial(1) != -1);
+ }
+ else
+ {
+ ULONG ScanCode;
+ while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
+ }
+}
+
+/**
+ * @brief
+ * Reads one character from the terminal. This function returns
+ * a scan code even when reading is done from a serial terminal.
+ **/
+CHAR
+KdpReadTermKey(
+ _Out_ PULONG ScanCode)
+{
+ CHAR Key;
+
+ *ScanCode = 0;
+
+ if (KdbDebugState & KD_DEBUG_KDSERIAL)
+ {
+ Key = (!KdTermNextKey ? KdbpGetCharSerial() : KdTermNextKey);
+ KdTermNextKey = ANSI_NULL;
+ if (Key == KEY_ESC) /* ESC */
+ {
+ Key = KdbpGetCharSerial();
+ if (Key == '[')
+ {
+ Key = KdbpGetCharSerial();
+ switch (Key)
+ {
+ case 'A':
+ *ScanCode = KEY_SCAN_UP;
+ break;
+ case 'B':
+ *ScanCode = KEY_SCAN_DOWN;
+ break;
+ case 'C':
+ break;
+ case 'D':
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ Key = (!KdTermNextKey ? KdbpGetCharKeyboard(ScanCode) : KdTermNextKey);
+ KdTermNextKey = ANSI_NULL;
+ }
+
+ /* Check for return */
+ if (Key == '\r')
+ {
+ /*
+ * We might need to discard the next '\n' which most clients
+ * should send after \r. Wait a bit to make sure we receive it.
+ */
+ KeStallExecutionProcessor(100000);
+
+ if (KdbDebugState & KD_DEBUG_KDSERIAL)
+ KdTermNextKey = KdbpTryGetCharSerial(5);
+ else
+ KdTermNextKey = KdbpTryGetCharKeyboard(ScanCode, 5);
+
+ if (KdTermNextKey == '\n' || KdTermNextKey == -1) /* \n or no response at
all */
+ KdTermNextKey = ANSI_NULL;
+ }
+
+ return Key;
+}
+
+/* EOF */
diff --git a/ntoskrnl/kd/kdterminal.h b/ntoskrnl/kd/kdterminal.h
index d5aab3fe48c..d930ff7ae98 100644
--- a/ntoskrnl/kd/kdterminal.h
+++ b/ntoskrnl/kd/kdterminal.h
@@ -21,9 +21,40 @@
#define KEYSC_HOME 0x0047
#define KEYSC_ARROWUP 0x0048 // == KEY_SCAN_UP
-SIZE_T
-KdIoReadLine(
- _Out_ PCHAR Buffer,
- _In_ SIZE_T Size);
+
+typedef struct _SIZE
+{
+ LONG cx;
+ LONG cy;
+} SIZE, *PSIZE;
+
+/* KD Controlling Terminal */
+
+/* These values MUST be nonzero, they're used as bit masks */
+typedef enum _KDB_OUTPUT_SETTINGS
+{
+ KD_DEBUG_KDSERIAL = 1,
+ KD_DEBUG_KDNOECHO = 2
+} KDB_OUTPUT_SETTINGS;
+
+extern ULONG KdbDebugState;
+extern SIZE KdTermSize;
+extern BOOLEAN KdTermConnected;
+extern BOOLEAN KdTermSerial;
+extern BOOLEAN KdTermReportsSize;
+
+BOOLEAN
+KdpInitTerminal(VOID);
+
+BOOLEAN
+KdpUpdateTerminalSize(
+ _Out_ PSIZE TermSize);
+
+VOID
+KdpFlushTerminalInput(VOID);
+
+CHAR
+KdpReadTermKey(
+ _Out_ PULONG ScanCode);
/* EOF */
diff --git a/ntoskrnl/kdbg/kdb.c b/ntoskrnl/kdbg/kdb.c
index 1b03f692ec5..8fd5b6675d8 100644
--- a/ntoskrnl/kdbg/kdb.c
+++ b/ntoskrnl/kdbg/kdb.c
@@ -49,7 +49,6 @@ static BOOLEAN
KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleSte
LONG KdbLastBreakPointNr = -1; /* Index of the breakpoint which cause KDB to be entered
*/
ULONG KdbNumSingleSteps = 0; /* How many single steps to do */
BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */
-ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
static BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was entered
because of single step */
PEPROCESS KdbCurrentProcess = NULL; /* The current process context in which KDB runs
*/
PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was intered
*/
@@ -1624,33 +1623,24 @@ continue_execution:
}
VOID
-NTAPI
KdbpGetCommandLineSettings(
- PCHAR p1)
+ _In_ PCSTR p1)
{
#define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
- while (p1 && (p1 = strchr(p1, ' ')))
+ while (p1 && *p1)
{
- /* Skip other spaces */
+ /* Skip leading whitespace */
while (*p1 == ' ') ++p1;
- if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
- {
- p1 += CONST_STR_LEN("KDSERIAL");
- KdbDebugState |= KD_DEBUG_KDSERIAL;
- KdpDebugMode.Serial = TRUE;
- }
- else if (!_strnicmp(p1, "KDNOECHO",
CONST_STR_LEN("KDNOECHO")))
- {
- p1 += CONST_STR_LEN("KDNOECHO");
- KdbDebugState |= KD_DEBUG_KDNOECHO;
- }
- else if (!_strnicmp(p1, "FIRSTCHANCE",
CONST_STR_LEN("FIRSTCHANCE")))
+ if (!_strnicmp(p1, "FIRSTCHANCE",
CONST_STR_LEN("FIRSTCHANCE")))
{
p1 += CONST_STR_LEN("FIRSTCHANCE");
KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways);
}
+
+ /* Move on to the next option */
+ p1 = strchr(p1, ' ');
}
}
diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h
index 26c79577030..4e2c04e7e3c 100644
--- a/ntoskrnl/kdbg/kdb.h
+++ b/ntoskrnl/kdbg/kdb.h
@@ -51,12 +51,6 @@ typedef enum _KDB_ENTER_CONDITION
KdbEnterFromUmode
} KDB_ENTER_CONDITION;
-/* These values MUST be nonzero. They're used as bit masks. */
-typedef enum _KDB_OUTPUT_SETTINGS
-{
- KD_DEBUG_KDSERIAL = 1,
- KD_DEBUG_KDNOECHO = 2
-} KDB_OUTPUT_SETTINGS;
/* FUNCTIONS *****************************************************************/
@@ -187,7 +181,6 @@ extern LONG KdbLastBreakPointNr;
extern ULONG KdbNumSingleSteps;
extern BOOLEAN KdbSingleStepOver;
extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
-extern ULONG KdbDebugState;
LONG
KdbpGetNextBreakPointNr(
@@ -252,8 +245,8 @@ KdbpAttachToProcess(
PVOID ProcessId);
VOID
-NTAPI
-KdbpGetCommandLineSettings(PCHAR p1);
+KdbpGetCommandLineSettings(
+ _In_ PCSTR p1);
KD_CONTINUE_TYPE
KdbEnterDebuggerException(IN PEXCEPTION_RECORD64 ExceptionRecord,
@@ -289,19 +282,6 @@ KdbpSafeWriteMemory(OUT PVOID Dest,
IN PVOID Src,
IN ULONG Bytes);
-#define KdbpGetCharKeyboard(ScanCode) KdbpTryGetCharKeyboard((ScanCode), 0)
-CHAR
-KdbpTryGetCharKeyboard(PULONG ScanCode, ULONG Retry);
-
-#define KdbpGetCharSerial() KdbpTryGetCharSerial(0)
-CHAR
-KdbpTryGetCharSerial(
- _In_ ULONG Retry);
-
-VOID
-KdbpSendCommandSerial(
- _In_ PCSTR Command);
-
VOID
KbdDisableMouse(VOID);
diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c
index f909fecdfc7..f889bd850a7 100644
--- a/ntoskrnl/kdbg/kdb_cli.c
+++ b/ntoskrnl/kdbg/kdb_cli.c
@@ -131,8 +131,6 @@ static ULONG KdbNumberOfRowsPrinted = 0;
static ULONG KdbNumberOfColsPrinted = 0;
static BOOLEAN KdbOutputAborted = FALSE;
static BOOLEAN KdbRepeatLastCommand = FALSE;
-static LONG KdbNumberOfRowsTerminal = -1;
-static LONG KdbNumberOfColsTerminal = -1;
PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during
initialization */
BOOLEAN KdbpBugCheckRequested = FALSE;
@@ -2786,26 +2784,35 @@ memrchr(const void *s, int c, size_t n)
return NULL;
}
-/*!\brief Calculate pointer position for N lines upper of current position.
+/**
+ * @brief Calculate pointer position for N lines above the current position.
*
- * \param Buffer Characters buffer to operate on.
- * \param BufLength Buffer size.
+ * Calculate pointer position for N lines above the current displaying
+ * position within the given buffer. Used by KdbpPager().
*
- * \note Calculate pointer position for N lines upper of current displaying
- * position within the given buffer.
+ * @param[in] Buffer
+ * Character buffer to operate on.
*
- * Used by KdbpPager().
- * Now N lines count is hardcoded to KdbNumberOfRowsTerminal.
- */
+ * @param[in] BufLength
+ * Size of the buffer.
+ *
+ * @param[in] pCurPos
+ * Current position within the buffer.
+ *
+ * @return Beginning of the previous page of text.
+ *
+ * @note N lines count is hardcoded to the terminal's number of rows.
+ **/
static PCHAR
CountOnePageUp(
_In_ PCCH Buffer,
_In_ ULONG BufLength,
- _In_ PCCH pCurPos)
+ _In_ PCCH pCurPos,
+ _In_ const SIZE* TermSize)
{
PCCH p;
// p0 is initial guess of Page Start
- ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal;
+ ULONG p0len = TermSize->cx * TermSize->cy;
PCCH p0 = pCurPos - p0len;
PCCH prev_p = p0, p1;
ULONG j;
@@ -2817,7 +2824,7 @@ CountOnePageUp(
p = memrchr(p0, '\n', p0len);
if (!p)
p = p0;
- for (j = KdbNumberOfRowsTerminal; j--; )
+ for (j = TermSize->cy; j--; )
{
int linesCnt;
p1 = memrchr(p0, '\n', p-p0);
@@ -2830,7 +2837,7 @@ CountOnePageUp(
p = p0;
break;
}
- linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal;
+ linesCnt = (TermSize->cx+prev_p-p-2) / TermSize->cx;
if (linesCnt > 1)
j -= linesCnt-1;
}
@@ -2874,27 +2881,23 @@ KdpFilterEscapes(
* Maximum length of buffer is limited only by memory size.
* Uses KdpDprintf internally (NOT DbgPrint!). Callers must already hold the
debugger lock.
*
- * Note: BufLength should be greater then (KdbNumberOfRowsTerminal *
KdbNumberOfColsTerminal).
+ * Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
*/
-VOID
+static VOID
KdbpPagerInternal(
_In_ PCHAR Buffer,
_In_ ULONG BufLength,
_In_ BOOLEAN DoPage)
{
- static CHAR InBuffer[128];
static BOOLEAN TerminalInitialized = FALSE;
- static BOOLEAN TerminalConnected = FALSE;
- static BOOLEAN TerminalReportsSize = TRUE;
CHAR c;
ULONG ScanCode;
PCHAR p;
- ULONG Length;
SIZE_T i;
LONG RowsPrintedByTerminal;
if (BufLength == 0)
- return;
+ return;
/* Check if the user has aborted output of the current command */
if (KdbOutputAborted)
@@ -2904,117 +2907,13 @@ KdbpPagerInternal(
if (!TerminalInitialized)
{
TerminalInitialized = TRUE;
-
- /* Enable line-wrap */
- KdbpSendCommandSerial("\x1b[?7h");
-
- /*
- * Query terminal type.
- * Historically it was done with CTRL-E ('\x05'), however nowadays
- * terminals respond to it with an empty (or a user-configurable)
- * string. Instead, use the VT52-compatible 'ESC Z' sequence or the
- * VT100-compatible 'ESC[c' one.
- */
- KdbpSendCommandSerial("\x1b[c");
- KeStallExecutionProcessor(100000);
-
- Length = 0;
- for (;;)
- {
- /* Verify we get an answer, but don't care about it */
- c = KdbpTryGetCharSerial(5000);
- if (c == -1)
- break;
- ++Length;
- }
- if (Length > 0)
- TerminalConnected = TRUE;
+ KdpInitTerminal();
}
- /* Get number of rows and columns in terminal */
- if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
- /* Refresh terminal size each time when number of rows printed is 0 */
- (KdbNumberOfRowsPrinted) == 0)
+ /* Refresh terminal size each time when number of rows printed is 0 */
+ if (KdbNumberOfRowsPrinted == 0)
{
- /* Retrieve the size of the serial terminal only when it is the
- * controlling terminal: serial output is enabled *and* KDSERIAL
- * is set (i.e. user input through serial). */
- BOOLEAN SerialTerminal =
-#if 0
- // Old logic where KDSERIAL also enables serial output.
- (KdbDebugState & KD_DEBUG_KDSERIAL) ||
- (KdpDebugMode.Serial && !KdpDebugMode.Screen);
-#else
- // New logic where KDSERIAL does not necessarily enable serial output.
- KdpDebugMode.Serial &&
- ((KdbDebugState & KD_DEBUG_KDSERIAL) || !KdpDebugMode.Screen);
-#endif
-
- if (SerialTerminal && TerminalConnected && TerminalReportsSize)
- {
- /* Try to query number of rows from terminal. A reply looks like
"\x1b[8;24;80t" */
- TerminalReportsSize = FALSE;
- KdbpSendCommandSerial("\x1b[18t");
- KeStallExecutionProcessor(100000);
-
- c = KdbpTryGetCharSerial(5000);
- if (c == KEY_ESC)
- {
- c = KdbpTryGetCharSerial(5000);
- if (c == '[')
- {
- Length = 0;
- for (;;)
- {
- c = KdbpTryGetCharSerial(5000);
- if (c == -1)
- break;
-
- InBuffer[Length++] = c;
- if (isalpha(c) || Length >= (sizeof(InBuffer) - 1))
- break;
- }
- InBuffer[Length] = '\0';
-
- if (InBuffer[0] == '8' && InBuffer[1] ==
';')
- {
- for (i = 2; (i < Length) && (InBuffer[i] !=
';'); i++);
-
- if (InBuffer[i] == ';')
- {
- InBuffer[i++] = '\0';
-
- /* Number of rows is now at Buffer + 2 and number of cols at
Buffer + i */
- KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, NULL, 0);
- KdbNumberOfColsTerminal = strtoul(InBuffer + i, NULL, 0);
- TerminalReportsSize = TRUE;
- }
- }
- }
- /* Clear further characters */
- while ((c = KdbpTryGetCharSerial(5000)) != -1);
- }
- }
-
- if (KdbNumberOfRowsTerminal <= 0)
- {
- /* Set number of rows to the default */
- if (KdpDebugMode.Screen && !SerialTerminal)
- KdbNumberOfRowsTerminal = (SCREEN_HEIGHT / (13 /*BOOTCHAR_HEIGHT*/ +
1));
- else
- KdbNumberOfRowsTerminal = 24;
- }
- if (KdbNumberOfColsTerminal <= 0)
- {
- /* Set number of cols to the default */
- if (KdpDebugMode.Screen && !SerialTerminal)
- KdbNumberOfColsTerminal = (SCREEN_WIDTH / 8 /*BOOTCHAR_WIDTH*/);
- else
- KdbNumberOfColsTerminal = 80;
- }
-
- // KdpDprintf("Cols/Rows: %dx%d\n",
- // KdbNumberOfColsTerminal, KdbNumberOfRowsTerminal);
+ KdpUpdateTerminalSize(&KdTermSize);
}
/* Loop through the strings */
@@ -3041,7 +2940,7 @@ KdbpPagerInternal(
/* Calculate the number of lines which will be printed in
* the terminal when outputting the current line. */
if (i > 0)
- RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) /
KdbNumberOfColsTerminal;
+ RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdTermSize.cx;
else
RowsPrintedByTerminal = 0;
@@ -3051,9 +2950,10 @@ KdbpPagerInternal(
//KdpDprintf("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted,
KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);
/* Display a prompt if we printed one screen full of text */
- if (KdbNumberOfRowsTerminal > 0 &&
- (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >=
KdbNumberOfRowsTerminal)
+ if (KdTermSize.cy > 0 &&
+ (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdTermSize.cy)
{
+ /* Disable the repetition of previous command with long many-page output */
KdbRepeatLastCommand = FALSE;
if (KdbNumberOfColsPrinted > 0)
@@ -3069,21 +2969,7 @@ KdbpPagerInternal(
}
RowsPrintedByTerminal++;
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- c = KdbpGetCharSerial();
- else
- c = KdbpGetCharKeyboard(&ScanCode);
-
- if (c == '\r')
- {
- /* Try to read '\n' which might follow '\r' - if \n is
not received here
- * it will be interpreted as "return" when the next command
should be read.
- */
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- c = KdbpTryGetCharSerial(5);
- else
- c = KdbpTryGetCharKeyboard(&ScanCode, 5);
- }
+ c = KdpReadTermKey(&ScanCode);
if (DoPage)
{
@@ -3106,13 +2992,13 @@ KdbpPagerInternal(
if (ScanCode == KEYSC_END || c == 'e')
{
PCHAR pBufEnd = Buffer + BufLength;
- p = CountOnePageUp(Buffer, BufLength, pBufEnd);
+ p = CountOnePageUp(Buffer, BufLength, pBufEnd, &KdTermSize);
i = strcspn(p, "\n");
}
else if (ScanCode == KEYSC_PAGEUP ||
ScanCode == KEYSC_ARROWUP || c == 'u')
{
- p = CountOnePageUp(Buffer, BufLength, p);
+ p = CountOnePageUp(Buffer, BufLength, p, &KdTermSize);
i = strcspn(p, "\n");
}
else if (ScanCode == KEYSC_HOME || c == 'h')
@@ -3139,11 +3025,10 @@ KdbpPagerInternal(
/* Remove escape sequences from the line if there is no terminal connected */
// FIXME: Dangerous operation since we modify the source string!!
- if (!TerminalConnected)
+ if (!KdTermConnected)
KdpFilterEscapes(p);
/* Print the current line */
- // KdpDprintf(p);
KdpDprintf("%s", p);
/* Restore not null char with saved */
@@ -3178,7 +3063,7 @@ KdbpPagerInternal(
* Maximum length of buffer is limited only by memory size.
* Uses KdpDprintf internally (NOT DbgPrint!). Callers must already hold the
debugger lock.
*
- * Note: BufLength should be greater then (KdbNumberOfRowsTerminal *
KdbNumberOfColsTerminal).
+ * Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
*/
VOID
KdbpPager(
@@ -3408,17 +3293,6 @@ KdbpCliMainLoop(
KdbpPrint("\n");
}
- /* Flush the input buffer */
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- {
- while (KdbpTryGetCharSerial(1) != -1);
- }
- else
- {
- ULONG ScanCode;
- while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
- }
-
/* Main loop */
do
{
@@ -3687,6 +3561,13 @@ KdbInitialize(
/* Write out the functions that we support for now */
DispatchTable->KdpPrintRoutine = KdbDebugPrint;
+ /* Check if we have a command line */
+ if (KeLoaderBlock && KeLoaderBlock->LoadOptions)
+ {
+ /* Get the KDBG Settings */
+ KdbpGetCommandLineSettings(KeLoaderBlock->LoadOptions);
+ }
+
/* Register for BootPhase 1 initialization and as a Provider */
DispatchTable->KdpInitRoutine = KdbInitialize;
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake
index 8df4eacccc3..8f3b6c8abbf 100644
--- a/ntoskrnl/ntos.cmake
+++ b/ntoskrnl/ntos.cmake
@@ -415,7 +415,8 @@ if(NOT _WINKD_)
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdmain.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdprompt.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdps2kbd.c
- ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdserial.c)
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdserial.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdterminal.c)
else()
add_definitions(-D_WINKD_)