From patchwork Mon Aug 25 16:27:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 125 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756139266; bh=329Z7Lugc4yfkCyg7EiFlhBEvFOOi7J41ahHDswgxeY=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=E9DWBoBXAxCjS6aPHhnFHTxv+faMnbec9bVUP9wkx9yP3YEBxwKxWUBwueKJQJopY Nepwa85upHBNB//mpsc0QC4Mjn9pAcywV7EOeO1PvWdSRoQiXUaU3ifKKrpdhgY6U7 2VsyH9dtWaXELzInCuLNPOAWMTTolXuGEbVfAeVOpF3p4ZRhdiKuBwjni8CStX+knj NuRIdydJA5f7NSYTKqDbX8AZPduUG2WWmgStdd7zGcri46AfmWhxsQhlqg3wS++1Ll /liRTEACRtCI9WZiQfX1IMUiMKTZybV2bPgUIxuxzqn78c42BXTOCJk6pLyz+Byfze r00sjlHkCeNuA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 92EFF677A0 for ; Mon, 25 Aug 2025 10:27:46 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id BOuHjwibrSbh for ; Mon, 25 Aug 2025 10:27:46 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756139263; bh=329Z7Lugc4yfkCyg7EiFlhBEvFOOi7J41ahHDswgxeY=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=qzuhk66Zmm3cvFPigfrNgvcnITs35H4chaFnxu2AH09SeZsh4i7zpMwELSbDv10IG 551SitqYY8ko1hlvSVQ6FId+nyFI/OfvoO73Y+38g+o4bs8Cv9gv7moewRN8bIOVJQ /i+rnuayxtyN37LVdL0XsqM08Oxt9I3LWmO8YWaxd4DnUDjiArk1NN2yZuk7Tv7TOP I5VC+AkHF2S+w21ZHMrU+eAOOeBxt9f31o9R4X6lX6jjV24+joEoNH3zVEbZJjGuse 47CExkHZdaJwySdmrz5y8PXoZ9MOTfCaJxRLHLv05EWqkONYlLCCcRz9TMo0kK83R+ o+ZRf/hWhSmEg== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C3ED46779C for ; Mon, 25 Aug 2025 10:27:43 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756139261; bh=D87RFgP7q7oRfM0Osrbwfy2tmMt0AfuKvfGoD/9j02g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bgMiBBwFG2NeOCi6f1u6XvvZjZb+ecaHMXfD9NxP5e+xHEAaKP28gPqz/+f/kHee3 H/UXHdgGf3dW6nyAD3gxGiKETOkzyGGADz5326++Uo1nZxfn3djX7FpEI67vyv5Kxl f2t3bYvBpRvgYPlXd7gx3lUCvGEy+ue/Oq5t5YWJM+hv6xVJQEEmkCIKX22DGTGIEy 12We6dyWSqr0joWQt/VbqfvbEPsRwdk87bBh8xTGLYGZoaE3jh6V16Uzhfv2FCiEv6 5ePrW1fK3E3d9BMNXySyCh3fYr6ypEo2sknHJoMI9ZtOdzjCDMrBdBHOB8Y3shJvWs FZx7wMmiXQLCw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 971CC6778A; Mon, 25 Aug 2025 10:27:41 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id j4zky1XVKVKt; Mon, 25 Aug 2025 10:27:41 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1756139261; bh=o8l2oBLudPfRpxQ7L0Dq7KaDaR2t5IaknUcei2/XzwE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YIPSUbsRwxqToOVQSA5h66wfOXoy7jj3+HQ1sVsrGu7hWdTtJxixsUSVC81gN/wPD cEeqE281IspWA8d+Dt8j+9IoyKXxvjPdt04sVFtP2vPoY7pMTAaGcqiVI+pSOY/Uf+ 77nzWRuqwuwZg3pwGc4wyOombej+fA6Qte4Lyg+tPGaFnUs1cI25SWPjrmSvkwEXdL sWMEkLFqR9Cfb5XGpEXu1gSJhzxk3xGfkk/ahbCBgVOPO4lxFamX6/ua0ydc0rYjhT ZCU81or1Ss1NVR4iGNN5F0P+QInDB3EAI0p1KxkTkCw5VDoxBtUCRAnmdXCr3bA/5G /64qE8fkx0oug== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id C1C15676E8; Mon, 25 Aug 2025 10:27:40 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Mon, 25 Aug 2025 10:27:07 -0600 Message-ID: <20250825162727.3185381-5-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250825162727.3185381-1-sjg@u-boot.org> References: <20250825162727.3185381-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: HHK65WF542SKNSIV2B5DJPDIZJYBCEVF X-Message-ID-Hash: HHK65WF542SKNSIV2B5DJPDIZJYBCEVF X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Heinrich Schuchardt , Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH v2 04/16] serial: Generalise the code to check the terminal size List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The EFI loader has some code to check the size (rows and columns) of an attached terminal. Move this over to the serial uclass so that it can be used elsewhere. Create a new CONFIG_SERIAL_TERM_PRESENT to control whether it should be used. Enable that for the EFI loader to preserve existing behaviour. Adjust the implementation so that it returns a useful error code on failure. Put the ESC and cESC values in the serial.h header. Signed-off-by: Simon Glass --- (no changes since v1) drivers/serial/Kconfig | 15 ++++ drivers/serial/serial-uclass.c | 118 +++++++++++++++++++++++++++++++ include/serial.h | 18 +++++ lib/efi_loader/efi_console.c | 124 +-------------------------------- 4 files changed, 154 insertions(+), 121 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index d58152abc7f..7d27dad327d 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -202,6 +202,21 @@ config VPL_DM_SERIAL implements serial_putc() etc. The uclass interface is defined in include/serial.h. +config SERIAL_TERM_PRESENT + bool "Assume there is a serial terminal present on the serial line" + depends on DM_SERIAL + default y if EFI_LOADER + help + In some cases boards are connected to a serial terminal and it is + useful to emit ANSI codes or other characters to determine the + properties of the terminal. + + Enable this if you wish to have these features. + + Note that enabling this for a board which is sending its output to + a log will result in junk in the log. It also introduces a delay of + up to 100ms on startup. + config DEBUG_UART bool "Enable an early debug UART for debugging" help diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index a08678dde4e..1204fb5d4c4 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -557,6 +558,123 @@ static int on_baudrate(const char *name, const char *value, enum env_op op, } U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); +/** + * term_get_char() - read a character from the console + * + * Wait for up to 100 ms to read a character from the console. + * + * @c: pointer to the buffer to receive the character + * Return: 0 on success, -ETIMEDOUT if timed out + */ +static int term_get_char(s32 *c) +{ + u64 timeout; + + /* Wait up to 100 ms for a character */ + timeout = timer_get_us() + 100000; + + while (!tstc()) + if (timer_get_us() > timeout) + return -ETIMEDOUT; + + *c = getchar(); + + return 0; +} + +/** + * term_read_reply() - receive and parse a reply from the terminal + * + * @n: array of return values + * @num: number of return values expected + * @end_char: character indicating end of terminal message + * Return: non-zero indicates error + */ +static int term_read_reply(int *n, int num, char end_char) +{ + int ret, i = 0; + s32 c; + + ret = term_get_char(&c); + if (ret) + return ret; + if (c != cESC) + return -EPROTO; + + ret = term_get_char(&c); + if (ret) + return ret; + if (c != '[') + return -EPROTO; + + n[0] = 0; + while (1) { + int ret; + + ret = term_get_char(&c); + if (ret) + return ret; + + if (c == ';') { + i++; + if (i >= num) + return -EPROTO; + n[i] = 0; + continue; + } else if (c == end_char) { + break; + } else if (c > '9' || c < '0') { + return -EPROTO; + } + + /* Read one more decimal position */ + n[i] *= 10; + n[i] += c - '0'; + } + if (i != num - 1) + return -EPROTO; + + return 0; +} + +int serial_query_size(int *rowsp, int *colsp) +{ + int ret = 0; + int n[2]; + + if (!CONFIG_IS_ENABLED(SERIAL_TERM_PRESENT)) + return -ENOENT; + + /* Empty input buffer */ + while (tstc()) + getchar(); + + /* + * Not all terminals understand CSI [18t for querying the console size. + * We should adhere to escape sequences documented in the console_codes + * man page and the ECMA-48 standard. + * + * So here we follow a different approach. We position the cursor to the + * bottom right and query its position. Before leaving the function we + * restore the original cursor position. + */ + puts(ESC "7" /* Save cursor position */ + ESC "[r" /* Set scrolling region to full window */ + ESC "[999;999H" /* Move to bottom right corner */ + ESC "[6n"); /* Query cursor position */ + + /* Read {rows,cols} */ + ret = term_read_reply(n, 2, 'R'); + if (!ret) { + *colsp = n[1]; + *rowsp = n[0]; + } + + printf(ESC "8"); /* Restore cursor position */ + + return ret; +} + #if CONFIG_IS_ENABLED(SERIAL_PRESENT) static int serial_post_probe(struct udevice *dev) { diff --git a/include/serial.h b/include/serial.h index e5f6d984d28..2aba4c313c2 100644 --- a/include/serial.h +++ b/include/serial.h @@ -3,6 +3,10 @@ #include +/* Escape value */ +#define cESC '\x1b' +#define ESC "\x1b" + struct serial_device { /* enough bytes to match alignment of following func pointer */ char name[16]; @@ -382,4 +386,18 @@ static inline void serial_flush(void) {} int serial_getc(void); int serial_tstc(void); +/** + * serial_query_size() - query serial console size + * + * When using a serial console or the net console we can only devise the + * terminal size by querying the terminal using ECMA-48 control sequences. + * + * @rowsp: returns number of rows + * @colsp: returns number of columns + * Returns: 0 on success, -NOENT if no terminal is present, -ETIMEDOUT if we + * checked for a terminal but didn't get a response in time, -EPROTO if the + * terminal did not respond as expected + */ +int serial_query_size(int *rowsp, int *colsp); + #endif diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index ade44cb6e36..d2eabfdb07e 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -59,9 +60,6 @@ const efi_guid_t efi_guid_text_input_protocol = const efi_guid_t efi_guid_text_output_protocol = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID; -#define cESC '\x1b' -#define ESC "\x1b" - /* * efi_con_mode - mode information of the Simple Text Output Protocol * @@ -77,76 +75,6 @@ static struct simple_text_output_mode efi_con_mode = { .cursor_visible = 1, }; -/** - * term_get_char() - read a character from the console - * - * Wait for up to 100 ms to read a character from the console. - * - * @c: pointer to the buffer to receive the character - * Return: 0 on success, 1 otherwise - */ -static int term_get_char(s32 *c) -{ - u64 timeout; - - /* Wait up to 100 ms for a character */ - timeout = timer_get_us() + 100000; - - while (!tstc()) - if (timer_get_us() > timeout) - return 1; - - *c = getchar(); - return 0; -} - -/** - * term_read_reply() - receive and parse a reply from the terminal - * - * @n: array of return values - * @num: number of return values expected - * @end_char: character indicating end of terminal message - * Return: non-zero indicates error - */ -static int term_read_reply(int *n, int num, char end_char) -{ - s32 c; - int i = 0; - - if (term_get_char(&c) || c != cESC) - return -1; - - if (term_get_char(&c) || c != '[') - return -1; - - n[0] = 0; - while (1) { - if (!term_get_char(&c)) { - if (c == ';') { - i++; - if (i >= num) - return -1; - n[i] = 0; - continue; - } else if (c == end_char) { - break; - } else if (c > '9' || c < '0') { - return -1; - } - - /* Read one more decimal position */ - n[i] *= 10; - n[i] += c - '0'; - } else { - return -1; - } - } - if (i != num - 1) - return -1; - - return 0; -} - /** * efi_cout_output_string() - write Unicode string to console * @@ -272,52 +200,6 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols) return (mode->rows == rows) && (mode->columns == cols); } -/** - * query_console_serial() - query serial console size - * - * When using a serial console or the net console we can only devise the - * terminal size by querying the terminal using ECMA-48 control sequences. - * - * @rows: pointer to return number of rows - * @cols: pointer to return number of columns - * Returns: 0 on success - */ -static int query_console_serial(int *rows, int *cols) -{ - int ret = 0; - int n[2]; - - /* Empty input buffer */ - while (tstc()) - getchar(); - - /* - * Not all terminals understand CSI [18t for querying the console size. - * We should adhere to escape sequences documented in the console_codes - * man page and the ECMA-48 standard. - * - * So here we follow a different approach. We position the cursor to the - * bottom right and query its position. Before leaving the function we - * restore the original cursor position. - */ - printf(ESC "7" /* Save cursor position */ - ESC "[r" /* Set scrolling region to full window */ - ESC "[999;999H" /* Move to bottom right corner */ - ESC "[6n"); /* Query cursor position */ - - /* Read {rows,cols} */ - if (term_read_reply(n, 2, 'R')) { - ret = 1; - goto out; - } - - *cols = n[1]; - *rows = n[0]; -out: - printf(ESC "8"); /* Restore cursor position */ - return ret; -} - /** * query_vidconsole() - query video console size * @@ -363,8 +245,8 @@ void efi_setup_console_size(void) if (IS_ENABLED(CONFIG_VIDEO)) ret = query_vidconsole(&rows, &cols); - if (ret) - ret = query_console_serial(&rows, &cols); + if (ret && IS_ENABLED(CONFIG_DM_SERIAL)) + ret = serial_query_size(&rows, &cols); if (ret) return;