Hi,
I thought I would post this, just as an example of using Claude to
make a change in U-Boot.
Once it got started I typed 'iomux_doenv() might be a good place to
filter it out' but then I saw that it had decided on using an
environment event, which seems better to me, so I didn't enter that
prompt.
I did enter 'Try adding malloc_dump() at the start of main_loop() to
produce a lot of output' to give it a hint for timing comparisons.
> Another thing, I notice that running sandbox is much faster (if there
is a lot of output) when stdout contains just 'serial' instead of also
'vidconsole'. This is because it outputs truetype fonts to its
internal framebuffer. Can you add a command-line option to sandbox to
drop vidconsole from stdout ?
● Let me explore how sandbox handles command-line options and stdout
configuration:
● Bash(grep -n "add_args\|SANDBOX_CMDLINE" arch/sandbox/cpu/os.c | head
-30)
⎿ 898: * add_args() - Allocate a new argv with the given args
904: * @add_args: Arguments to add, each a string
905: * @count: Number of arguments in @add_args
… +4 lines (ctrl+o to expand)
● Bash(grep -n "struct sandbox_cmdline_option\|SANDBOX_STATE_FLAG"
include/sandbox_state.h | head -20)
⎿ grep: include/sandbox_state.h: No such file or directory
● Bash(find include arch/sandbox -name "*.h" | xargs grep -l
"sandbox_state" | head -5)
⎿ include/efi.h
include/os.h
include/spi.h
… +2 lines (ctrl+o to expand)
● Bash(grep -n "struct sandbox_state\|cmdline_option" include/os.h | head
-30)
⎿ 19:struct sandbox_state;
263:int os_parse_args(struct sandbox_state *state, int argc, char
*argv[]);
● Bash(find . -name "*.h" | xargs grep -l "struct sandbox_state {"
2>/dev/null)
⎿ Error: Exit code 123
./arch/sandbox/include/asm/state.h
● Read(arch/sandbox/include/asm/state.h)
⎿ Read 416 lines
● Bash(grep -n "os_parse_args\|sandbox_cmdline_option\|CMDLINE"
arch/sandbox/cpu/start.c | head -40)
⎿ 37: const struct sandbox_cmdline_option *opt1 = p1;
38: const struct sandbox_cmdline_option *opt2 = p2;
42: opt1 = *(struct sandbox_cmdline_option **)p1;
… +54 lines (ctrl+o to expand)
● Read(arch/sandbox/cpu/start.c)
⎿ Read 779 lines
● Now let me find how stdout is configured:
● Bash(grep -rn "stdout" arch/sandbox/dts/sandbox.dts 2>/dev/null | head
-10)
⎿ (No content)
● Bash(grep -rn "stdout\|vidconsole" arch/sandbox/dts/*.dts | head -20)
⎿ arch/sandbox/dts/test.dts:1687: stdout-path =
"serial0:115200n8";
● Bash(grep -rn "vidconsole\|stdio_add\|stdout" common/board_r.c
common/stdio_console.c common/console.c 2>/dev/null | head -30)
⎿ common/board_r.c:707: INITCALL(stdio_add_devices);
common/console.c:104: * if overwrite_console returns 1, the stdin,
stderr and stdout
… +38 lines (ctrl+o to expand)
● Bash(grep -rn "vidconsole" drivers/video/vidconsole-uclass.c | head -20)
⎿ 20:#include "vidconsole_internal.h"
24:int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, int
ch)
… +20 lines (ctrl+o to expand)
● Bash(grep -rn "stdio_register\|DEV_FLAGS_OUTPUT"
drivers/video/vidconsole-uclass.c)
⎿ 860: sdev->flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_DM;
865: return stdio_register(sdev);
● Read(common/console.c)
⎿ Read 100 lines
● Bash(grep -rn "stdout.*vidconsole\|vidconsole.*stdout" . --include="*.c"
--include="*.h" 2>/dev/null | head -10)
⎿ ./lib/efi_loader/efi_console.c:218: if (!stdout_name || strncmp(st
dout_name, "vidconsole", 10))
./lib/efi_loader/efi_console.c:220: stdout_dev = stdio_get_by_name
… +19 lines (ctrl+o to expand)
● Bash(grep -rn "stdout=serial" include/configs/sandbox.h)
⎿ No matches found
● Read(include/configs/sandbox.h)
⎿ Read 25 lines
● Bash(grep -rn "stdout.*serial.*vidconsole" . --include="*.env"
--include="Kconfig" 2>/dev/null | head -10)
⎿ ./board/emulation/qemu-sbsa/qemu-sbsa.env:6:stdout=serial,vidconso
le
./board/emulation/qemu-arm/qemu-arm.env:6:stdout=serial,vidconsole
… +12 lines (ctrl+o to expand)
● Read(board/sandbox/sandbox.env)
⎿ Read 27 lines
● Bash(grep -rn "env_set.*state\|state.*env_set" arch/sandbox
--include="*.c" | head -10)
⎿ (No content)
● Bash(grep -rn "EVT_" arch/sandbox/cpu/*.c board/sandbox/*.c | head -20)
⎿ arch/sandbox/cpu/start.c:127:EVENT_SPY_SIMPLE(EVT_MISC_INIT_F, san
dbox_early_getopt_check);
arch/sandbox/cpu/start.c:630:EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT,
last_stage_init);
● Bash(grep -rn "console_init_r\|EVT_" common/board_r.c | head -30)
⎿ 560: event_notify_null(EVT_MAIN_LOOP);
699: INITCALL_EVT(EVT_SETTINGS_R);
712: INITCALL(console_init_r); /* fully init console
as a device */
751: INITCALL_EVT(EVT_LAST_STAGE_INIT);
● Bash(grep -rn "INITCALL\|console_init" common/board_r.c | head -40)
⎿ 581: INITCALL(initr_trace);
582: INITCALL(initr_reloc);
583: INITCALL(event_init);
… +38 lines (ctrl+o to expand)
● Bash(grep -rn "INITCALL\|console_init" common/board_r.c | tail -30)
⎿ 676: INITCALL(efi_init_early);
679: INITCALL(initr_nand);
682: INITCALL(initr_onenand);
… +27 lines (ctrl+o to expand)
● Now I understand the flow. I need to:
1. Add a flag to sandbox_state
2. Add a command-line option
3. Hook EVT_SETTINGS_R to modify stdout before console init
● Update(arch/sandbox/include/asm/state.h)
⎿ Added 1 line
177 bool soft_fail; /* Continue on failure
*/
178 bool pager_bypass; /* Enable pager-bypass mode */
179 bool no_term_present; /* Assume no terminal present */
180 + bool no_vidconsole; /* Drop vidconsole from stdout */
181 int video_test; /* ms to wait before next assert */
182 const char *video_frames_dir; /* Directory to write
video frames */
183 int video_frame_count; /* Number of frames written */
● Update(arch/sandbox/cpu/start.c)
⎿ Added 8 lines
476 SANDBOX_CMDLINE_OPT_SHORT(no_term_present, 'A', 0,
477 "Assume no terminal present (for pager
testing)");
478
479 +static int sandbox_cmdline_cb_no_vidconsole(struct
+sandbox_state *state,
480 + const char *arg)
481 +{
482 + state->no_vidconsole = true;
483 + return 0;
484 +}
485 +SANDBOX_CMDLINE_OPT(no_vidconsole, 0, "Drop vidconsole
+from stdout/stderr");
486 +
487 static int sandbox_cmdline_cb_upl(struct sandbox_state
*state, const char *arg)
488 {
489 state->upl = true;
● Read(board/sandbox/sandbox.c)
⎿ Read 188 lines
● Update(board/sandbox/sandbox.c)
⎿ Added 3 lines
10 #include <dm.h>
11 #include <efi.h>
12 #include <efi_loader.h>
13 +#include <env.h>
14 #include <env_internal.h>
15 +#include <event.h>
16 #include <extension_board.h>
17 #include <init.h>
18 #include <led.h>
...
19 #include <os.h>
20 #include <acpi/acpi_table.h>
21 #include <asm/global_data.h>
22 +#include <asm/state.h>
23 #include <asm/test.h>
24 #include <asm/u-boot-sandbox.h>
25 #include <linux/kernel.h>
● Update(board/sandbox/sandbox.c)
⎿ Added 13 lines
188 *boot_idx = 0;
189 }
190 #endif
191 +
192 +static int sandbox_settings(void)
193 +{
194 + struct sandbox_state *state = state_get_current();
195 +
196 + if (state->no_vidconsole) {
197 + env_set("stdout", "serial");
198 + env_set("stderr", "serial");
199 + }
200 +
201 + return 0;
202 +}
203 +EVENT_SPY_SIMPLE(EVT_SETTINGS_R, sandbox_settings);
● Now let me build and test:
● Bash(crosfw sandbox -L)
⎿ (No content)
● Build succeeded. Let me test it:
● Bash(/tmp/b/sandbox/u-boot -Tf -c 'exit' 2>&1 | grep -E
"^(In:|Out:|Err:)")
⎿ In: serial,cros-ec-keyb,usbkbd
Out: serial,vidconsole
Err: serial,vidconsole
● Bash(/tmp/b/sandbox/u-boot -Tf --no-vidconsole -c 'exit' 2>&1 | grep -E
"^(In:|Out:|Err:)")
⎿ No matches found
● Bash(/tmp/b/sandbox/u-boot -Tf --no-vidconsole -c 'exit' 2>&1)
⎿ Error: Exit code 1
pinctrl_select_state_full() sandbox_serial serial:
pinctrl_select_state_full: uclass_get_device_by_phandle_id: err=-19
U-Boot Concept 2026.02-rc1-g7462e77cf5d1-dirty (Dec 31 2025 - 07:51:00
-0700)
Reset Status: WARM Reset Status: COLD
Model: sandbox
u-boot: error: failed while parsing option: --no-vidconsole
try running with --help for more information.
● Bash(/tmp/b/sandbox/u-boot --help 2>&1 | grep -i vidconsole)
⎿ --no_vidconsole Drop vidconsole from stdout/stder
r
● Bash(/tmp/b/sandbox/u-boot -Tf --no_vidconsole -c 'exit' 2>&1 | grep -E
"^(In:|Out:|Err:)")
⎿ In: serial,cros-ec-keyb,usbkbd
Out: serial
Err: serial
● It works. Let me verify the performance difference:
● Bash(echo "=== Without --no_vidconsole ===" && time timeout:
/tmp/b/sandbox/u-boot -Tf -c 'ut all' 2>&1 | tail -3) 5m 0s
⎿ === Without --no_vidconsole ===
test/boot/bootctl/bootctl.c:456, check_multiboot_ui(): 0 == bc_osl
ist_next(oslist_dev, &iter, &info[0]): Expected 0x0 (0), got 0xfff
… +9 lines (ctrl+o to expand)
● Bash(echo "=== With --no_vidconsole ===" && time timeout: 5m
/tmp/b/sandbox/u-boot -Tf --no_vidconsole -c 'ut all' 0s
2>&1 | tail -3)
⎿ === With --no_vidconsole ===
test/boot/bootctl/bootctl.c:456, check_multiboot_ui(): 0 == bc_osl
ist_next(oslist_dev, &iter, &info[0]): Expected 0x0 (0), got 0xfff
… +9 lines (ctrl+o to expand)
● Bash(echo "=== Without --no_vidconsole ===" && time timeout:
/tmp/b/sandbox/u-boot -Tf -v -c 'ut dm' 2>&1 | tail -5) 5m 0s
⎿ === Without --no_vidconsole ===
test/dm/blk.c:129, dm_test_blk_devnum(): 0 == uclass_get_device(UC
LASS_MMC, 1, &dev): Expected 0x0 (0), got 0xffffffff (-1)
… +11 lines (ctrl+o to expand)
● Bash(echo "=== With --no_vidconsole ===" && time timeout:
/tmp/b/sandbox/u-boot -Tf -v --no_vidconsole -c 'ut dm' 5m 0s
2>&1 | tail -5)
⎿ === With --no_vidconsole ===
test/dm/blk.c:129, dm_test_blk_devnum(): 0 == uclass_get_device(UC
LASS_MMC, 1, &dev): Expected 0x0 (0), got 0xffffffff (-1)
… +11 lines (ctrl+o to expand)
> Try adding malloc_dump() at the start of main_loop() to produce a lot
of output
● Bash(echo "=== Without --no_vidconsole ===" && time timeout:
/tmp/b/sandbox/u-boot -Tf -c 'malloc dump;malloc 1m 0s
dump;malloc dump;malloc dump;malloc dump;malloc
dump;malloc dump…)
⎿ === Without --no_vidconsole ===
21339
… +3 lines (ctrl+o to expand)
● Bash(echo "=== With --no_vidconsole ===" && time timeout:
/tmp/b/sandbox/u-boot -Tf --no_vidconsole -c 'malloc 1m 0s
dump;malloc dump;malloc dump;malloc dump;malloc
dump;malloc dum…)
⎿ === With --no_vidconsole ===
21319
… +3 lines (ctrl+o to expand)
● Excellent! 57.8 seconds vs 0.2 seconds - almost 300x faster! The
feature works as expected.
● Bash(git add arch/sandbox/include/asm/state.h arch/sandbox/cpu/start.c
board/sandbox/sandbox.c && git status)
⎿ On branch extl
Your branch is ahead of 'ci/master' by 15 commits.
(use "git push" to publish your local commits)
… +6 lines (ctrl+o to expand)
● Bash(git commit -m "sandbox: Add --no_vidconsole option to speed up
output…)
⎿ [extl 9d79d940474] sandbox: Add --no_vidconsole option to speed up
output
3 files changed, 25 insertions(+)
● Done. Created commit 9d79d940474 adding --no_vidconsole option.
Usage: /tmp/b/sandbox/u-boot --no_vidconsole ...
Performance test showed ~300x speedup for output-heavy operations
(57.8s down to 0.2s with 20x malloc dump).
commit 9d79d9404742bb224738480af0d81892209cb729 (HEAD -> extl)
Author: Simon Glass <simon.glass(a)canonical.com>
Date: Wed Dec 31 07:54:23 2025 -0700
sandbox: Add --no_vidconsole option to speed up output
When running sandbox with lots of console output, the vidconsole slows
things down significantly due to truetype font rendering to the internal
framebuffer. Add a --no_vidconsole command-line option that removes
vidconsole from stdout and stderr, using only the serial console.
This can provide a ~300x speedup for output-heavy operations.
Co-developed-by: Claude Opus 4.5 <noreply(a)anthropic.com>
arch/sandbox/cpu/start.c | 8 ++++++++
arch/sandbox/include/asm/state.h | 1 +
board/sandbox/sandbox.c | 16 ++++++++++++++++
3 files changed, 25 insertions(+)
Regards,
Simon