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 #include "kd.h" +#include "kdterminal.h" #define NDEBUG #include /* 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 + * Copyright 2022-2023 Hermès Bélusca-Maïto + */ + +/* INCLUDES ******************************************************************/ + +#include +#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_)