Image of an arrow

Accelerating early Linux boot with Yocto multiconfig

Avatar

scuny

Accelerating early Linux boot with Yocto multiconfig

By Paul Le Guen de Kerneizon

Introduction

In embedded products, cutting seconds, or even hundreds of milliseconds, from power‑on to application readiness is often critical. In this article, I will present a practical workflow to measure, compare, and iteratively reduce the early boot window of a Linux embedded system, limited to the kernel and initramFS part. We will be using the Yocto project, and especially the BitBake’s multiconfig feature.

Setting the context

Nowadays, modern embedded system boot sequence share the same boot-up sequence:

    • The board firmware looks for any bootable device (USB key, hard drive, etc), and loads a valid Linux bootloader.
    • The Linux bootloader is configured to load a Linux kernel image, with custom arguments.
    • Finally, the Linux kernel boots and set up the rootfs.

 

For this article, I will consider a very simple Linux BSP architecture, using separated initramfs and rootfs images. This kind of layout is interesting to implement security features such as Secure Boot (rootfs authentication before load) and various others (file system check, A/B updates, etc). It applies to any kind of modern architecture (x86, ARM), excluding specific vendor boot sequence.

Our target BSP is composed of the following Yocto images:

    • lab-image-initramfs: this image contains the initramfs root file system, that will be responsible of the Linux first stage boot, including the load of the final rootfs. It is a very simple image, based on the core-image-minimal-initramfs image.
    • lab-image-rootfs: this image contains the final rootfs, packaged in a read-only file format such as ext4 or squashFS.
    • lab-image: this image packages the previous images into a single image, with an embedded Linux bootloader.

InitramFS optimization

As we saw previously, the initramfs image is loaded by the Linux bootloader. In embedded systems, I/O with devices such as disks are slow, and one of the most time consuming element is the initramfs image loading by the bootloader. So, reducing the size of this image will help to reduce it loading time, and so, the global system boot-time.

Initial measurements

We need to establish first what weight the most in the generated initramfs image. To do so, we are going to use the Bitbake buildhistory feature allowing to give some metrics about the contents of our generated image. It can be enabled by adding these lines in your distro file:

After building initramfs image, buildhistory has been generated:

We are interested in by the installed-package-sizes.txt file. It contains the size of each installed package in the initramfs image, sorted by weight:

Using an awk command we can get the total size of our initramfs image:

Here, the size of our image is about 39MiB.
To measure the boot-time on the target we highly recommend, if possible, to get the boot serial output and use the minicom timestamp feature.

 

List of Initramfs optimizations

On a first glance, we could interpret that there are not that much to optimize in our initramfs image, specially because it is already well minimized by the core-image-minimal-initramfs image. But some optimization can be implemented that can make the difference:

    • Changing the default C library from glib to musl library.
    • Changing the default initmanager from sysvinit to busybox-mdev.
    • Removing any additional unused packages.

Introducing Bitbake multiconfig feature

By default, a single Bitbake command can only build an image with a single configuration (distro, machine). Since the Langdale release of the Yocto Project, the multiconfig feature allows to easily apply different configuration within a single distro, for multiple images.
In our case, we would like to use the musl library and eudev init manager only for the lab-image-initramfs image, and not the rootfs image.

Setup a basic multiconfig

First, you need to add a new folder named “multiconfig” in the “conf” directory of your layer. In this folder, add a new file with the name of your multiconfig, in our example “mclabinitramfs”.

 

Now in your distro file (here lab.conf), add the following line:

We now have a basic multiconfig implementation, which currently does nothing.

Link the multiconfig to the initramfs

The usecase of the multiconfig here is to apply specific configuration boundared only to the lab-image-initramfs image. So we need to tell to Bitbake this dependency. To do so, add the following lines in your distro file (here lab.conf):

These lines specify two things:

    • INITRAMFS: the name of the initramfs used.
    • INITRAMFS_MULTICONFIG: tells to Bitbake that the kernel must be bundled with an initramfs image using a specific multiconfig and not the default one.
    • INITRAMFS_DEPLOY_DIR_IMAGE: the location where all the initramfs artifacts (images, etc) should be deployed.

Optimization

Use musl libray

musl is a C library for the Linux kernel. The main advantage of the musl library is that packages compiled with it are much lighter compared to packages build with glibc. However not all packages are compatible with musl library, especially for systemd, where musl support is still experimental. This is why I don’t recommend to use for all the images, in particular the rootfs image.

Back to our multiconfig, musl library can be enabled using the TCLIBC variable, set in the sources/meta-lab-distro/conf/multiconfig/mclabinitramfs.conf file:

Use a lighter init manager

By default, Bitbake uses sysvinit as the default initialization manager. It is great, but it can be easily improved by using mdev-busybox which is lighter compared to sysvinit. To use it, simply add these lines in the sources/meta-lab-distro/conf/multiconfig/mclabinitramfs.conf file:

Additional optimizations

To reduce further the size of the initramfs image, additional optimizations can be implemented, but are less applicable:

    • Use sh instead of bash as command interpreter, as sh is lighter compared to bash. Initramfs scripts are written using sh syntax, but keep in mind that you might need to convert your own script to the sh syntax if needed.
    • Kernel configuration minimization (unneeded file systems, etc)

Final results

With these optimizations, if we compute the size of the initramfs image, we get now a size of 29MiB, and so a reduction of 25%!
Now regarding the real result on target, it will also depends of the hardware used (CPU, disk type, etc). On our internal tests, on an ARM target we achieved to get 1.2s of boot-time reduction during initramfs image loading.

Leave a comment

Your email address will not be published. Required fields are marked *


Similar articles

Image of an arrow

Author : Luc Beaufils, Embedded Systems Engineer   Debugging MCUs has always been the key to producing high-quality code, but reliance on vendor-specific IDEs and complex debug server configurations can hinder a smooth development workflow. While VSCode has revolutionized the way developers write and debug code, setting up a debug session for MCUs can sometimes […]

  Empowering the Embedded Industry to Tackle the EU Cyber Resilience Act and Cyber regulations with an Innovative & Open Source Vulnerability Management Tool.   Nuremberg, March 11, 2025 – Savoir-faire Linux, a leading open-source software engineering and consulting firm, is proud to announce the official release of VulnScout.io, an open source cybersecurity solution designed […]

Savoir-faire Linux is excited to announce DHTNet, a powerful new C++17 library spun off from the Jami project that simplifies peer-to-peer connectivity. DHTNet enables developers to establish secure P2P connections between devices using only public keys, eliminating the need for centralized infrastructure or direct IP addressing. Features Connection Management: DHTNet simplifies the establishment and management […]

What’s new? We’re happy to announce the release of v2.8.0, which includes a few new features as well as bug fixes. Check out the summarized changelog below: Renamed command “Pick configuration” to “Change active buildConfiguration” Automatically re-scan when changing buildConfiguration Cache per-buildConfiguration scan results Make the recipes view appear as “loading” while a scan is […]