Skip to main content

TECH VEDA

Corporate on-site training - Submit proposal Pick your modulesSharpen your kernel skills: deep dives, drivers, Yocto, CVEs, careers — updated daily. Read the blog →
System Design

Embedded Linux Initramfs: Do You Need One, or Should the Kernel Mount Root Directly?

Does an embedded Linux initramfs belong in your product? Compare direct root mount, a bundled initramfs and RAM-only boot, and when each one is right.

Embedded Linux Initramfs: Do You Need One, or Should the Kernel Mount Root Directly?

Most embedded Linux products with eMMC or SD storage do not need an initramfs: build the storage driver and root filesystem into the kernel, let the bootloader pass root=, and use dm-mod.create= if the root filesystem is protected by dm-verity. Add an initramfs when user-space code must run before root can be mounted, for example to unlock an encrypted root with a hardware-held key, to assemble LVM or network storage, or to load the storage driver as a module. The trade-off is a second image to build, sign, patch and keep in step with the kernel, against a simpler boot path with fewer components.

Early in boot, something must find and mount the real root filesystem: either the kernel itself, or a small user-space program in an initial RAM filesystem. A desktop distribution always uses an initramfs, because its kernel cannot know which storage driver a machine needs. On an embedded Linux product you control the kernel configuration, so the choice is yours. This article treats the embedded Linux initramfs as an architecture decision and follows the order Context, Options, Decision and Consequences.

The context

The kernel always has an in-memory filesystem called rootfs, an instance of ramfs or tmpfs. According to the kernel documentation on ramfs, rootfs and initramfs, every kernel build links a cpio archive into the image, empty by default, and extracts it into rootfs. If an /init program is present after extraction, the kernel runs it as PID 1, and that program is responsible for finding and mounting the real root. If there is no /init, the kernel uses its own code to locate the root partition named on the command line, mount it and run /sbin/init from it.

The question is whether your product puts anything in that archive. Five forces shape the answer:

  • What must happen before root is mounted. A built-in driver and a device name are enough for the kernel. A key from a TPM or trusted application, LVM, iSCSI or a recovery check needs user-space code first.
  • Integrity and confidentiality of root. A dm-verity root, as in our post on how a read-only rootfs stays verified, can be set up by the kernel alone. An encrypted root usually cannot, because the key must not be on the command line.
  • Kernel configuration policy. Without an initramfs, the storage controller driver and the root filesystem driver must be built in (=y). No module can be loaded before root is mounted, because the module files are on root.
  • Boot time and image size. An initramfs adds an archive to load and decompress, and a user-space stage, before the real init.
  • Update and signing model. Whatever runs before root is part of the trusted boot chain and must be signed and updated with the kernel.

The options

Option 1: The kernel mounts root directly

The bootloader passes something like root=PARTUUID=... rootwait ro, and the kernel mounts that partition and starts /sbin/init. For a dm-verity root, the kernel option CONFIG_DM_INIT enables the dm-mod.create= parameter, whose Kconfig help text states that it is useful for mounting the root filesystem without an initramfs. The dm-init documentation lists verity, crypt, linear, striped, delay and snapshot-origin as allowed targets, and adds dm-mod.waitfor= for root devices that are probed asynchronously, such as MMC or USB.

raghu@techveda.org:~$ cat /proc/cmdline
console=ttyS0,115200 ro rootwait=10 root=/dev/dm-0 dm-mod.waitfor=<data_dev>,<hash_dev> dm-mod.create="vroot,,,ro,0 <sectors> verity 1 <data_dev> <hash_dev> 4096 4096 <data_blocks> 1 sha256 <root_hash> <salt>"

The example is schematic. The whole verity setup is a kernel parameter, protected by whatever signs the command line.

  • Pros: one fewer image to build, sign and patch, and the shortest path from kernel to application. The bootloader can choose the A/B slot through root=.
  • Cons: storage and filesystem drivers must be built in. There is no shell or logic to recover from a mount failure; the kernel panics. The rootwait=<seconds> timeout form, added in 2023, stops the kernel from waiting indefinitely for a missing root device, so that together with a reboot-on-panic setting the bootloader can detect the failure. Anything that needs user-space code before root is not possible.

Option 2: An initramfs that mounts root and switches to it

A small archive holds an /init (a shell script, a C program, or systemd running in initrd mode) plus the tools it needs. It unlocks or assembles the root device, mounts it and switches to it. The kernel documentation describes the preferred switch as pivot_root(".", ".") followed by a lazy unmount; BusyBox and util-linux provide switch_root, and systemd provides systemctl switch-root. The systemd initrd interface defines what such an initrd must hand over, and systemd detects initrd mode by the presence of /etc/initrd-release.

The archive can be built into the kernel through CONFIG_INITRAMFS_SOURCE, or loaded by the bootloader as a separate file. In the Yocto Project, INITRAMFS_IMAGE with INITRAMFS_IMAGE_BUNDLE = "1" builds an initramfs image (the reference is core-image-minimal-initramfs) and links it into the kernel; initramfs-framework supplies modules such as udev, e2fs, lvm and overlayroot.

  • Pros: any logic can run before root: key unsealing from a TPM or a trusted application, LVM, network root, a filesystem check, a factory-reset path, a fallback to the other A/B slot. Drivers can be modules.
  • Cons: a second root filesystem, with its own BusyBox or systemd, libraries and CVEs. It must stay in step with the kernel (module versions) and be signed with it. It adds boot time and a stage that can fail in its own ways.

Option 3: The initramfs is the whole system

The complete root filesystem lives in the initramfs and never switches to storage. In Buildroot, BR2_TARGET_ROOTFS_INITRAMFS embeds the generated root filesystem into the kernel image as an initramfs; its help text warns against combining it with other filesystem formats, because that produces two identical root filesystems.

  • Pros: one file to boot and verify. Root is never mounted from writable flash, so it cannot be corrupted at run time. Well suited to installers, factory test images, rescue images and network-booted units.
  • Cons: the whole system occupies RAM for the life of the device, and every change to user space means a new kernel image. It scales poorly beyond a small root filesystem.

The decision: when an embedded Linux initramfs is worth it

For the common product, boot without an initramfs. If the device boots from eMMC, SD or NVMe with mainline drivers you can build in, uses a plain or dm-verity read-only root, and selects the A/B slot in the bootloader, Option 1 gives you the shortest boot path, the smallest trusted base and one fewer image to maintain. Treat dm-mod.create= and a signed command line as the replacement for what an initramfs would otherwise do.

Choose Option 2 when any of these is true:

  • The root filesystem is encrypted and the key is unsealed by hardware or a trusted application at boot.
  • Root is on LVM, iSCSI, NFS or another stack that needs user-space setup or a daemon.
  • The kernel is shared across product variants and the storage drivers must be modules.
  • You need a recovery decision, a filesystem repair or a factory reset that must run before the main root is mounted.

Choose Option 3 for installer, manufacturing, rescue and netboot images, and for very small products whose root filesystem fits comfortably in RAM.

Consequences

Without an initramfs, the kernel command line becomes a security contract. It carries the root device and, for dm-verity, the root hash, so it must come from a signed image, not an editable bootloader environment. Our post on a signed FIT image U-Boot will verify shows one way to do that. Changing the eMMC host driver or root filesystem to =m later produces a kernel that cannot mount root, so add a build-time check for those symbols. Mount failures need a bootloader-level answer, such as the boot counter and fallback described in who decides an update worked.

With an initramfs, you maintain a second small distribution. Its BusyBox, udev or systemd components belong in your SBOM and need CVE tracking. Bundle it into the kernel image or the same signed FIT, so kernel, modules and initramfs are verified and updated as one unit; a separately loaded, unsigned initramfs is a gap in secure boot. Measure the boot time it adds on your hardware, and keep its /init short and tested, because a failure there leaves no main system to report from.

For the team, an embedded Linux initramfs needs an owner for the early user-space code, in addition to the kernel and bootloader skills that Option 1 already requires. Both are BSP skills, covered in our embedded Linux and Yocto training. Our tutorial on booting a custom kernel in QEMU with a minimal initramfs builds one by hand.

Key takeaways

  • The kernel can mount root itself when the storage and filesystem drivers are built in and the device is named on the command line.
  • CONFIG_DM_INIT and dm-mod.create= let the kernel set up a dm-verity root without an initramfs.
  • An embedded Linux initramfs is justified when user-space code must run before root: key unsealing, LVM or network storage, modular drivers, or a pre-mount recovery step.
  • Whatever runs before root is part of the trusted boot chain; bundle the initramfs with the kernel and sign them together.
Was this worth your time?

Frequently asked questions

Can I use dm-verity on the root filesystem without an initramfs?
Yes. Enable CONFIG_DM_INIT and describe the verity device with the dm-mod.create= kernel parameter, then point root= at the mapped device. Use dm-mod.waitfor= when the underlying devices are on MMC or USB and probe asynchronously.

Why can’t the kernel load my eMMC driver as a module without an initramfs?
Module files are stored on the root filesystem. Until root is mounted there is nowhere to load them from, so the storage controller driver and the root filesystem driver must be built into the kernel.

When does an encrypted root filesystem force an initramfs?
When the key is unsealed at boot by a TPM, a secure element or a trusted application. That step needs user-space code, and placing the raw key on the kernel command line is not acceptable, so an initramfs runs the unlock and then switches to the real root.

Should the initramfs be a separate file or built into the kernel?
For a product, build it into the kernel image or the same signed FIT image. Then the kernel, its modules and the initramfs are always verified and updated together, and there is no unsigned stage in the boot chain.

Further reading

RB
Raghu Bharadwaj

Founder, TECH VEDA — 20+ years teaching the Linux kernel, device drivers and embedded systems.

Follow on LinkedIn

Get new posts by email

Kernel, embedded Linux and AI-era engineering — a few sharp reads a month. No spam.

We email occasionally and never share your address.