ACPI Firmware Performance Data Table

U-Boot Concept now has preliminary support for the ACPI Firmware Performance Data Table (FPDT). It is included in the ‘bootstage and script enhancement’ series. The OS can look at this table to figure out how long the firmware took to boot.

Only the ‘basic boot’ record is supported. It contains the following fields:

  • reset_end – Timestamp for the end of reset. This is set to the timestamp when U-Boot starts, or strictly speaking, when it sets up bootstage.
  • loader_start – Timestamp for when U-Boot starts loading the OS (not supported)
  • loader_exec – Timestamp for when U-Boot starts OS execution. This presupposes the EFI loader, i.e. starting the OS does not actually mean that U-Boot is finished. For now this is not supported.
  • ebs_entry – Timestamp for when the OS (or EFI app) calls exit-boot-services (not supported)
  • ebs_exit – Timestamp for when U-Boot completes the exit-boot-services call (not supported)

All timestamps are 64-bit values in microseconds with 0 assumes to be the end of the reset signal.

As you can see from the above, most of the fields are not currently filled in. Further work will be needed to plumb this into U-Boot’s EFI loader. As with the BGRT (blog link) the FPDT is added to the ACPI tables provided by QEMU, when running under emulation.




Some thoughts on Claude

I’ve been experimenting with AI coding tools, mostly Claude, for the last few months. Here are some thoughts on my experience so far.

Things I have tried

So far I have tried using Claude for many different tasks:

  • Solving a coding problem, such as creating a Python script to scan header files
  • Writing tests for existing code
  • Checking patches before I send them
  • Writing drafts for blog posts
  • Figuring out bugs
  • Adjusting code to make tests pass

First, a caveat. I am a beginner at using this technology and do not spend much time following leaders in this space. I started using Claude based on a family recommendation and am far from being any sort of expert.

The good

When I first tried out creating a new command in Claude, it produced code which compiled and looked like U-Boot code. This seemed quite magical to me and i left the computer with a feeling of awe and bewilderment. I have a basic understanding of how AI operates but it is amazing to see it producing code like this. Also the inference is very fast, sometimes producing hundreds of lines of code in a minute or less.

Claude works within your project directory. It can read and write commits, run tests, etc. For a code base like U-Boot with lots of tests, it is relatively easy to get it to make changes while ensuring that the tests still pass. It can execute most commands that you can. It asks first but you can add rules to a JSON file to give it permission to run things itself.

In most cases, Claude is able to solve the problem. For example, I wanted to build U-Boot as a library. I actually had some old patches for this, but I decided to give the task to Claude. I provided a lot of guidance on exactly how it should work, but Claude figured out the Makefile rules, iterating until things worked and fixing bugs that I found. I was able to make changes myself, tell Claude and it would build on them.

The easiest tasks for Claude are to extend an existing feature and the associated tests. The hardest are to refactor code in non-trivial ways.

One interesting case where Claude does well is dealing with conflicts when rebasing a series or applying patches. I have only tried this a few times but it has not made any mistakes yet. It is fairly slow, though.

The bad

Claude is a long way from perfect. It feels to me like a very junior but knowledgeable software engineer. It happily writes 600 lines of code when 300 would do. For larger tasks, the code feels extremely ‘flabby’ and a bit painful to read. Variables names are too long. Useless comments are added to obvious code. It happily creates highly redundant code instead of setting up a helper function first.

But with all of these problems, you can guide it to perform better. You can review the code and ask it to make changes and it happily does so. It might not be able to conceive of a refactoring that would improve code, but it can execute it.

For one tasks, Claude was able to create a 1200-line Python script in about an hour (with lots of prompting, etc.) that would have likely taken me 1-2 days (it is hard to be sure, since I didn’t do it). I then spent about 6 hours refacoring and rewriting the script after which I felt that the code wasn’t too bad. The end result was likely not as good as I would have done if I had written it myself from scratch, but it was fine.

Sometimes Claude gets stuck. It tends to happen when I am trying to get it to do something I’m not to sure about. It sometimes just gets the wrong end of the stick, or solves a slightly different problem. This is most common when first firing it up. After a bit of back and forth it settles in and makes progress

The ugly

What is Claude bad at? When running programs it can see the console output, but it cannot interact with the program, or at least I’m not sure how to make it do that. So for example it can run U-Boot sandbox with a timeout and it can even pass it commands to run. But it doesn’t know how to ‘type’ commands interactively.

Claude can sometimes change the test to fit the code, when the tasks was to fix the code. It tends to write non-deterministic tests, such as asserting that an integer is greater than zero, rather than checking for an exact value.

Claude can produce commit messages. It tends to be verbose by default but you can ask it to be brief. But I have not had much success in getting Claude to create its own commits after making a whole lot of changes.

Getting things done can sometimes just be very slow. I have not really compared the time to create high-quality, finished patches myself versus with Claude. That is something I must try, now that I am learning more about it.

My workflow

How do I actually use Claude? Well, first I figure out a design for what I want to do, typically a diagram or some notes. Then I ask Claude to perform an initial change to make a start. Then I build on that piece by piece until I have something working. I have not tried giving it a large challenge.

In some cases I create commits as I go, or even ask Claude to do this, but mostly I just create the whole thing and then manually build the commits afterwards. For code that Claude created in whole or part I add a Co-developed-by tag.

Breaking things into chunks saves time, I think. Cleaning up hundreds of lines of AI-generated code is very time-consuming and tedious. It is easier to tweak it a bit as I go.

A note on Gemini

I have tried Gemini CLI and sadly so far it has not been useful except in a few small areas. It is quite slow and seems to go into the weeds with any sort of moderate challenge. I expect this to change rapidly, so I keep trying it every now and then. I also use Gemini to create most of the featured images.

I have not tried OpenAI so far.

What do you think?

Leave a message in the comments if you have any thoughts or suggestions!




New video command and unified embedded image handling

U-Boot has long supported embedding a graphical image directly into the binary – like the boot logo and the recently added BGRT (Boot Graphics Resource Table) image for EFI systems. But the way these images were handled was a bit of a mixed bag, with different patterns for different images and custom boilerplate for each one.

A new 6-patch series cleans this up, introducing a unified infrastructure for embedded images along with new commands to work with them.

What’s new

Unified image infrastructure

Previously, images were handled through ad-hoc Makefile rules that looked for specific patterns like _logo.bmp or _image.bmp. Each image required custom accessor macros and boilerplate code.

The new approach moves all embedded images into a single drivers/video/images/ directory and automatically generates linker list entries for them. This makes it trivial to add new images – just add obj-y += myimage.o to the Makefile and reference it using video_image_get(myimage, &size) or video_image_getptr(myimage).

The linker list infrastructure ensures that all images are discoverable at runtime, which enables the new video images command described below.

New video command

A new video command has been added with four subcommands:

  • video setcursor <col> <row> – Set cursor position (equivalent to existing setcurs command)
  • video puts <string> – Write string at current position (equivalent to existing lcdputs command)
  • video write -p [<col>:<row> <string>...] – Write string at a given position, either a character or a pixel position
  • video images – List all images compiled into U-Boot

The existing standalone setcurs and lcdputs commands remain available for backward compatibility.

Example usage

=> video images
Name                       Size
-------------------- ----------
bgrt                      43926
u_boot                     6932

Total images: 2

=> video setcursor 10 5
=> video puts "Hello U-Boot!"
=> video write -p a3:34 "Pixels"

The payoff

This series removes 46 lines of duplicate accessor code while adding about 500 lines total (mostly documentation and tests). But the real win is in maintainability:

  • Simpler to extend: Adding a new embedded image now requires just a single line in a Makefile
  • Discoverable: The video images command shows what’s available at runtime
  • Better organized: All images live in drivers/video/images/ rather than scattered across the tree
  • Consistent API: One pair of macros works for all images

The series also brings comprehensive documentation for the video commands (which previously had none) and adds tests to ensure everything works correctly.

If you’ve ever wanted to add a custom boot logo or wondered what images are built into your U-Boot binary, this series makes both much easier!




Enhancing EFI Boot and Developer Experience

We’ve just rolled out a series of updates aimed at improving the U-Boot EFI application, with a special focus on streamlining the testing and debugging process, particularly for ARM platforms. This batch of 24 patches introduces several quality-of-life improvements, from better debugging tools to more robust boot procedures. Let’s dive into the key changes.


Streamlining the Boot Process with ‘Fake Go’ 🚀

One of the standout features in this release is the introduction of a ‘fake go’ option for the boot process. Previously available only for tracing, this feature is now a standalone debugging tool enabled by CONFIG_BOOTM_FAKE_GO.

When you initiate a boot with the ‘fake go’ flag (e.g., bootflow boot -f or bootm fake), U-Boot performs all the necessary steps to prepare for booting an OS—loading the kernel, setting up the device tree, and preparing memory—but stops just short of jumping to the OS. This allows you to inspect the system’s state at the final moment before handoff, which is invaluable for debugging complex boot issues without needing a full OS boot cycle.


Pager Improvements for Better Interaction 📄

The console pager is a useful tool, but it can be cumbersome when you’re working without a serial console or need to quickly bypass lengthy output. We’ve introduced two new ways to control the pager on the fly:

  • Quit and Suppress (q): Pressing q at the pager prompt will now immediately stop all further output for the current command. This is perfect for when you’ve seen what you need and want to return to the prompt without sitting through pages of text.
  • Bypass Session (Q): Pressing Q will put the pager into bypass mode for the rest of your U-Boot session, allowing all subsequent commands to print their full output without interruption.

These small changes make console interaction much more fluid and give you greater control over command output.


Key Fixes and Enhancements 🛠️

Alongside these major features, this series includes a number of other smaller updates:

  • Safer Image Relocation on ARM: We’ve improved how kernel images are relocated on ARM. Instead of moving the image to a static offset, which could risk overwriting other critical data like the device tree, U-Boot now uses the LMB (Logical Memory Block) library to safely allocate a new, unused region of memory.
  • Improved Debugging Output: We’ve added more detailed debug messages throughout the boot process, especially in FIT image handling and device tree selection, making it easier to trace the boot flow and diagnose issues.
  • Cleaner ATAGs Messaging: The often-confusing “FDT and ATAGS support not compiled in” error has been clarified. U-Boot will now correctly report when a device tree is missing, preventing developers from going down the wrong path when debugging.
  • CI and Build Fixes: A few patches have been included to fix a bug in our automated release script that was causing CI failures, ensuring our development and release processes remain smooth.

These updates continue the development of the EFI app, while benefiting others boards as well.




Automating the U-Boot Concept Release Cycle


U-Boot Concept releases provide regular, time-based snapshots of our development progress, offering a stable point for users and developers. Up until recently, creating these releases involved a series of manual steps that were time-consuming and prone to human error.

To improve this process, we’re happy to announce a new, fully automated release workflow for U-Boot Concept. This system uses GitLab CI/CD and a custom Python script to handle the entire release process, from version calculation to final tagging, ensuring consistency and reliability.


A Predictable Schedule

The automation is built around a strict, predictable schedule that defines when final and release candidate (RC) versions are created. This removes any ambiguity about when to expect a new release.

  • Final Releases: Occur on the first Monday of every even-numbered month (February, April, June, August, October, December). The version number corresponds to the year and month, such as 2025.10.
  • Release Candidates (RCs): A series of three release candidates are created every two weeks leading up to a final release:

    • rc1: 6 weeks before the final release.
    • rc2: 4 weeks before the final release.
    • rc3: 2 weeks before the final release.

  • Dead Period: The time between a final release and the next rc1 is considered a “dead period” where no automated releases occur. This provides a development window before the next stabilization cycle begins.

The Automation in Action

The entire process is managed by a scheduled GitLab CI/CD pipeline that runs periodically to check if a release is due. Here’s a step-by-step look at what happens on a release day:

  1. Date Check & Version Calculation: The pipeline executes a Python script (scripts/release_version.py), which acts as the brains of the operation. The script checks the current date against the release schedule. If it’s not a designated release Monday, the job simply exits.
  2. Makefile Version Bump: If it is a release day, the script calculates the new version (e.g., 2025.12-rc1) and automatically updates the VERSION, PATCHLEVEL, and EXTRAVERSION variables in the project’s Makefile.
  3. Automated Commit: The CI job commits the modified Makefile directly to the master branch with a standardized message, such as chore: Bump version for release candidate 2025.12-rc1.
  4. Documentation Update: The script then updates the release history in doc/develop/concept_releases.rst, adding an entry for the new version along with the corresponding commit SHA. It also intelligently updates the “Next Release” section to show the schedule for the upcoming final release. This change is also committed and pushed automatically.
  5. Tag and Release: Finally, the pipeline uses the official release-cli tool to create a formal Git tag (e.g., c2025.12-rc1) and a corresponding GitLab Release. This provides a clear, permanent marker for the release, complete with a title and description. The ‘c’ prefix makes it clear that this is a Concept release, not the main tree.

Benefits of Automation

This new workflow brings several key advantages to the U-Boot Concept project:

  • Consistency: Every release is generated using the exact same procedure, ensuring uniformity.
  • Reliability: The risk of human error—like typos in version numbers or forgetting a step—is eliminated.
  • Transparency: The entire process is defined in code, and the release history is now automatically documented and kept up-to-date for everyone to see.
  • Efficiency: Developer time is freed from the manual chores of release management, allowing more focus on development and innovation.

This move to an automated system marks a significant step in improving our release management and ensuring that U-Boot Concept remains a dependable and predictable development platform.




A Cursor Comes to the U-Boot Console

For a long time, editing commands in the U-Boot video console has been an exercise in memory. Without a visible cursor, it was often difficult to know your exact position in a long command line. A new 41-patch series in Concept changes that by introducing comprehensive cursor support for U-Boot’s video consoles.

This update brings a familiar (but so far non-blinking!) cursor to the command line, making editing commands a much more intuitive process.

How It Works

The new cursor functionality is designed to be efficient and visually clean.

  • Idle Display: The cursor is only drawn when U-Boot is idle and waiting for input. As soon as you begin typing or a command is executed, the cursor is hidden.
  • Save and Restore: To prevent visual artifacts, the video driver now saves the framebuffer pixels that are underneath the cursor’s position before it is drawn. When the cursor needs to be hidden, these saved pixels are restored, ensuring that the original display content is perfectly preserved.
  • Broad Support: This functionality is not limited to one type of console. The new cursor is supported on both the standard bitmap-font console (console_normal) and the more advanced console_truetype.

Related Improvements

This series goes beyond just adding a cursor and includes several related enhancements that improve the overall console experience:

  • Truetype Console Upgrades: The truetype console receives two major improvements. First, it can now render standard bitmap fonts, making it more versatile. Second, a long-standing issue has been fixed where using arrow keys to edit commands would corrupt the displayed text. Command-line editing with truetype fonts is now much more reliable.
  • Expo on Standard Consoles: The expo toolkit’s line-editing feature, previously dependent on the truetype console, now works with the standard bitmap-font console as well. This is made possible by the new console state-tracking implemented for the cursor.
  • Thoroughly Tested: The series includes a new set of tests specifically for the cursor functionality, verifying backspace behavior and ensuring there are no visual artifacts left behind after editing.

This work represents a significant quality-of-life improvement for anyone who works regularly with the U-Boot command line without a serial UART. To enable it on your board, simply add CONFIG_CURSOR=y to your configuration.




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.




Mouse Support Comes to U-Boot

We’re excited to announce a new patch series that brings mouse support to U-Boot! This long-awaited feature resurrects some old code that was originally developed for Nuklear integration and provides a comprehensive mouse input framework.

What’s New

The 17-patch series (1,374 lines added across 44 files) introduces a simple mouse subsystem including:

  • Mouse Uclass: A new device model class for mouse devices
  • Multiple Driver Support:
  • Sandbox mouse driver for development and testing
  • USB mouse driver for x86 platforms
  • EFI mouse driver for EFI applications
  • Command Interface: New mouse command to display mouse input
  • Script Integration: Updated build-efi and build-qemu scripts with mouse support

Key Features

Universal Mouse Support

The new mouse uclass provides a consistent interface across different platforms and hardware configurations. Whether you’re running U-Boot on real hardware, in QEMU, or as an EFI application, mouse support is now either available or can be plumbed in.

USB Mouse Integration

For x86 platforms, the USB mouse driver enables standard USB mice to work with U-Boot after running usb start. This is particularly useful for interactive applications and debugging.

EFI Simple Pointer Protocol

The EFI mouse driver implements the EFI Simple Pointer Protocol, making mouse support available when U-Boot runs as an EFI application on real hardware.

Testing Framework

Comprehensive testing support includes unit tests for the mouse uclass and integration with the sandbox environment for development.

Current Status

The mouse support is functional across multiple platforms:

  • ✅ X86 QEMU (after usb start)
  • ✅ Real hardware with EFI
  • ✅ Sandbox environment for development

There are are a few limitations:

  • ARM QEMU mouse support needs refinement
  • USB mouse initialization timeout (though functionality works)

Looking Forward

This mouse support lays the groundwork for more interactive U-Boot applications and improved user interfaces. The framework is designed to be extensible, allowing for future enhancements and additional mouse driver implementations.





U-Boot as a Library: Introducing ulib – A Bridge to the Future of Firmware

The world of firmware development is evolving rapidly. Modern SoCs are increasingly complex, boot protocols are multiplying, and new programming languages like Rust and Zig are gaining traction in systems programming. Meanwhile, U-Boot has accumulated over two decades of battle-tested functionality supporting 1300+ boards, a comprehensive driver model, extensive filesystem support, and a wealth of boot protocols.

What if we could make all this U-Boot functionality available to new projects without requiring them to rebuild everything from scratch? This is the vision behind ulib – the U-Boot library system that transforms U-Boot from a standalone firmware into a reusable library.

What is ulib?

The U-Boot library (ulib) is a groundbreaking feature that allows U-Boot to be built as either a shared library (libu-boot.so) or static library (libu-boot.a). This enables external programs to link against U-Boot’s functionality without needing to integrate directly with the U-Boot build system or create full U-Boot images.

Think of it as taking U-Boot’s extensive hardware abstraction layer, driver model, filesystem support, and utility functions and making them available as a traditional library that any C or Rust program can use.

Key Features and Capabilities

Dual Library Support

  • Shared Library (libu-boot.so): Dynamic linking with smaller executables but runtime dependencies, useful for development
  • Static Library (libu-boot.a): Self-contained executables with no runtime dependencies, ideal for embedded systems

Symbol Renaming System

One of ulib’s most elegant solutions addresses a common problem: symbol conflicts. When you link against U-Boot’s library, you don’t want U-Boot’s printf() to override the standard library’s version. ulib automatically handles this through a sophisticated symbol renaming system:

#include <stdio.h>        // Standard library functions
#include <u-boot-api.h>   // U-Boot functions with ub_ prefix

int main() {
    printf("Using standard printf\n");      // System printf
    ub_printf("Using U-Boot printf\n");     // U-Boot's printf
    return 0;
}

Comprehensive Example Programs

The implementation includes both C and Rust examples that demonstrate real-world usage:

#include <u-boot-lib.h>
#include <u-boot-api.h>

int main(int argc, char *argv[])
{
    // Initialize U-Boot library
    if (ulib_init(argv[0]) < 0)
        return 1;

    // Use U-Boot OS abstraction functions
    int fd = os_open("/proc/version", 0);
    if (fd >= 0) {
        char line[256];
        while (os_fgets(line, sizeof(line), fd)) {
            ub_printf("Read: %s", line);
        }
        os_close(fd);
    }

    // Clean up
    ulib_uninit();
    return 0;
}

Multi-Language Support

ulib isn’t limited to C. The implementation includes a Rust crate (u-boot-sys) that provides FFI bindings, enabling Rust programs to leverage U-Boot functionality:

use u_boot_sys::*;

fn main() {
    unsafe {
        if ulib_init(/* ... */) == 0 {
            ub_printf(b"Hello from Rust!\n\0".as_ptr() as *const i8);
            ulib_uninit();
        }
    }
}

Technical Architecture

Build System Integration

The ulib system is deeply integrated into U-Boot’s build process. When you configure U-Boot with CONFIG_ULIB=y, the build system:

  1. Automatically disables LTO (Link Time Optimization) since it’s incompatible with symbol renaming
  2. Excludes the main() function to allow external programs to provide their own entry points
  3. Applies symbol renaming using objcopy --redefine-sym
  4. Generates API headers with renamed function declarations
  5. Preserves the critical U-Boot linker lists for proper driver initialization

Symbol Renaming Pipeline

The symbol renaming system uses a Python script (scripts/build_api.py) that:

  • Parses symbol definition files (lib/ulib/rename.syms)
  • Extracts function declarations from header files
  • Applies renaming transformations to object files
  • Generates unified API headers with renamed declarations

Linker Considerations

Proper linking requires careful attention to U-Boot’s linker lists. For static libraries, this means using whole-archive linking and custom linker scripts to ensure proper section alignment:

-Wl,--whole-archive $(obj)/libu-boot.a -Wl,--no-whole-archive

Current Status and Platform Support

As of this post, ulib supports the sandbox architecture, making it perfect for:

  • Development and testing on host systems
  • Creating test frameworks that exercise U-Boot code
  • Building applications that need U-Boot’s OS abstraction layer
  • Prototyping new boot protocols or filesystem handlers

The sandbox support is the ideal starting point – it provides a safe, familiar environment for developers to experiment with U-Boot functionality without needing embedded hardware.

Testing and Quality Assurance

The ulib implementation includes comprehensive testing through:

  • Unit Tests: Both shared and static library test programs
  • Integration Tests: Complete example programs demonstrating real usage
  • Python Test Suite: Automated testing via U-Boot’s pytest framework
  • Multi-language Validation: Tests for both C and Rust implementations

The test suite validates everything from basic library initialization to complex symbol renaming scenarios.

License Implications and Considerations

It’s important to understand that ulib inherits U-Boot’s GPL-2.0+ license. This means:

  • Static linking creates derivative works requiring GPL compliance
  • Dynamic linking is less clear
  • Source code distribution is typically required
  • Commercial users should consult legal counsel

The documentation explicitly covers these considerations, ensuring developers make informed decisions.

Real-World Applications

ulib opens up several compelling use cases:

Test Framework Development

Create comprehensive test suites that can exercise U-Boot drivers and functionality without needing physical hardware:

// Test U-Boot filesystem code
if (!ulib_init("test-program")) {
    // Test FAT filesystem functions
    // Test ext4 filesystem functions
    // Test device tree parsing
    ulib_uninit();
}

Rapid Prototyping

Develop new boot protocols or features using familiar development environments before porting to embedded systems.

Cross-Language Integration

Build systems where Rust handles high-level logic while leveraging U-Boot’s proven hardware abstraction:

// Rust application using U-Boot's hardware drivers
let device_info = unsafe { ub_get_device_info() };
process_hardware_data(device_info);

Educational Tools

Create interactive learning tools that demonstrate embedded systems concepts using U-Boot’s extensive codebase.

The Vision: A Bridge to the Future

The author of ulib, Simon Glass, describes it as “a bridge from the best of what we have today to whatever it is that will replace it.” This isn’t hyperbole – it’s a recognition that firmware development is in transition.

Consider the possibilities:

  • Language Evolution: As Rust gains traction in systems programming, ulib provides a path to gradually migrate while preserving decades of hardware support
  • Architectural Changes: Future boot systems can leverage U-Boot’s proven functionality while experimenting with new approaches
  • Testing Revolution: Complex embedded systems can be tested on development machines using U-Boot’s hardware abstraction
  • Innovation Platform: New boot protocols, filesystems, and hardware support can be developed and tested rapidly

Implementation Highlights

The commit series that introduces ulib spans 50+ commits and represents a major engineering effort:

Core Infrastructure

  • Initial library build support
  • Shared library infrastructure
  • Test program foundation
  • Linker script adaptations

Symbol Management

  • Python-based symbol renaming system
  • API header generation
  • Build system integration
  • Symbol conflict resolution

Documentation and Examples

  • Comprehensive documentation covering usage, licensing, and architecture
  • Working C and Rust examples
  • Integration with U-Boot’s test framework
  • Complete build instructions

Tests

  • Python test suite integration
  • Symbol renaming validation
  • Multi-language example testing
  • Comprehensive error handling

Getting Started

Using ulib is straightforward:

# Build U-Boot with library support
make sandbox_defconfig
make -j$(nproc)

# Run the test programs
LD_LIBRARY_PATH=. ./test/ulib/ulib_test          # Shared library
./test/ulib/ulib_test_static                     # Static library

# Build and run examples
cd examples/ulib
make UBOOT_BUILD=/tmp/b/sandbox srctree=../..
./demo_static

Future Roadmap

The ulib foundation enables several exciting developments:

  • Multi-Architecture Support: Extending beyond sandbox to ARM, RISC-V, and x86
  • Selective Subsystem Inclusion: Choose which U-Boot components to include
  • Package Management: Integration with pkg-config and other dependency systems
  • API Versioning: Stability guarantees for external developers
  • Enhanced Language Bindings: Improved Rust integration and potential Python support

Conclusion

ulib represents more than just a technical feature – it’s a paradigm shift that opens U-Boot’s extensive capabilities to the broader systems programming community. By making U-Boot functionality available as a library, we create opportunities for innovation that were previously impossible.

Whether you’re building test frameworks, prototyping new boot systems, exploring cross-language development, or simply want to leverage U-Boot’s proven hardware support in new applications, ulib provides the foundation.

The future of firmware development is uncertain, but with ulib, we can build that future on the solid foundation of U-Boot’s two decades of evolution. It’s not just about preserving the past – it’s about enabling the next generation of innovations in systems software.

The bridge to the future starts here. Welcome to ulib 🙂





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.