Dumping expo contents

Expo is U-Boot’s forms and UI subsystem. It supports text, images and menus and a large expo can contain quite a bit of information. How do you debug and understand that? Tracing through large, linked data structures is not fun.

U-Boot Concept now has an expo_dump() function, designed to be called from your code when you are trying to figure out what is happening. It writes a dump of the expo to an abuf, something like the following:

Expo: name 'my menus'
  display lcd
  cons lcd.vidconsole_tt
  mouse (none)
  scene_id 0
  next_id 46
  req_width 0
  req_height 0
  text_mode 0
  popup 0
  show_highlight 0
  mouse_enabled 0
  mouse_ptr 0000000000000000
  mouse_size 0x0
  mouse_pos (0,0)
  damage (0,0)-(0,0)
  done 0
  save 0
  last_key_ms 4526828813
  video: 1366x768 white_on_black 0
  Theme:
    font_size 0
    white_on_black 0
    menu_inset 0
    menuitem_gap_y 0

Scenes:
  Scene 7: name 'main'
    title_id 0 ((none))
    highlight_id 0 ((none))
    Object 9 (logo): type image
      flags dirty
      bbox: (50,20)-(210,180)
      dims: 160x160
      Image: data ff000000
    Object 10 (text): type text
      flags dirty
      bbox: (400,100)-(526,140)
      dims: 126x40
      Text: str_id 20 font_name 'cantoraone_regular' font_size 40
        str 'my string'
    Object 11 (text): type text
      flags dirty
      bbox: (200,600)-(496,660)
      dims: 296x60
      Text: str_id 21 font_name 'nimbus_sans_l_regular' font_size 60
        str 'another string'
    Object 12 (text): type text
      flags size_valid, dirty
      bbox: (500,200)-(1000,350)
      dims: 477x240
      Text: str_id 22 font_name 'nimbus_sans_l_regular' font_size 60
        str 'this is yet
another string, with word-wrap and it goes on for quite a while'
    Object 13 (main): type menu
      flags size_valid, dirty
      bbox: (50,400)-(210,560)
      dims: 160x160
      Menu: pointer_id 45 title_id 14 manual 0
        Item 35: name 'item1' label_id 36 desc_id 37
        Item 40: name 'item2' label_id 41 desc_id 42
    Object 14 (title): type text
      flags dirty
      bbox: (50,400)-(122,418)
      dims: 72x18
      Text: str_id 24 font_name '(default)' font_size 0
        str 'Main Menu'
    Object 45 (cur_item): type text
      flags dirty
      bbox: (147,436)-(156,454)
      dims: 9x18
      Text: str_id 25 font_name '(default)' font_size 0
        str '>'
    Object 36 (label1): type text
      flags dirty
      bbox: (50,436)-(79,454)
      dims: 28x18
      Text: str_id 26 font_name '(default)' font_size 0
        str 'Play'
    Object 37 (item1-txt): type text
      flags dirty
      bbox: (227,436)-(316,454)
      dims: 89x18
      Text: str_id 27 font_name '(default)' font_size 0
        str 'Lord Melchett'
    Object 38 (item1-key): type text
      flags dirty
      bbox: (177,436)-(186,454)
      dims: 9x18
      Text: str_id 28 font_name '(default)' font_size 0
        str '1'
    Object 41 (label2): type text
      flags dirty
      bbox: (50,454)-(79,472)
      dims: 29x18
      Text: str_id 30 font_name '(default)' font_size 0
        str 'Now'
    Object 42 (item2-txt): type text
      flags dirty
      bbox: (227,454)-(316,472)
      dims: 70x18
      Text: str_id 31 font_name '(default)' font_size 0
        str 'Lord Percy'
    Object 43 (item2-key): type text
      flags dirty
      bbox: (177,454)-(186,472)
      dims: 9x18
      Text: str_id 32 font_name '(default)' font_size 0
        str '2'
    Object 15 (box): type box
      flags size_valid, dirty
      bbox: (500,200)-(1000,350)
      dims: 160x0
      Box: fill 0 width 3
    Object 16 (box2): type box
      flags 
      bbox: (0,0)-(0,0)
      dims: 160x0
      Box: fill 0 width 1
    Object 17 (editor): type textedit
      flags size_valid, dirty
      bbox: (100,200)-(400,650)
      dims: 289x54
      Textedit: str_id 23 font_name '(default)' font_size 0
    Object 18 (overlap): type text
      flags dirty
      bbox: (405,105)-(480,123)
      dims: 75x18
      Text: str_id 34 font_name '(default)' font_size 0
        str 'overlap text'

To print it, use puts() which has no line limits and will just dump the entire block to the console.

One nice thing about this dump is that you can compare it with a desired expo state.

What’s next? It would be nice to be able to move the mouse around and get information about the objects underneath the mouse. Another useful feature would be to write the dump to a file.

For now, it’s a start. Give it a try!




Dealing with test images

Testing boot scenarios in very important but there are quite a lot of them! Concept currently has about 13 images containing various partitions and files used by the bootstd tests. These are listed in test.dts, for example:

	aliases {
...
		mmc7 = "/mmc7";
		mmc8 = "/mmc8";
...
	};

	/* This is used for Android boot image v4 tests */
	mmc7 {
		status = "disabled";
		compatible = "sandbox,mmc";
		filename = "mmc7.img";
	};

	/* This is used for Android boot image v2 tests. */
	mmc8 {
		status = "disabled";
		compatible = "sandbox,mmc";
		filename = "mmc8.img";
	};

All images are built by test_ut_dm_init_bootstd(), but most of these are disabled by default, to avoid making sandbox unwieldy and confusing. It also means that a test only has to worry about its particular disk image (plus a few common ones) and doesn’t have to be be updated every time a new test case is added in the code base.

But sometimes it is useful to enable a particular image. Tests do this individually, by enabling a devicetree node and then binding a device to it. But there is no way to do this from the command line. The only way is to edit test.dts to remove the status = "disabled" line for a node.

Until now. A very simple addition to sandbox allows an image to be enabled from the command line: the sb devon command. Simply specify the device name (e.g. mmc11) and it will set up a device. From then on the device appears as normal, so it can be used with the bootflow command, ls, etc.

When you have finished with the device sb devoff disables it again, putting things back to normal. Here is an example:

=> mmc list
mmc2: 2 (SD)
mmc1: 1 (SD)
mmc0: 0 (SD)
=> ls mmc b:1
** Bad device specification mmc b **
Couldn't find partition mmc b:1
=>
=> sb devon mmc11
Device 'mmc11' enabled
=> mmc list
mmc2: 2 (SD)
mmc1: 1 (SD)
mmc0: 0 (SD)
mmc11: 11 (SD)
=> ls mmc b:1    
            extlinux/
        7   initrd.img-6.8.0-53-generic
     1620   vmlinuz-6.8.0-53-generic

2 file(s), 1 dir(s)

=> sb devoff mmc11
Device 'mmc11' disabled
=> mmc list       
mmc2: 2 (SD)
mmc1: 1 (SD)
mmc0: 0 (SD)
=> 

Give it a try!




Mouse and Touchpad Support Added to Expo

U-Boot’s ‘expo’ toolkit is used for creating user interfaces, such as the configuration editor (cedit) and graphical boot menus (bootflow menu). Previously, user interaction with expo scenes was limited to the keyboard.

A recent 23-patch series introduces support for mouse and touchpad interaction.

New Input Handling

For devices where a mouse or touchpad is available, keyboard-only navigation can be inefficient. This update is intended to improve user interaction, particularly within complex screens like the configuration editor.

The core of this update is a new expo_send_click() function, which is designed to work similarly to the existing expo_send_key() function for processing user input.

The expo framework separates the processing of an event (like a click or keypress) from the handling of the resulting action. This series maintains that design, which allows expo to be integrated into different event loops. If a mouse is detected, expo will enable it by default.

Implementation Details

To enable mouse clicks, the framework required a method to determine which UI element exists at a specific (x, y) coordinate. This was implemented in several stages:

  1. Coordinate Checking: New functions, such as scene_menu_within() and scene_textline_within(), have been added. These check if a given coordinate is within the bounding box of a menu item or an editable text field.
  2. Scene-Level Clicks: The logic was then extended to the scene level, allowing a click to be routed to the correct object within the current scene. This includes handling for popup menus.
  3. Input Polling: The main expo_poll() function was updated to check for both keyboard and mouse events.

Additional Changes

The series also includes a few other updates:

  • Filled Boxes: The video API now supports drawing filled rectangles in addition to outlines.
  • New Fonts: The Ubuntu Light and Bold fonts have been added.
  • Testing: New tests for the mouse functionality have been added, including helpers to simulate clicks and verify the resulting actions.

This series expands U-Boot’s user interface capabilities by adding a new method for user input.




Bridging Worlds: Major Improvements to U-Boot’s EFI App and Device Tree Handling

The U-Boot EFI application is a powerful tool, allowing U-Boot to run on top of existing UEFI firmware. This is increasingly important as we see new platforms, especially in the ARM64 world, shipping with complex, ACPI-based firmware. A prime example is the recent wave of laptops powered by the Qualcomm X-Elite, which rely on this boot model.

However, booting a traditional, device-tree-based OS like ARM Linux from this environment presents a unique set of challenges. A recent comprehensive patch series lands with a host of fixes and new features designed to bridge the gap between the EFI world and the device tree world, dramatically improving the experience and reliability of the U-Boot EFI app.

Let’s dive into what’s new.


The Core Challenge: Memory Map Misalignment

When Linux boots using a device tree, it trusts the /reserved-memory nodes in the FDT to know which memory regions to avoid. But when running as an EFI application, the underlying UEFI firmware has its own, separate memory map with regions reserved for runtime services, ACPI data, and other critical functions.

If U-Boot doesn’t transfer this information into the device tree, Linux has no idea these regions are off-limits. It might try to use them, leading to mysterious crashes and instability.

The Solution: Automatic Memory Map Synchronization

Enter a new mechanism to synchronize these two views of memory. A new command, efi memsync, has been introduced.

This command:

  1. Reads the memory map provided by the EFI boot services.
  2. Parses the existing /reserved-memory nodes in U-Boot’s working device tree.
  3. Compares the two, identifying any reserved regions from EFI that are missing in the device tree.
  4. Automatically creates new no-map reserved-memory nodes in the device tree for these missing regions.

This process is now automatically run during the boot flow when using the EFI app, ensuring that the device tree passed to Linux is a complete and accurate representation of the hardware’s memory layout.

=> efi memsync -v
Comparing EFI memory-map with reserved-memory
EFI Memory Map Analysis:
ID   Type                  Start              End                In DT?
------------------------------------------------------------------------
0    EFI_RUNTIME_SERVICES_CODE 0x001f9ef000       0x001faef000       no -> adding
1    EFI_ACPI_RECLAIM_MEMORY   0x001fb6f000       0x001fb7f000       no -> adding
2    EFI_ACPI_MEMORY_NVS       0x001fb7f000       0x001fbff000       yes
Regions added: 2

New command: fdt reserved

To complement efi memsync, you can now easily inspect the result with the fdt reserved command. It provides a clean, readable list of all regions in the /reserved-memory node.

=> fdt reserved
ID   Name                 Start            Size
----------------------------------------------------------------
0    secmon@1f000000      0x1f000000         0x1000000
1    efi-runtime@1f9ef000 0x1f9ef000         0x100000

Stability and Polish

Beyond the major new features, this series includes critical fixes that make the EFI app more robust and stable:

  • Correct Device Naming: A subtle bug was fixed where block devices were being named based on a temporary placeholder, leading to confusing device names. Names are now set correctly before the device is bound.
  • ARM64 Exception Level Handling: The app now correctly avoids trying to change CPU exception levels, which it is not permitted to do, preventing crashes on ARM platforms.
  • Graceful Exit: The app no longer tries to free its own memory right before exiting, which could cause a crash. It now relies on the underlying UEFI firmware to clean up resources.
  • Simple Framebuffer: For a better user experience, the app now automatically adds a simple-framebuffer node to the device tree, ensuring Linux has an early graphics console.

Conclusion

This is a small step forward for U-Boot’s capabilities as an EFI application. These changes are already proving essential for bringing up Linux on platforms like the Qualcomm X-Elite, showcasing U-Boot’s adaptability and continued importance in a complex and evolving boot ecosystem.




Concept mailing list and patch management

If you are interested in watching the development of U-Boot Concept, consider joining the mailing list. You can do this in your web browser here, or send an email with ‘subscribe’ in the subject to concept-join@u-boot.org. If you are able to review patches or contribute your own, please do!

Also the patchwork server is up and running so future patches will be visible there. This also helps to collect reviews, etc.

You may also find it interesting to look at the merge requests.

Development goals

With U-Boot Concept, the goal is to continue the transformation of the code base so that it remains relevant in future, even if only as fodder for new developments. Keys goals remaining for 2025 are:

  • Continue evolution of standard boot
  • Get the EFI app fully functional on x86 and ARM
  • Broaden the expo feature set a little, e.g. a text editor
  • Keep up with the development of the Flat Image Tree (FIT) specification
  • Create packages for QEMU and EFI (including versions more focussed on secure boot)
  • Take a look at what it would take to support Rust code
  • Build out the new filesystem and file uclasses (better Linux compatibility?)

Not all of these will get done, but we’ll see what happens!




Fixing a Devious Memory Corruption Bug in Sandbox

We’ve just merged a fix in Concept for a particularly tricky memory corruption bug in the U-Boot sandbox environment. This bug was difficult to track down, so we wanted to share the story of the investigation and the solution.

The Symptom: Mysterious Heap Corruption

The problem first appeared as random and hard-to-reproduce memory corruption in the malloc() heap. These are often the most frustrating bugs to solve, as the place where the program crashes is rarely the place where the error actually occurred. After many hours of debugging, the root cause was finally identified, and it was quite unexpected.


The Culprit: A Memory Map Collision đź’Ą

It turns out that the PCI Enhanced Allocation (EA) driver, a feature used for testing within sandbox, was mapping its simulated device memory at the 1MB physical address.

This might seem harmless, but there’s a problem. When using the vbe_abrec_os boot method in sandbox, the Linux kernel is also loaded and executed from that very same 1MB address.

The collision was triggered by a specific feature: measured boot. When enabled, the bootm_measure() command needs to read the kernel’s data to calculate its hash. To do this, it calls map_sysmem() on the kernel’s memory region at 1MB. However, because the PCI EA driver had claimed that address space, the call was “hijacked.” Instead of mapping and reading RAM where the kernel was supposed to be, U-Boot was unknowingly reading from the simulated PCI device!

This led to the measurement being performed on incorrect data and, through a complex chain of events, corrupted the heap, causing crashes later on.


The Fix: A Multi-Pronged Approach

The solution was implemented in a series of five patches that not only fix the bug but also add safeguards to prevent similar issues in the future.

1. Move the PCI Space

The core of the fix was to move the PCI EA test space out of the way. Patch 2/5 relocates it from 0x100000 (1MB) to a much safer address at 0x20000000, well clear of any system RAM used by sandbox. This resolves the memory collision entirely.

2. Make Partial Maps a Fatal Error

A key clue during debugging was this log message: map_physmem: Warning: partial map at 100000, wanted 4, got 2000

This warning indicated that a driver asked to map a certain number of bytes but the underlying device mapping had a different size. While this might sometimes be harmless, in this case, it was a giant red flag that something was wrong.

Patch 5/5 promotes this warning to a fatal error. It now prints a “Fatal: partial map…” message and calls os_abort(). This makes the system fail loudly and immediately, which is much better than silently continuing with a corrupted state. This change will make similar bugs far easier to spot in the future.

3. Clean up Mapping Sizes

With the new fatal error in place, we had to clean up a few drivers that were requesting inexact mapping sizes. Patches 3/5 and 4/5 update the ACPI PMC driver and the PCI EA tests to request the exact size of the memory they intend to map, silencing the new error and making the code more precise.

4. A Quick Logging Fix

Finally, patch 1/5 was a small but helpful cleanup, swapping the “wanted” and “got” values in the log message, which were reversed, to avoid any future confusion.

This was a great example of how a seemingly innocuous test configuration can have far-reaching and destructive consequences. By moving the test region and hardening our memory mapping code, the sandbox environment is now more robust. Happy hacking!




Making CI Work for You: New Controls for U-Boot’s GitLab Pipeline

Continuous Integration (CI) is the backbone of a large project like U-Boot, ensuring that every change is tested against a huge matrix of boards and configurations. While this comprehensive testing is vital for quality, it can also be time-consuming. When you’re focused on a specific feature, waiting for a full “world build” to complete can slow down your development cycle.

A little series of patches introduces several improvements to U-Boot’s GitLab CI, giving developers powerful new tools to get faster, more targeted feedback.


## A New Toolbox for CI Control

This series is all about empowering developers to tailor CI runs to their specific needs. Instead of a one-size-fits-all pipeline, you can now easily select which parts you want to run.

Stage-Level Control

You can now disable entire stages of the CI pipeline using simple variables. If your changes don’t affect the world build, you can just turn it off for your test push:

# Push to the 'ci' remote, disabling the world_build stage
$ git push ci -o ci.variable=WORLD_BUILD=0

Similar variables are available for the other main stages:

  • TEST_SUITES=0: Disables the collection of miscellaneous tests (pylint, docs, etc.).
  • TEST_PY=0: Disables all test.py jobs.

Granular test.py Selection

The test.py stage runs U-Boot on emulated hardware and is often the most critical part of the pipeline. The TEST_PY variable offers fine-grained control here. You can use it to run:

  • All tests for a single board: TEST_PY=sandbox
  • A single, specific test job: TEST_PY='sandbox with clang test.py'

This is incredibly useful when you’re working on a single board and want to avoid running tests for dozens of others.


Laser-Focused Testing with TEST_SPEC

For the ultimate level of precision, the new TEST_SPEC variable lets you pass a test specifier directly to pytest. This allows you to run a single test or a specific group of tests across all relevant jobs.

For example, if you’re working on the bootstd command, you can run only the bootstd tests in CI with:

# Run only tests with 'bootstd' in their name
$ git push ci -o ci.variable=TEST_SPEC=bootstd

This can reduce a test run from 30 minutes to just a few minutes, providing a rapid feedback loop for iterative development.


A Cleaner, More Consistent CI

Beyond adding new features, the series also includes cleanups that make the CI configuration more consistent and maintainable. Stage names like world build have been standardized to world_build, and redundant shell logic has been removed in favor of letting GitLab’s own rules: engine handle job execution.

These small changes improve the readability and reliability of the CI infrastructure, making life easier for both developers and maintainers. By giving developers more control over their CI runs, these updates promise to make the development process faster and more efficient.




Taming Build Complexity: Introducing Config Fragments in Buildman

As U-Boot’s support for hardware grows, so does the complexity of managing build configurations. A single board might require several build variations—for example, one with network support and one without, or a standard build versus one tailored for Android booting. Historically, managing these variations often meant duplicating large defconfig files, a maintenance headache waiting to happen.

A recent patch series, with contributions from Heinrich Schuchardt and Simon Glass, introduces a powerful and elegant solution to this problem by formally integrating configuration fragments into buildman, U-Boot’s indispensable build-testing tool.


What are Config Fragments?

A config fragment is a small, targeted file containing just a few Kconfig options. For instance, an acpi.config fragment might contain only one line:

CONFIG_ACPIGEN=y

Instead of creating a whole new qemu-riscv64_smode_acpi_defconfig, you can now apply this small fragment on top of the existing qemu-riscv64_smode_defconfig to generate a new build variant on the fly. This approach is cleaner, reduces duplication, and makes configurations easier to manage.

While the underlying Kconfig system has supported this for a while, buildman was unaware of this mechanism—until now.


Official buildman Support: Two New Approaches

The new series enhances buildman by providing two ways to work with fragments.

The Manual Approach: --fragments

For quick tests or one-off builds, buildman now has a --fragments command-line option. You can pass a comma-separated list of fragment files to apply to your build.

For example, to build qemu-riscv64_smode with ACPI support, you can now run:

tools/buildman/buildman -k qemu-riscv64_smode --fragments acpi.config

buildman handles the rest, correctly merging the fragment with the board’s base defconfig.


The Automated Build Matrix: --extend and .buildman

The real impact of this series lies in its ability to automate the discovery and building of these variations. This is achieved through a new file format and a new command-line flag.

A new file, configs/extended.buildman, now defines the relationships between boards and their valid fragments, creating what are called “extended boards.”

The syntax is simple and powerful. You can define a build variant and specify which boards it applies to using wildcards or by checking for specific CONFIG options in the base defconfig.

Here’s an example from the series that creates ACPI-enabled variants for all RISC-V QEMU boards:

# Build RISC-V QEMU builds with ACPI
name: acpi
fragment: acpi
targets:
  qemu-riscv*

To tell buildman to parse this file and build all the resulting extended boards, you simply add the -X (or --extend) flag to your command. buildman will then discover that acpi,qemu-riscv64_smode is a valid new target and add it to its build queue.


Continuous Integration for All Variants

This isn’t just a tool for local development. The final piece of this series integrates the -X flag directly into U-Boot’s GitLab CI. This means that these “extended board” configurations are now built and tested automatically as part of the “world build,” guaranteeing that build variations are treated as first-class citizens and don’t suffer from bit-rot. This last patch is pending, due to some last-minute issues.

By formalizing the concept of config fragments, this series makes the U-Boot build system more robust, easier to maintain, and better equipped to handle the diverse configurations required by the embedded ecosystem.




QEMU improvements

Since 2018 U-Boot has had a good selection of features for running on top of QEMU, including:

  • virtio using PCI devices (legacy and modern)
  • virtio using memory-mapped I/O
  • block devices, to support filesystems, etc. (virtio-blk)
  • network devices (virtio-net)
  • random-number device (virtio-rng)

Most of this was written by Bin Meng. It uses driver model and is nicely implemented.

What’s new?

More recently a few more features have been added:

  • SCSI devices, for more flexible discovery with multiple disks (virtio-scsi)
  • Filesystem devices, for access to host files (virtio-fs). See the separate post about this.
  • Visibility into the available virtio devices (virtio list)
  • Additions to the qfw command to improve visibility

The `virtio list` command can be useful for seeing what paravirtualised devices are available and whether U-Boot has a driver for them. Here you can see U-Boot running on an x86 host.

=> virtio scan
=> virtio list
Name                  Type            Driver
--------------------  --------------  ---------------
virtio-pci.m#0         5: balloon     (none)
virtio-pci.m#1         4: rng         virtio-rng#1
virtio-pci.m#2        12: input-host  (none)
virtio-pci.m#3        12: input-host  (none)
virtio-pci.m#4        13: vsock       (none)
virtio-pci.m#5         3: serial      (none)
virtio-pci.m#6         8: scsi        virtio-scsi#6
virtio-pci.m#7         9: 9p          (none)
virtio-pci.m#8        1a: fs          virtio-fs#8
virtio-pci.m#9        10: gpu         (none)
virtio-pci.m#10        1: net         virtio-net#a
=>

Here you can see how the random-number driver can be used:

=> random 1000 10
16 bytes filled with random data
=> md.b 1000 10
00001000: 00 3f e2 f8 a1 70 4e 5f 8c 19 19 ba 18 76 32 bc  .?...pN_.....v2.
=> 

SCSI is accessed by scanning it first. Note that standard boot does this automatically, if you are just booting an OS.

=> scsi scan
scanning bus for devices...
  Device 0: (0:1) Vendor: QEMU Prod.: QEMU HARDDISK Rev: 2.5+
            Type: Hard Disk
            Capacity: 10240.0 MB = 10.0 GB (20971520 x 512)
=> part list scsi 0

Partition Map for scsi device 0  --   Partition Type: EFI

Part	Start LBA	End LBA		Name
	Attributes
	Type GUID
	Partition GUID
  1	0x00200800	0x013fffde	""
	attrs:	0x0000000000000000
	type:	0fc63daf-8483-4772-8e79-3d69d8477de4
		(linux)
	guid:	e53def26-b3a7-4227-8175-b933282b824f
  e	0x00000800	0x000027ff	""
	attrs:	0x0000000000000000
	type:	21686148-6449-6e6f-744e-656564454649
		(21686148-6449-6e6f-744e-656564454649)
	guid:	a52718a3-62a4-483a-b8fa-38cefacad2fd
  f	0x00002800	0x000377ff	""
	attrs:	0x0000000000000000
	type:	c12a7328-f81f-11d2-ba4b-00a0c93ec93b
		(EFI System Partition)
	guid:	077b8491-26d1-4984-a86f-2c8674c438ee
 10	0x00037800	0x00200000	""
	attrs:	0x0000000000000000
	type:	bc13c2ff-59e6-4262-a352-b275fd6f7172
		(bc13c2ff-59e6-4262-a352-b275fd6f7172)
	guid:	3b088c0d-2f7b-4d92-b7c0-561d0e2cdd30
=> 

You can also inspect some of the qfw tables directly. The qfw list command has been around for a while, although some minor updates were added recently. It shows the files that QEMU presents to U-Boot:

=> qfw list 
    Addr     Size Sel Name
-------- -------- --- ------------
       0        0  20 bios-geometry                                           
       0       6d  21 bootorder                                               
3fcab000       14  22 etc/acpi/rsdp                                           
3fcad000    20000  23 etc/acpi/tables                                         
       0        4  24 etc/boot-fail-wait                                      
       0       28  25 etc/e820                                                
       0        8  26 etc/msr_feature_control                                 
       0       18  27 etc/smbios/smbios-anchor                                
       0      169  28 etc/smbios/smbios-tables                                
       0        1  29 etc/smi/features-ok                                     
       0        8  2a etc/smi/requested-features                              
       0        8  2b etc/smi/supported-features                              
       0        6  2c etc/system-states                                       
       0     1000  2d etc/table-loader                                        
       0        0  2e etc/tpm/log                                             
       0        8  2f etc/vmgenid_addr                                        
3fcac000     1000  30 etc/vmgenid_guid                                        
       0     2400  31 genroms/kvmvapic.bin 

Low-level features

The new qfw table command can be useful to seeing exactly how the ACPI tables are provided:

=> qfw table
  0 alloc: align 10 zone fseg name 'etc/acpi/rsdp'
  1 alloc: align 1000 zone high name 'etc/vmgenid_guid'
  2 alloc: align 40 zone high name 'etc/acpi/tables'
  3 add-chksum offset 49 start 40 length 30f7 name 'etc/acpi/tables'
  4 add-ptr offset 315b size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
  5 add-ptr offset 315f size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
  6 add-ptr offset 31c3 size 8 dest 'etc/acpi/tables' src 'etc/acpi/tables'
  7 add-chksum offset 3140 start 3137 length f4 name 'etc/acpi/tables'
  8 add-chksum offset 3234 start 322b length 120 name 'etc/acpi/tables'
  9  10 add-ptr offset 3375 size 4 dest 'etc/acpi/tables' src 'etc/vmgenid_guid'
 11 add-chksum offset 3354 start 334b length ca name 'etc/acpi/tables'
 12 add-chksum offset 341e start 3415 length 38 name 'etc/acpi/tables'
 13 add-chksum offset 3456 start 344d length 208 name 'etc/acpi/tables'
 14 add-chksum offset 365e start 3655 length 3c name 'etc/acpi/tables'
 15 add-chksum offset 369a start 3691 length 28 name 'etc/acpi/tables'
 16 add-ptr offset 36dd size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 17 add-ptr offset 36e1 size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 18 add-ptr offset 36e5 size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 19 add-ptr offset 36e9 size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 20 add-ptr offset 36ed size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 21 add-ptr offset 36f1 size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 22 add-ptr offset 36f5 size 4 dest 'etc/acpi/tables' src 'etc/acpi/tables'
 23 add-chksum offset 36c2 start 36b9 length 40 name 'etc/acpi/tables'
 24 add-ptr offset 10 size 4 dest 'etc/acpi/rsdp' src 'etc/acpi/tables'
 25 add-chksum offset 8 start 0 length 14 name 'etc/acpi/rsdp'

Since QEMU can also provide SMBIOS tables, these can be inspected using the smbios command:

=> smbios
SMBIOS 3.0.0 present.
9 structures occupying 361 bytes
Table at 0x3fcdc018

Handle 0x0100, DMI type 1, 27 bytes at 0x3fcdc018
System Information
	Manufacturer: QEMU
	Product Name: Standard PC (Q35 + ICH9, 2009)
	Version: pc-q35-8.2
	Serial Number: 
	UUID: 8967d155-8cbb-484f-9246-d2c4eeeedff1
	Wake-up Type: Power Switch
	SKU Number: 
	Family: 

Handle 0x0200, DMI type 2, 15 bytes at 0x3fcdc063
Baseboard Information
	Manufacturer: Canonical Ltd.
	Product Name: LXD
	Version: pc-q35-8.2
	Serial Number: 
	Asset Tag: 
	Feature Flags: 0x01
	Chassis Location: 
	Chassis Handle: 0x0300
	Board Type: Motherboard
	Number of Contained Object Handles: 0x00

Handle 0x0300, DMI type 3, 22 bytes at 0x3fcdc091
Baseboard Information
	Manufacturer: QEMU
	Type: 0x01
	Version: pc-q35-8.2
	Serial Number: 
	Asset Tag: 
	Boot-up State: Safe
	Power Supply State: Safe
	Thermal State: Safe
	Security Status: Unknown
	OEM-defined: 0x00000000
	Height: 0x00
	Number of Power Cords: 0x00
	Contained Element Count: 0x00
	Contained Element Record Length: 0x00
	SKU Number: 

Handle 0x0400, DMI type 4, 48 bytes at 0x3fcdc0b8
Processor Information:
	Socket Designation: CPU 0
	Processor Type: Central Processor
	Processor Family: Other
	Processor Manufacturer: QEMU
	Processor ID word 0: 0x000a06a4
	Processor ID word 1: 0x0f8bfbff
	Processor Version: pc-q35-8.2
	Voltage: 0x00
	External Clock: 0x0000
	Max Speed: 0x07d0
	Current Speed: 0x07d0
	Status: 0x41
	Processor Upgrade: Other
	L1 Cache Handle: 0xffff
	L2 Cache Handle: 0xffff
	L3 Cache Handle: 0xffff
	Serial Number: 
	Asset Tag: 
	Part Number: 
	Core Count: 0x16
	Core Enabled: 0x16
	Thread Count: 0x16
	Processor Characteristics: 0x0002
	Processor Family 2: Other
	Core Count 2: 0x0016
	Core Enabled 2: 0x0016
	Thread Count 2: 0x0016
	Thread Enabled: 0x5043

Handle 0x1000, DMI type 16, 23 bytes at 0x3fcdc0ff
Header and Data:
	00000000: 10 17 00 10 01 03 06 00 00 10 00 fe ff 01 00 00
	00000010: 00 00 00 00 00 00 00

Handle 0x1100, DMI type 17, 40 bytes at 0x3fcdc118
Header and Data:
	00000000: 11 28 00 11 00 10 fe ff ff ff ff ff 00 04 09 00
	00000010: 01 00 07 02 00 00 00 02 00 00 00 00 00 00 00 00
	00000020: 00 00 00 00 00 00 00 00
Strings:
	String 1: DIMM 0
	String 2: QEMU

Handle 0x1300, DMI type 19, 31 bytes at 0x3fcdc14d
Header and Data:
	00000000: 13 1f 00 13 00 00 00 00 ff ff 0f 00 00 10 01 00
	00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Handle 0x2000, DMI type 32, 11 bytes at 0x3fcdc16e
Header and Data:
	00000000: 20 0b 00 20 00 00 00 00 00 00 00

Handle 0x7f00, DMI type 127, 4 bytes at 0x3fcdc17b
End Of Table

You can see above that these are created by QEMU, under control of LXD. Thus the environment which U-Boot sees can be controlled by QEMU or by tools which integrate QEMU.

What’s next?

U-Boot has a fairly solid set of QEMU features at this point. It provides an alternative to OVMF in some cases, with a faster boot, while still using EFI. Future work may include looking at booting without EFI, thus saving time and reducing complexity.




Host-file Access with New virtio-fs

What is virtio-fs?

For those unfamiliar, virtio-fs is a modern shared filesystem designed specifically for virtualised environments. It allows a virtual machine (the “guest”) to access a directory on the host system, but it does so with a focus on performance and providing local filesystem semantics.

Unlike traditional methods like network filesystems (e.g., NFS, Samba) or even the older virtio-9p protocol, virtio-fs is engineered to take advantage of the fact that the guest and host are running on the same machine. By leveraging shared memory and a design based on FUSE (Filesystem in Userspace), it bypasses much of the communication overhead that can slow down other solutions. The result is a faster, more seamless file sharing experience that is ideal for development, testing, and booting from a root filesystem located on the host.

virtio-fs arrives in U-Boot Concept

The recent merge request in U-Boot Concept introduces a new virtio-fs driver within U-Boot. This initial implementation enables two key functions:

  • List directories on the host
  • Read files from the host

This is made possible by a new filesystem driver that integrates with U-Boot’s new FS, DIR, and FILE uclasses. A compatibility layer is included so that existing command-line functionalities continue to work as expected.

This new capability in U-Boot opens up more flexible and efficient workflows. For example, developers can now more easily load kernels, device tree blobs, or other artifacts directly from their development workstation into a QEMU guest running U-Boot, streamlining the entire test and debug cycle. For cloud use cases, reading configuration files from via virtio-fs is a common requirement.

Overall this lays a strong foundation for future enhancements to virtio-fs support within U-Boot, promising even tighter integration between guest environments and the host system.