mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/9] lib: term: fix fbconsole cursor desynchronization
@ 2026-05-01  6:53 Ahmad Fatoum
  2026-05-01  6:53 ` [PATCH 1/9] lib: term: avoid printing NUL with new new console_puts API Ahmad Fatoum
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Ahmad Fatoum @ 2026-05-01  6:53 UTC (permalink / raw)
  To: barebox

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.

This can lead to the cursor to end up at odd places on some consoles,
but not others as can be seen here on this video of the barebox
framebuffer console on a device without a terminal connected to the
serial port:

https://fosstodon.org/@otte_homan@theblower.au/116229733790452489

The <blue>OTICE</blue> is due to the framebuffer console cursor being
placed at the very end of the previous line. Then N is printed and
the rest at the line after it.

This series fixes term_getsize() to correctly account for differences
between the framebuffer and "regular" consoles and then switches off the
UEFI loader console support to make use of it.

This fixes the display of the OpenBSD bootloader when run under QEMU.

There's still some more improvements to be made to the GOP support, but
they do not preclude actual use: To have the OpenBSD installer
automatically use the console, simple-framebuffer ought to be used
instead of the GOP anyway.

Ahmad Fatoum (9):
  lib: term: avoid printing NUL with new new console_puts API
  lib: term: return error code from term_getsize()
  lib: term: add per-console terminal response parser
  lib: term: factor out single cdev handling from term_getsize
  lib: term: fix term_getsize cursor restore
  console: add get_size callback for direct size reporting
  video: fbconsole: implement get_size
  console: add per-console terminal.size parameter
  efi: reimplement query_console_serial using term_getsize

 common/console.c               |  18 ++++
 drivers/video/fbconsole.c      |  10 +++
 efi/loader/protocols/console.c | 119 +------------------------
 include/console.h              |   3 +
 include/term.h                 |   7 +-
 lib/term.c                     | 158 +++++++++++++++++++++++----------
 6 files changed, 148 insertions(+), 167 deletions(-)

-- 
2.47.3




^ permalink raw reply	[flat|nested] 11+ messages in thread

* [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

end of thread, other threads:[~2026-05-07 10:40 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 3/9] lib: term: add per-console terminal response parser Ahmad Fatoum
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 ` [PATCH 5/9] lib: term: fix term_getsize cursor restore Ahmad Fatoum
2026-05-01  6:54 ` [PATCH 6/9] console: add get_size callback for direct size reporting Ahmad Fatoum
2026-05-01  6:54 ` [PATCH 7/9] video: fbconsole: implement get_size Ahmad Fatoum
2026-05-01  6:54 ` [PATCH 8/9] console: add per-console terminal.size parameter 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox