* [PATCH 1/9] lib: term: avoid printing NUL with new new console_puts API
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
@ 2026-05-01 6:53 ` Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 2/9] lib: term: return error code from term_getsize() Ahmad Fatoum
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:53 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
sizeof(esc) includes the NUL terminator, which gets sent through
cdev->puts and may render as a glyph on the other side's terminal.
Use the new console_puts to avoid this.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
lib/term.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/term.c b/lib/term.c
index 73a9904c2e1f..0aa4612d0b08 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -34,7 +34,7 @@ void term_getsize(int *screenwidth, int *screenheight)
memset(buf, 0, sizeof(buf));
- cdev->puts(cdev, esc, sizeof(esc));
+ console_puts(cdev, esc);
n = 0;
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 2/9] lib: term: return error code from term_getsize()
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 1/9] lib: term: avoid printing NUL with new new console_puts API Ahmad Fatoum
@ 2026-05-01 6:53 ` Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 3/9] lib: term: add per-console terminal response parser Ahmad Fatoum
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:53 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Instead of silently writing a magic value of 256 into the output
parameters on error, let callers distinguish the case that
"no interactive console responded" from a legitimate terminal size
by means of an error code.
No current user makes use of the 256 magic value, so we only need to
change term_getsize() itself.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
include/term.h | 2 +-
lib/term.c | 32 +++++++++++++++++++-------------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/include/term.h b/include/term.h
index 097f84681d49..e53fcffcfc28 100644
--- a/include/term.h
+++ b/include/term.h
@@ -3,6 +3,6 @@
#define __TERM_H
void term_setpos(int x, int y);
-void term_getsize(int *screenwidth, int *screenheight);
+int term_getsize(int *screenwidth, int *screenheight);
#endif /* __LIBBB_H */
diff --git a/lib/term.c b/lib/term.c
index 0aa4612d0b08..78158a3036c3 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -11,20 +11,17 @@ void term_setpos(int x, int y)
printf("\x1b[%d;%dH", y + 2, x + 1);
}
-void term_getsize(int *screenwidth, int *screenheight)
+int term_getsize(int *screenwidth, int *screenheight)
{
int n;
+ int width = INT_MAX, height = INT_MAX;
+ bool found = false;
char *endp;
const char esc[] = "\e7" "\e[r" "\e[999;999H" "\e[6n";
char buf[64];
- if (screenwidth)
- *screenwidth = 256;
- if (screenheight)
- *screenheight = 256;
-
for_each_console(cdev) {
- int width, height;
+ int w, h;
uint64_t start;
if (!(cdev->f_active & CONSOLE_STDIN))
@@ -60,14 +57,23 @@ void term_getsize(int *screenwidth, int *screenheight)
if (buf[1] != '[')
continue;
- height = simple_strtoul(buf + 2, &endp, 10);
- width = simple_strtoul(endp + 1, NULL, 10);
+ h = simple_strtoul(buf + 2, &endp, 10);
+ w = simple_strtoul(endp + 1, NULL, 10);
- if (screenwidth)
- *screenwidth = min(*screenwidth, width);
- if (screenheight)
- *screenheight = min(*screenheight, height);
+ width = min(w, width);
+ height = min(h, height);
+ found = true;
}
term_setpos(0, 0);
+
+ if (!found)
+ return -ENOENT;
+
+ if (screenwidth)
+ *screenwidth = width;
+ if (screenheight)
+ *screenheight = height;
+
+ return 0;
}
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 3/9] lib: term: add per-console terminal response parser
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 1/9] lib: term: avoid printing NUL with new new console_puts API Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 2/9] lib: term: return error code from term_getsize() Ahmad Fatoum
@ 2026-05-01 6:53 ` Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 4/9] lib: term: factor out single cdev handling from term_getsize Ahmad Fatoum
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:53 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Add term_cdev_read_reply() to parse CSI responses from the specified
console device, replacing the open-coded parsing in term_getsize().
The function collects the response into a buffer with a single 100ms
timeout, then validates and parses it using simple_strtoul, keeping
the same timeout and parsing semantics as the original code.
Also add term_cdev_drain() to discard pending input before sending
a query, preventing stale data from being parsed as a response.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
lib/term.c | 96 +++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 66 insertions(+), 30 deletions(-)
diff --git a/lib/term.c b/lib/term.c
index 78158a3036c3..96fdb0737d31 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -3,6 +3,8 @@
#include <linux/kstrtox.h>
#include <linux/minmax.h>
+#include <errno.h>
+#include <clock.h>
#include <console.h>
#include <term.h>
@@ -11,54 +13,88 @@ void term_setpos(int x, int y)
printf("\x1b[%d;%dH", y + 2, x + 1);
}
+static void term_cdev_drain(struct console_device *cdev)
+{
+ while (cdev->tstc(cdev))
+ cdev->getc(cdev);
+}
+
+/**
+ * term_cdev_read_reply - read and parse a CSI response from a console
+ * @cdev: console device to read from
+ * @params: output array of parsed integer parameters
+ * @num: number of expected parameters
+ * @end_char: character that terminates the response (e.g. 'R')
+ *
+ * Reads a CSI response of the form ESC [ Pn ; Pn ; ... <end_char>
+ * with a single 100ms timeout for the entire response.
+ *
+ * Return: 0 on success, -ETIMEDOUT or -EINVAL on failure.
+ */
+static int term_cdev_read_reply(struct console_device *cdev,
+ int *params, int num, char end_char)
+{
+ char buf[64];
+ uint64_t start;
+ char *endp;
+ int n = 0, i;
+
+ start = get_time_ns();
+
+ while (1) {
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+
+ if (!cdev->tstc(cdev))
+ continue;
+
+ buf[n] = cdev->getc(cdev);
+ if (buf[n] == end_char)
+ break;
+
+ if (++n >= sizeof(buf) - 1)
+ return -EINVAL;
+ }
+
+ if (n < 2 || buf[0] != '\e' || buf[1] != '[')
+ return -EINVAL;
+
+ endp = buf + 2;
+ for (i = 0; i < num; i++) {
+ params[i] = simple_strtoul(endp, &endp, 10);
+ if (i < num - 1) {
+ if (*endp != ';')
+ return -EINVAL;
+ endp++;
+ }
+ }
+
+ return 0;
+}
+
int term_getsize(int *screenwidth, int *screenheight)
{
- int n;
int width = INT_MAX, height = INT_MAX;
bool found = false;
- char *endp;
const char esc[] = "\e7" "\e[r" "\e[999;999H" "\e[6n";
- char buf[64];
for_each_console(cdev) {
- int w, h;
- uint64_t start;
+ int w, h, params[2];
if (!(cdev->f_active & CONSOLE_STDIN))
continue;
if (!(cdev->f_active & CONSOLE_STDOUT))
continue;
- memset(buf, 0, sizeof(buf));
+ term_cdev_drain(cdev);
console_puts(cdev, esc);
- n = 0;
-
- start = get_time_ns();
-
- while (1) {
- if (is_timeout(start, 100 * MSECOND))
- break;
-
- if (!cdev->tstc(cdev))
- continue;
-
- buf[n] = cdev->getc(cdev);
-
- if (buf[n] == 'R')
- break;
-
- n++;
- }
-
- if (buf[0] != 27)
- continue;
- if (buf[1] != '[')
+ if (term_cdev_read_reply(cdev, params, 2, 'R'))
continue;
- h = simple_strtoul(buf + 2, &endp, 10);
- w = simple_strtoul(endp + 1, NULL, 10);
+ h = params[0];
+ w = params[1];
width = min(w, width);
height = min(h, height);
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 4/9] lib: term: factor out single cdev handling from term_getsize
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (2 preceding siblings ...)
2026-05-01 6:53 ` [PATCH 3/9] lib: term: add per-console terminal response parser Ahmad Fatoum
@ 2026-05-01 6:53 ` Ahmad Fatoum
2026-05-01 6:53 ` [PATCH 5/9] lib: term: fix term_getsize cursor restore Ahmad Fatoum
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:53 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The logic is easier to follow with the per-cdev code split off.
No functional change intended.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
include/term.h | 5 +++++
lib/term.c | 42 +++++++++++++++++++++++++++---------------
2 files changed, 32 insertions(+), 15 deletions(-)
diff --git a/include/term.h b/include/term.h
index e53fcffcfc28..4845aad6ec66 100644
--- a/include/term.h
+++ b/include/term.h
@@ -2,7 +2,12 @@
#ifndef __TERM_H
#define __TERM_H
+struct console_device;
+
void term_setpos(int x, int y);
int term_getsize(int *screenwidth, int *screenheight);
+int term_cdev_get_size(struct console_device *cdev,
+ int *screenwidth, int *screenheight);
+
#endif /* __LIBBB_H */
diff --git a/lib/term.c b/lib/term.c
index 96fdb0737d31..3949aeb45136 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -72,29 +72,41 @@ static int term_cdev_read_reply(struct console_device *cdev,
return 0;
}
+int term_cdev_get_size(struct console_device *cdev,
+ int *screenwidth, int *screenheight)
+{
+ const char esc[] = "\e7" "\e[r" "\e[999;999H" "\e[6n";
+ int ret, params[2];
+
+ if (!(cdev->f_active & CONSOLE_STDIN))
+ return -ENOENT;
+ if (!(cdev->f_active & CONSOLE_STDOUT))
+ return -ENOENT;
+
+ term_cdev_drain(cdev);
+
+ console_puts(cdev, esc);
+
+ ret = term_cdev_read_reply(cdev, params, 2, 'R');
+ if (ret)
+ return ret;
+
+ *screenheight = params[0];
+ *screenwidth = params[1];
+
+ return 0;
+}
+
int term_getsize(int *screenwidth, int *screenheight)
{
int width = INT_MAX, height = INT_MAX;
bool found = false;
- const char esc[] = "\e7" "\e[r" "\e[999;999H" "\e[6n";
for_each_console(cdev) {
- int w, h, params[2];
+ int w, h;
- if (!(cdev->f_active & CONSOLE_STDIN))
+ if (term_cdev_get_size(cdev, &w, &h))
continue;
- if (!(cdev->f_active & CONSOLE_STDOUT))
- continue;
-
- term_cdev_drain(cdev);
-
- console_puts(cdev, esc);
-
- if (term_cdev_read_reply(cdev, params, 2, 'R'))
- continue;
-
- h = params[0];
- w = params[1];
width = min(w, width);
height = min(h, height);
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 5/9] lib: term: fix term_getsize cursor restore
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (3 preceding siblings ...)
2026-05-01 6:53 ` [PATCH 4/9] lib: term: factor out single cdev handling from term_getsize Ahmad Fatoum
@ 2026-05-01 6:53 ` Ahmad Fatoum
2026-05-01 6:54 ` [PATCH 6/9] console: add get_size callback for direct size reporting Ahmad Fatoum
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:53 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
term_getsize() sends \e7 (DECSC) per-cdev to Save Cursor position, but
fails to use \e8 (DECRC) to Restore Cursor on each console afterwards.
Instead, it attempts to restore with term_setpos(0, 0) which uses printf()
internally and thus hits all stdout consoles, including ones that were
never queried like fbconsole.
Fix this by making cursor saving/restoring per-console by means of
DECSC/DECRC and thereby removing the term_setpos(0, 0) call entirely.
Both existent callers are safe without the term_setpos(0, 0):
- edit.c immediately clears the screen with \e[2J and positions its own
cursor
- watch.c sends \e[H\e[J (home + clear) before calling term_getsize
Also send DECRC on parse failure to restore cursor even when the terminal
didn't respond to the position query.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
lib/term.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/term.c b/lib/term.c
index 3949aeb45136..0a656d79e725 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -76,6 +76,7 @@ int term_cdev_get_size(struct console_device *cdev,
int *screenwidth, int *screenheight)
{
const char esc[] = "\e7" "\e[r" "\e[999;999H" "\e[6n";
+ const char restore[] = "\e8";
int ret, params[2];
if (!(cdev->f_active & CONSOLE_STDIN))
@@ -88,6 +89,9 @@ int term_cdev_get_size(struct console_device *cdev,
console_puts(cdev, esc);
ret = term_cdev_read_reply(cdev, params, 2, 'R');
+
+ console_puts(cdev, restore);
+
if (ret)
return ret;
@@ -113,8 +117,6 @@ int term_getsize(int *screenwidth, int *screenheight)
found = true;
}
- term_setpos(0, 0);
-
if (!found)
return -ENOENT;
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 6/9] console: add get_size callback for direct size reporting
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (4 preceding siblings ...)
2026-05-01 6:53 ` [PATCH 5/9] lib: term: fix term_getsize cursor restore Ahmad Fatoum
@ 2026-05-01 6:54 ` Ahmad Fatoum
2026-05-01 6:54 ` [PATCH 7/9] video: fbconsole: implement get_size Ahmad Fatoum
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:54 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Add an optional get_size callback to struct console_device that allows
consoles to report their dimensions directly without requiring escape
sequence queries.
Update term_getsize() to try get_size first for consoles that implement
it. These consoles only need CONSOLE_STDOUT to participate in size
detection. Consoles without get_size still require both CONSOLE_STDIN
and CONSOLE_STDOUT for the escape sequence query path.
This enables output-only consoles like fbconsole to report their size
to commands like edit and watch.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
include/console.h | 1 +
lib/term.c | 8 ++++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/include/console.h b/include/console.h
index 1dfaa66d9266..f2b8da1546ef 100644
--- a/include/console.h
+++ b/include/console.h
@@ -43,6 +43,7 @@ struct console_device {
int (*set_mode)(struct console_device *cdev, enum console_mode mode);
int (*open)(struct console_device *cdev);
int (*close)(struct console_device *cdev);
+ int (*get_size)(struct console_device *cdev, int *width, int *height);
const char *devname;
int devid;
diff --git a/lib/term.c b/lib/term.c
index 0a656d79e725..382250c70ddf 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -79,11 +79,15 @@ int term_cdev_get_size(struct console_device *cdev,
const char restore[] = "\e8";
int ret, params[2];
- if (!(cdev->f_active & CONSOLE_STDIN))
- return -ENOENT;
if (!(cdev->f_active & CONSOLE_STDOUT))
return -ENOENT;
+ if (cdev->get_size)
+ return cdev->get_size(cdev, screenwidth, screenheight);
+
+ if (!(cdev->f_active & CONSOLE_STDIN))
+ return -ENOENT;
+
term_cdev_drain(cdev);
console_puts(cdev, esc);
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 7/9] video: fbconsole: implement get_size
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (5 preceding siblings ...)
2026-05-01 6:54 ` [PATCH 6/9] console: add get_size callback for direct size reporting Ahmad Fatoum
@ 2026-05-01 6:54 ` Ahmad Fatoum
2026-05-01 6:54 ` [PATCH 8/9] console: add per-console terminal.size parameter Ahmad Fatoum
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:54 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The fbconsole does not support input and doesn't emulate the control
characters for querying size. The get_size callback allows such consoles
to report their size anyway, so implement it.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
drivers/video/fbconsole.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index fd220a6c1e05..9fde6cc9c6d7 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -88,6 +88,15 @@ static int fbc_tstc(struct console_device *cdev)
return 0;
}
+static int fbc_get_size(struct console_device *cdev, int *width, int *height)
+{
+ struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev);
+
+ *width = priv->cols;
+ *height = priv->rows;
+ return 0;
+}
+
static void cls(struct fbc_priv *priv)
{
void *buf = gui_screen_render_buffer(priv->sc);
@@ -842,6 +851,7 @@ int register_fbconsole(struct fb_info *fb)
cdev->tstc = fbc_tstc;
cdev->putc = fbc_putc;
cdev->getc = fbc_getc;
+ cdev->get_size = fbc_get_size;
cdev->devname = basprintf("fbconsole%s", fbname);
cdev->devid = DEVICE_ID_SINGLE;
cdev->open = fbc_open;
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 8/9] console: add per-console terminal.size parameter
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (6 preceding siblings ...)
2026-05-01 6:54 ` [PATCH 7/9] video: fbconsole: implement get_size Ahmad Fatoum
@ 2026-05-01 6:54 ` Ahmad Fatoum
2026-05-01 7:19 ` [PATCH 9/9] efi: reimplement query_console_serial using term_getsize Ahmad Fatoum
2026-05-07 10:38 ` [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 6:54 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Expose a read-only "size" device parameter on every registered console.
Reading it queries the console dimensions via term_cdev_get_size() and
returns a WxH string (e.g. "80x25").
For consoles that will implement the get_size callback like fbconsole,
the size is read directly. For consoles with both stdin and stdout
active the size is probed using ANSI escape sequences. Consoles that
are output-only or cannot be queried return an error.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
common/console.c | 18 ++++++++++++++++++
include/console.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/common/console.c b/common/console.c
index 8b6824b85e43..6b484b67bc45 100644
--- a/common/console.c
+++ b/common/console.c
@@ -10,6 +10,7 @@
#include <malloc.h>
#include <param.h>
#include <console.h>
+#include <term.h>
#include <driver.h>
#include <fs.h>
#include <of.h>
@@ -216,6 +217,20 @@ static int console_baudrate_set(struct param_d *param, void *priv)
return console_set_baudrate(cdev, cdev->baudrate_param);
}
+static int console_size_get(struct param_d *param, void *priv)
+{
+ struct console_device *cdev = priv;
+ int rows = 0, cols = 0;
+
+ /* Parameter will just report 0x0 on errors) */
+ (void)term_cdev_get_size(cdev, &cols, &rows);
+
+ free(cdev->term_size);
+ cdev->term_size = xasprintf("%ux%u", cols, rows);
+
+ return 0;
+}
+
static void console_init_early(void)
{
kfifo_init(console_input_fifo, console_input_buffer,
@@ -391,6 +406,9 @@ int console_register(struct console_device *newcdev)
dev_add_param_string(dev, "active", console_active_set, console_active_get,
&newcdev->active_string, newcdev);
+ dev_add_param_string(dev, "terminal.size", NULL, console_size_get,
+ &newcdev->term_size, newcdev);
+
if (IS_ENABLED(CONFIG_CONSOLE_ACTIVATE_FIRST)) {
if (list_empty(&console_list))
activate = CONSOLE_STDIOE;
diff --git a/include/console.h b/include/console.h
index f2b8da1546ef..cfd2480f30d3 100644
--- a/include/console.h
+++ b/include/console.h
@@ -58,6 +58,8 @@ struct console_device {
unsigned int baudrate;
unsigned int baudrate_param;
+ char *term_size;
+
const char *linux_console_name;
const char *linux_earlycon_name;
void __iomem *phys_base;
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 9/9] efi: reimplement query_console_serial using term_getsize
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (7 preceding siblings ...)
2026-05-01 6:54 ` [PATCH 8/9] console: add per-console terminal.size parameter Ahmad Fatoum
@ 2026-05-01 7:19 ` Ahmad Fatoum
2026-05-07 10:38 ` [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01 7:19 UTC (permalink / raw)
To: barebox
query_console_serial() used printf() to send terminal size query
escape sequences, which go to _all_ active consoles. This corrupted
the fbconsole cursor position because fbconsole receives the
ESC [999;999H sequence and moves its cursor to the bottom-right
corner.
Replace the custom implementation with term_getsize() from lib/term.c,
which calculates the minimum terminal size across all consoles,
including the framebuffer console.
Link: https://fosstodon.org/@otte_homan@theblower.au/116229733790452489
Reported-by: @otte_homan@theblower.au
Fixes: 65ac28276e5d ("efi: loader: protocol: add console support")
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
efi/loader/protocols/console.c | 119 +--------------------------------
1 file changed, 2 insertions(+), 117 deletions(-)
diff --git a/efi/loader/protocols/console.c b/efi/loader/protocols/console.c
index 211e725cfd7b..113443db09d6 100644
--- a/efi/loader/protocols/console.c
+++ b/efi/loader/protocols/console.c
@@ -20,6 +20,7 @@
#include <efi/protocol/text.h>
#include <efi/error.h>
#include <efi/guid.h>
+#include <term.h>
#ifdef DEBUG
#include <efi/loader/trace.h>
@@ -83,76 +84,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 = get_time_ns();
-
- while (!tstc())
- if (is_timeout(timeout, 100 * MSECOND))
- 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
*
@@ -270,58 +201,12 @@ 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;
-}
-
static void efi_setup_console_size(void)
{
int rows = 25, cols = 80;
int ret = -ENODEV;
- ret = query_console_serial(&rows, &cols);
+ ret = term_getsize(&cols, &rows);
if (ret)
return;
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization
2026-05-01 6:53 [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization Ahmad Fatoum
` (8 preceding siblings ...)
2026-05-01 7:19 ` [PATCH 9/9] efi: reimplement query_console_serial using term_getsize Ahmad Fatoum
@ 2026-05-07 10:38 ` Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2026-05-07 10:38 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Fri, 01 May 2026 08:53:54 +0200, Ahmad Fatoum wrote:
> term_getsize() was added as a common helper to compute the minimum
> terminal size across all enabled stdout consoles.
>
> Since then, the EFI loader support added the same functionality again in
> open-coded form.
>
> Both suffer from the same underlying issue: They emit some control
> characters on all enabled stdout consoles without the regard for the
> individual size and capabilities of the terminals they are connected to.
>
> [...]
Applied, thanks!
[1/9] lib: term: avoid printing NUL with new new console_puts API
https://git.pengutronix.de/cgit/barebox/commit/?id=7f61a6fb7991 (link may not be stable)
[2/9] lib: term: return error code from term_getsize()
https://git.pengutronix.de/cgit/barebox/commit/?id=a81f585e824e (link may not be stable)
[3/9] lib: term: add per-console terminal response parser
https://git.pengutronix.de/cgit/barebox/commit/?id=920132df3126 (link may not be stable)
[4/9] lib: term: factor out single cdev handling from term_getsize
https://git.pengutronix.de/cgit/barebox/commit/?id=ea6ccaf8059d (link may not be stable)
[5/9] lib: term: fix term_getsize cursor restore
https://git.pengutronix.de/cgit/barebox/commit/?id=6be1d3436997 (link may not be stable)
[6/9] console: add get_size callback for direct size reporting
https://git.pengutronix.de/cgit/barebox/commit/?id=4cd56f6eb2da (link may not be stable)
[7/9] video: fbconsole: implement get_size
https://git.pengutronix.de/cgit/barebox/commit/?id=96362db024f8 (link may not be stable)
[8/9] console: add per-console terminal.size parameter
https://git.pengutronix.de/cgit/barebox/commit/?id=d88b030c564f (link may not be stable)
[9/9] efi: reimplement query_console_serial using term_getsize
https://git.pengutronix.de/cgit/barebox/commit/?id=ea66f5fe5ede (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 11+ messages in thread