Weighing the Cost: An Update on Ext4l Code Size

A recent series in Concept enables ext4l for an ARM board, finally allowing us to make a concrete comparison between the code size of this new Linux-ported driver and the existing U-Boot implementation.

Here is a short note on what we found.

The “Linux is Large” Reality

The first observation is that the Linux kernel no longer operates under strict code-size constraints. In the early days of embedded Linux, there was immense pressure to keep footprints tiny—projects like uClinux aimed to run in very limited RAM. Today, even embedded CPUs often have gigabytes of RAM, and they run the full kernel without blinking.

This shift shows through in the code. One striking example: ext4l contains about 20KB just in error messages and warnings. To put that in perspective, those strings alone take up roughly the same amount of space as the entire code size of the existing, legacy ext4 implementation in U-Boot!

Shoehorning a modern Linux filesystem driver into a bootloader was always going to involve trade-offs. Now, we have the numbers to quantify them.

The Weigh-in: Early Results

So, how heavy is ext4l? We ran comparisons on Thumb2 (specifically the firefly-rk3288).

  • Legacy Ext4: ~7KB (Read-Only) / ~21KB (Read-Write)
  • New Ext4l: ~98KB (Read-Only) / ~137KB (Read-Write)

There is no getting around it: ext4l is significantly heavier.

Is the Size Worth It?

The short answer is: Yes, because the legacy driver is becoming obsolete.

U-Boot’s existing ext4 implementation is losing utility in the modern world. Most modern Linux distributions enable metadata checksums (metadata_csum) by default, rendering their filesystems unmountable by the current U-Boot driver. While the legacy driver has basic journaling, it lacks support for fast-commits and other features required to interact safely with real-world partitions.

Despite the size increase, ext4l provides feature-parity with Linux, allowing U-Boot to reliably interact with modern filesystems.

The Path Forward: Top-Down or Bottom-Up?

We are currently taking a “Top-Down” approach: porting the full-featured Linux driver (ext4l) and then looking for size reductions. There are likely areas we can trim, but we must be careful not to spoil one of ext4l‘s major benefits: a small code delta compared to Linux, which makes maintenance easier.

However, there is a potential “Bottom-Up” path: we could enhance the legacy ext4 driver just enough to support required features like checksums, without importing the full Linux architecture. The end result would likely land somewhere in the middle—smaller than ext4l, but larger than the current legacy driver.

The downside? It creates a distinct codebase that requires its own maintenance, separate from the kernel.

For now, ext4l gives us compatibility today, but the hunt for optimization continues.




🔑 Full Circle: Completing TKey Hardware-Backed LUKS Unlock

This final series in Concept closes out the complete implementation of TKey hardware-backed full disk encryption (FDE) in U-Boot.

The previous series established the core logic and UI flow. This final work wraps up the effort by providing end-to-end testing, a useful Python tool for key management on the host, along with documentation, making the feature ready for real-world secure-boot environments.


🛠️ The Final Pieces of the Puzzle

This series of 7 patches focuses on robust testing, external utility, and documentation.

1. Host-Side Key Management Tool

The core of this series is the new script, scripts/tkey_fde_key.py.

  • Key Derivation: This script allows users on their host machine to use a physical TKey and a passphrase to derive the exact same disk encryption key that U-Boot derives at boot time.
  • Disk Operations: It is an all-in-one utility that can then use the derived key to:

    • Encrypt a disk image (or partition) with LUKS.
    • Open/Unlock an already encrypted disk image for host access.
    • This capability is essential for creating encrypted root filesystems that U-Boot can later unlock using the TKey.

2. Comprehensive Testing & Infrastructure

To ensure this complex hardware-backed flow is reliable, the test infrastructure has been significantly upgraded:

  • Full TKey Unlock Test: A major test, bootctl_logic_tkey, validates the entire TKey unlock state machine: passphrase entry, handling TKey removal and re-insertion prompts, app loading, key derivation, and final LUKS partition unlock.
  • New Test Devices: The series adds two new disk images to the sandbox:

    • mmc13: A LUKS2-encrypted disk designed specifically for TKey-based unlock.
    • mmc14: A LUKS2-encrypted disk for testing the pre-derived master key path (via the -p flag in luks unlock), ensuring maximum flexibility.

  • Keyfile Support: The Python filesystem helper is updated to support key files (instead of only passphrases) and the ability to specify a raw master key. This allows the automated tests to encrypt disks using the deterministic key generated by the TKey emulator.

3. Complete Documentation

The final piece is the doc/usage/tkey-fde.rst guide, which ties the entire workflow together.

  • Workflow Explained: This new documentation covers the entire TKey FDE workflow, from how the key is derived from the User-Supplied Secret (USS) and the TKey’s Unique Device Identifier (UDI), to using the tkey_fde_key.py script and configuring U-Boot.
  • Physical TKey Testing: It includes a guide on how to use a real TKey for testing by generating an override.bin key, allowing developers to switch seamlessly between the emulator and physical hardware.

What’s next?

This work has been an interesting expedition into LUKS and hardware-backed security. While it is complete from the U-Boot side, there are a few loose ends which could be looked at in future. For example, it would be useful to communicate the unlock key to Linux’s the ramdisk environment, so it doesn’t need to do another unlock (and prompt the user) on startup.

In any case, U-Boot now includes a complete, robust, and well-documented solution for hardware-backed full disk encryption, a significant step forward in the area of security.




🔒 TKey Integration: Unlocking Encrypted Disks

A new series in Concept introduces the complete logic and UI enhancements required to use a TKey to unlock an encrypted disk (like a LUKS partition) before booting an operating system.

1. The TKey Unlock Flow

The TKey unlock process is complex because it involves iterative communication with the external hardware and handling scenarios like the TKey being in the wrong mode:

  • State Machine: The series implements a simple state machine (using enum unlock_state) to manage the entire TKey process. This allows the UI to remain responsive while waiting for user input, TKey removal, TKey insertion, or the app loading process .
  • App Loading: The user’s passphrase is used as the User-Supplied Secret (USS) to load a signing app onto the TKey. This is done incrementally (tkey_load_next) on each UI poll to prevent the UI from freezing.
  • Key Derivation: Once the app is loaded, the TKey’s public key is used to derive the disk encryption key (via SHA256 hashing), which is then used to unlock the LUKS partition.

2. UI and UX Enhancements

The user interface has been significantly upgraded to support this secure flow:

  • Visual Indicators: The series adds a lock image which appears next to any encrypted OS entry in the Bootctl UI, providing immediate visual feedback.
  • Passphrase Prompt: A dedicated textline object is provided for the user to enter their passphrase/USS. The series ensures this text renders as asterisks (by setting the SCENEOF_PASSWORD flag) for security.
  • User Messaging: The UI is enhanced to display dynamic messages to the user:

    • “Unlocking…” or “Preparing TKey… 50%” (progress updates during app load).
    • Error messages like “Incorrect passphrase.”
    • Hardware prompts like “Please remove TKey” or “Please insert TKey.”

  • Autonomy: The series provides functions (bc_ui_show_pass, bc_ui_get_pass, etc.) to allow the core logic to control the visibility and content of the passphrase and message fields.

3. Stability and Testing

  • LUKS2 Support: The logic is updated to ensure compatibility with LUKS2 partitions, which is crucial for modern Linux distributions.
  • TKey Correction: A fix is included in the TKey driver logic to correctly handle the position and use of the USS hash during app loading.
  • Test Environment: The series enables the Bootctl tests and includes configuration to use a TKey emulator within the Sandbox environment, ensuring the new TKey logic remains functional in the future.
  • luks command enhancement: The luks unlock command gains a new -p flag, allowing a pre-derived master key to be passed, which is useful for testing or integration with external key management systems.

This series moves U-Boot’s Bootctl from simple boot selection toward a feature-rich, hardware-backed security manager, making it a viable candidate for handling encrypted system boots.




Where did I come from? Introducing the backtrace command

Debugging embedded bootloaders can often feel like working in the dark. When execution crashes or behaves unexpectedly, the first question an engineer usually asks is, “How did I get here?”

Of course, one should always have a JTAG debugger ready to press into service, but so few boards provide a JTAG header.

To help, a recent series introduces a standardised Backtrace Library and a corresponding command to U-Boot. While currently implemented for the sandbox architecture, the design provides a generic API that paves the way for runtime stack traces across other architectures in the future.

The Power of Context

Previously, getting a call stack in U-Boot often meant attaching an external debugger (like GDB) or manually instrumenting code with print statements. This series adds runtime support to look at the backtrace directly from the console.

With the new backtrace command, developers can instantly see the call stack, complete with function names, source filenames, and line numbers.

How it Works

The implementation is split into a generic library and architecture-specific drivers:

  1. Generic API (include/backtrace.h): Provides functions like backtrace_init() to collect the stack and backtrace_show() to print it.
  2. Sandbox Implementation: For sandbox, we use the host’s libbacktrace (bundled with GCC). This allows U-Boot to read the DWARF debug information generated during the build to resolve addresses into human-readable symbols.

Cleaner Output

Raw backtraces can be messy, often printing absolute paths that clutter the terminal. A nice touch in this series (specifically Patch 9) is the automatic stripping of the source tree prefix.

Before:

run_command_list() at /home/user/workspace/u-boot/common/cli.c:168

After:

run_command_list() at common/cli.c:168

Example Usage

Once enabled with CONFIG_CMD_BACKTRACE, using the tool is straightforward:

=> backtrace
backtrace: 14 addresses
  backtrace_show() at lib/backtrace.c:18
  do_backtrace() at cmd/backtrace.c:17
  cmd_process() at common/command.c:637
  run_list_real() at common/cli_hush.c:1868
  parse_stream_outer() at common/cli_hush.c:3207
  parse_string_outer() at common/cli_hush.c:3257
  run_command_list() at common/cli.c:168
  sandbox_main_loop_init() at arch/sandbox/cpu/start.c:153
  board_init_r() at common/board_r.c:774
  ...

Looking Ahead

Currently this feature relies on libbacktrace and is available only for sandbox. However, the infrastructure is now in place. We are looking forward to seeing architecture maintainers implement the backing backtrace_init logic for ARM, RISC-V, and x86 to bring this powerful debugging capability to physical hardware.




Unlocking Modern Storage: U-Boot Adds LUKSv2 Support

We’re excited to announce that U-Boot concept has merged support for unlocking LUKSv2 encrypted partitions! This is a significant enhancement to U-Boot’s security capabilities, allowing it to handle the encryption standard used today by most current Linux distributions.

This 16-patch series (and a small follow-up) bring U-Boot up to speed with modern disk encryption, building on the existing luks unlock command.

Why LUKSv2?

While LUKSv1 was added initially, it was with the intention of taking this next step. LUKSv2 is the modern standard, offering superior security. The two key features U-Boot now supports from LUKSv2 are:

  1. Argon2id Key Derivation: LUKSv2 defaults to using Argon2id, the winner of the Password Hashing Competition. Unlike LUKSv1’s PBKDF2, Argon2id is a memory-hard function designed to be highly resistant to brute-force attacks using GPUs and ASICs. This series introduces the Argon2 library to U-Boot to handle this.
  2. XTS Cipher Mode: Support for the AES-XTS cipher mode (via mbedtls) has been added. XTS is the modern standard for disk encryption, providing stronger security guarantees than the older CBC mode.

The Implementation: A JSON-to-FDT Converter

One of the most interesting challenges in this series was handling the LUKSv2 metadata format. Unlike LUKSv1’s binary header, LUKSv2 stores its complex, hierarchical metadata as a JSON object.

As noted in the cover letter:

“One interesting part of this series is a converter from JSON to FDT, so that U-Boot’s existing ofnode interface can be used to access the hierarchical data in JSON text. This obviously results in quite a bit of new code, but it is more robust than trying to parse the text directly using strstr(), etc.”

This is the core of the new implementation. Instead of writing a new, complex JSON parser from scratch, a new function, json_to_fdt(), was created. This function parses the JSON text and converts it on-the-fly into a Flattened Device Tree (FDT) blob in memory.

From there, the LUKSv2 code can use U-Boot’s familiar and robust ofnode API (ofnode_find_subnode(), ofnode_read_string(), etc.) to navigate the metadata and retrieve keyslots, digests, and segment information. This approach is not only more reliable but also fits better within the existing U-Boot architecture.

How It Works

For the command interface, not much has changed. The existing luks unlock command just grows some new features:

  • It automatically detects whether the partition is LUKSv1 or LUKSv2.
  • If it’s LUKSv2, it will parse the JSON metadata.
  • If the keyslot uses Argon2id, it will use the new Argon2 library to derive the key.
  • If the partition uses XTS, it will use the newly enabled mbedtls functions to decrypt it.

Once unlocked, the encrypted partition is mapped as a blkmap device (e.g., blkmap 0), which you can then read from using standard commands like ext4load, fatload, or ls.

This work, along with the necessary documentation and test updates, makes U-Boot ready to boot from modern, secure, full-disk-encrypted systems.




Unlocking Disks Earlier: Basic LUKS1 Support Arrives in U-Boot

A new 24-patch series in Concept that introduces basic support for unlocking LUKS1 encrypted partitions directly within U-Boot. This is a foundational step toward a more integrated and user-friendly full-disk encryption (FDE) experience.

🤔 The Problem with “Late” Unlocking

Traditionally, FDE on Linux systems is handled late in the boot process. U-Boot loads a kernel and an initial ramdisk (initramfs), and it’s the initramfs’s job to prompt the user for a passphrase and unlock the main root filesystem.

This common approach works, but it has several drawbacks:

  • Firmware is blind: U-Boot has no way of knowing if the boot will succeed until long after it has handed off control.
  • Confusing user experience: The passphrase prompt appears late in the boot sequence, sometimes after the vendor logo has disappeared.
  • No integrated UI: It’s not possible to create a single, polished firmware UI that handles both boot selection and disk decryption.
  • Inflexible for automation: In VM environments where a key might be known in advance, there’s no way for the firmware to use it, so the ramdisk must handle this through attestation, etc.
  • Ramdisk is required: You can’t boot from an encrypted disk unless you also use a ramdisk to perform the unlock.

💡 What’s New: The luks Command

This patch series takes a small step to improve this by bringing decryption capabilities into U-Boot itself. The new feature set is centered around the luks command, which allows U-Boot to interact with LUKS-encrypted partitions.

The command introduces three main subcommands:

  1. luks detect: Checks if a given partition is a valid LUKS device.
  2. luks info: Parses and displays the LUKS header metadata. This works for both LUKS1 and LUKS2 partitions, thanks to a new simple JSON parser included in the series for handling the LUKS2 header.
  3. luks unlock: unlocks a LUKS1 partition using a provided passphrase.

Here’s a look at it in action:

=> luks detect mmc 1:2
LUKS1 encrypted partition detected

=> luks info mmc 1:2
Version:         1
Cipher name:     aes
Cipher mode:     cbc-essiv:sha256
Hash spec:       sha256
Payload offset:  4096 sectors
Key bytes:       32

=> luks unlock mmc 1:2 mysecretpassphrase
Unlocked LUKS partition as blkmap device 'luks-mmc-1:2'
=>

🔓 Accessing Decrypted Data via blkmap

Once a partition is unlocked, how do you access the data? The luks unlock command integrates with U-Boot’s blkmap subsystem.

When a partition is successfully unlocked, a new virtual blkmap device is created. This device provides read-only access to the decrypted data on-the-fly.

This means you can now use standard U-Boot commands to read files directly from the encrypted partition, just as if it were a normal, unencrypted disk:

=> ls blkmap 0 /
          ./
          ../
          lost+found/
2481008   vmlinuz-6.8.0-53-generic
1616      initrd.img-6.8.0-53-generic

=> ext4load blkmap 0 ${kernel_addr_r} /vmlinuz-6.8.0-53-generic
2481008 bytes read in 64 ms (37.0 MiB/s)
=>

This simple feature allows U-Boot to load a kernel, read a configuration file, or access any other data from an encrypted volume before booting.

🛠️ Under the Hood: What Made This Possible

There is quite a bit of foundational work included in this series:

  • Crypto: The mbedtls library in U-Boot was enhanced to enable PKCS#5 (PBKDF2) functions, which are essential for deriving keys from passphrases in LUKS. A fix for AES-192 and AES-256 key-size handling was also included.
  • blkmap Enhancement: The blkmap driver was extended with a new blkmap_map_crypt() function to handle the on-the-fly decryption.
  • Testing: A large portion of the series is dedicated to building solid testing infrastructure. This includes updates to the Docker image, CI configuration and new Python test helpers (fs_helper.py) to create, encrypt, and test against real LUKS1 and LUKS2 disk images.

This series lays the groundwork for a more secure and streamlined boot process. While full LUKS2 unlock support and read-write access are topics for another day, this is a step forward.





Pass a boot command to QEMU!

The build-qemu script provides lots of useful features and is an easy way to run U-Boot under QEMU with an OS, with or without video, etc. Now in Concept it is possible to pass a boot command!

The -b/–bootcmd option creates a special ‘file’ within QEMU that contains the requested command. Then U-Boot uses an event in main.c to check for that file and read it. The command is then executed instead of the autoboot command. In effect, it provides a way to control what U-Boot does when it starts up.

Possible uses may include setting the bootmeth order to boot using extlinux instead of EFI.

Note that this does not affect the preboot command.

The main patch is the addition of a new EVT_BOOTCMD event which is emitted in main_loop() before starting the main CLI loop. Under the hood, QEMU provides the information in its internal filesystem, the the opt/u-boot/bootcmd file. You can see this using the ‘qfw’ command:

$ ./scripts/build-qemu -a x86 -rs -b 'echo hi'

U-Boot Concept SPL 2025.10
Trying to boot from SPI


U-Boot Concept 2025.10

CPU:   QEMU Virtual CPU version 2.5+
DRAM:  512 MiB
Core:  19 devices, 12 uclasses, devicetree: separate
Loading Environment from FAT... ** Bad device specification virtio 0 **
Model: QEMU x86 (Q35)
Net:   eth0: virtio-net#0

Hit any key to stop autoboot:  0 
hi
=> qfw list
    Addr     Size Sel Name
-------- -------- --- ------------
       0        0  20 bios-geometry                                           
       0        0  21 bootorder                                               
1ec21000       14  22 etc/acpi/rsdp                                           
1ec21040    20000  23 etc/acpi/tables                                         
       0        4  24 etc/boot-fail-wait                                      
       0       28  25 etc/e820                                                
       0       18  26 etc/smbios/smbios-anchor                                
       0      13b  27 etc/smbios/smbios-tables                                
       0        1  28 etc/smi/features-ok                                     
       0        8  29 etc/smi/requested-features                              
       0        8  2a etc/smi/supported-features                              
       0        6  2b etc/system-states                                       
       0     1000  2c etc/table-loader                                        
       0        0  2d etc/tpm/log                                             
       0     2400  2e genroms/kvmvapic.bin                                    
       0        7  2f opt/u-boot/bootcmd                                      
=> 

For now this option is only supported on x86, but ARM support should land in the next few weeks.

The build-efi script also supports this option for the app, but it is implemented in a completely different way. It creates an environment file on the FAT filesystem which U-Boot can read when it starts up. A later series provides this feature which is has also landed in Concept.

The ability to pass information from the host is a useful feature in QEMU. Keep it in mind if you are working in an emulation environment!




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.




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 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.