Quick Cap
"Walk me through the boot process" is one of THE most common embedded Linux interview questions. The answer is a four-stage chain: ROM bootloader loads U-Boot SPL, which loads full U-Boot, which loads the kernel + device tree blob (DTB), and the kernel mounts the root filesystem and starts PID 1. Each stage has specific responsibilities and failure modes that interviewers probe.
Key Facts:
- Boot chain: ROM code, then U-Boot SPL, then U-Boot, then kernel, then init (PID 1)
- U-Boot loads three things: kernel image (
zImage/Image), device tree blob (DTB), and optionally initramfs - Kernel command line (
bootargs) controls root device, console, init, and debug options - initramfs is an in-memory rootfs for early setup before the real rootfs is available
- "Kernel panic: VFS: Unable to mount root fs" is the most common boot failure — wrong
root=or missing filesystem driver - Boot time optimization can reduce cold boot from 30s to under 2s
Deep Dive
At a Glance
| Stage | Who Provides It | What It Does | Typical Time |
|---|---|---|---|
| ROM bootloader | SoC vendor (burned into chip) | Loads SPL from Flash/SD/eMMC | 0.1-0.5s |
| U-Boot SPL | Open-source (U-Boot project) | Initializes DRAM, loads full U-Boot | 0.2-1s |
| U-Boot | Open-source (U-Boot project) | Loads kernel + DTB + initramfs | 1-3s |
| Linux kernel | Open-source (kernel.org) | Decompresses, initializes subsystems, mounts rootfs | 1-10s |
| init (PID 1) | Distro/build system | Starts services, reaches application ready | 1-15s |
Boot Sequence Overview
Power On|vROM Bootloader (SoC internal, loads SPL from Flash/SD/eMMC)|vU-Boot SPL (initializes DRAM, loads full U-Boot)|vU-Boot (loads kernel + DTB + optional initramfs from storage/network)|vLinux Kernel (decompresses, initializes subsystems, mounts rootfs)|vinit (PID 1) -- systemd, BusyBox init, or SysVinit|vApplication ready
Each stage trusts the previous one to have set up the environment correctly. The ROM bootloader has no user-configurable code — it is mask-programmed into the SoC and defines which boot media are checked (SD, eMMC, SPI NOR, USB) and in what order. The boot media order is typically set by hardware pin strapping or eFuses.
U-Boot: More Than Just a Bootloader
U-Boot (Das U-Boot) is the standard bootloader for embedded Linux. It is a full development environment with a command shell, scripting, network stack, filesystem drivers, and environment variable persistence.
What U-Boot does:
- Initializes DRAM (SPL stage) and peripheral clocks
- Provides a command-line interface over serial console
- Reads kernel, DTB, and initramfs from storage (eMMC, SD, NOR, NAND) or network (TFTP)
- Passes the kernel command line and DTB address to the kernel
- Transfers control to the kernel entry point
Key environment variables:
| Variable | Purpose | Example |
|---|---|---|
bootcmd | Auto-boot command sequence | load mmc 0:1 ${loadaddr} zImage; bootz ${loadaddr} - ${fdt_addr} |
bootargs | Kernel command line | console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait |
bootdelay | Seconds to wait before auto-boot | 3 (set to 0 for production) |
loadaddr | Address to load kernel image | 0x42000000 |
fdt_addr | Address to load device tree blob | 0x43000000 |
Boot commands:
| Command | Image Format | Architecture |
|---|---|---|
bootz | zImage (compressed) | 32-bit ARM |
booti | Image (uncompressed or gzip) | 64-bit ARM (AArch64) |
bootm | uImage (U-Boot legacy wrapper) | Any (legacy format) |
Network boot for development: During development, TFTP boot avoids reflashing for every kernel change. U-Boot fetches the kernel and DTB over Ethernet, and the kernel mounts the rootfs via NFS. This gives a desktop-like edit-compile-test cycle on embedded hardware.
When asked about U-Boot, do not say "it is just a bootloader." Explain that it is a full development environment with network boot, scripting, environment variables, and storage drivers. This shows you have actually worked with it, not just read about it.
Kernel Command Line (bootargs)
The kernel command line is a string of key-value parameters that control how the kernel behaves. It is passed via the bootargs environment variable in U-Boot or embedded in the device tree blob's /chosen node.
Critical parameters:
| Parameter | Purpose | Example |
|---|---|---|
console= | Serial console device and baud rate | console=ttyS0,115200 |
root= | Root filesystem device | root=/dev/mmcblk0p2 |
rootfstype= | Filesystem type of root device | rootfstype=ext4 |
rootwait | Wait for root device to appear (essential for slow-probing storage) | rootwait (no value) |
init= | Path to init program | init=/sbin/init |
quiet | Suppress kernel messages (faster boot) | quiet (no value) |
loglevel= | Kernel log verbosity (0-7) | loglevel=3 |
A typical production bootargs string looks like:
console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait quiet loglevel=3
The kernel parses this string during early boot. Unknown parameters are passed to init as arguments or set as environment variables. You can inspect the active command line at runtime via /proc/cmdline.
Without rootwait, the kernel may attempt to mount the root filesystem before the storage controller has finished probing. This causes the dreaded "VFS: Unable to mount root fs" panic even though the device and filesystem are perfectly valid. Always include rootwait when booting from SD, eMMC, or USB.
initramfs vs initrd
Both provide an early root filesystem that the kernel can use before the real rootfs is available, but they work differently:
| Characteristic | initramfs | initrd |
|---|---|---|
| Format | cpio archive (optionally compressed) | Block device image (ext2/ext4) |
| Kernel handling | Extracted into tmpfs (ramfs) | Mounted as a ramdisk block device |
| Memory model | Pages freed as files are deleted | Fixed-size ramdisk allocated at boot |
| Preferred? | Yes — simpler, more flexible | Legacy — rarely used in new designs |
| Built into kernel? | Can be linked directly into the kernel image | Always a separate file |
When you need initramfs:
- Storage drivers are compiled as modules (not built-in) and must be loaded before the rootfs device is accessible
- The rootfs is on an encrypted partition that must be unlocked before mounting
- A/B partition selection logic must run before mounting the real root
- Complex network-based rootfs setup (iSCSI, NBD)
When you can skip it:
- All storage drivers are built into the kernel (not modules)
- The rootfs is on a simple block device (eMMC, SD) that the kernel can mount directly
- No pre-mount setup is required
In practice, many embedded systems skip initramfs entirely — the kernel is configured with built-in eMMC/SD drivers and mounts the rootfs directly. This saves boot time and reduces complexity.
Rootfs Mounting Strategies
| Strategy | bootargs Configuration | Use Case |
|---|---|---|
| Block device root | root=/dev/mmcblk0p2 rootfstype=ext4 rootwait | Standard production setup |
| NFS root (development) | root=/dev/nfs nfsroot=192.168.1.1:/path ip=dhcp | Development — edit files on host, test on target instantly |
| Read-only root with overlay | root=/dev/mmcblk0p2 ro + overlayfs in init scripts | Production — squashfs base + writable overlay for config |
| A/B partitioning | Bootloader selects partition based on boot count or last-known-good flag | OTA updates — boot from A, update B, swap on next boot |
The read-only root with overlayfs pattern is the most robust for production: the base image is immutable (verified, compressed), modifications go to a separate writable partition, and factory reset is just wiping the overlay. A/B partitioning adds another layer of safety — if an OTA update fails, the bootloader falls back to the known-good partition.
Boot Time Optimization
Boot time is critical in automotive (functional safety requires fast startup), industrial (minimize downtime), and consumer (user experience). A naive embedded Linux boot can take 30+ seconds; an optimized one can reach application-ready in under 2 seconds.
| Technique | Typical Saving | Effort |
|---|---|---|
| Kernel pruning (remove unused drivers) | 2-5s | Low |
quiet boot (suppress kernel messages) | 0.5-1s | Trivial |
| Deferred module loading | 1-3s | Medium |
systemd-analyze blame (find slow services) | 1-5s | Low |
| Application preloading (start before all services) | 2-5s | Medium |
| Kernel XIP (execute-in-place from Flash) | 1-2s | High |
| U-Boot Falcon mode (skip full U-Boot, SPL loads kernel directly) | 1-2s | High |
The low-hanging fruit is always kernel pruning and quiet boot. Run systemd-analyze blame to find the slowest services, then decide which can be deferred or removed. Falcon mode eliminates the full U-Boot stage entirely — the SPL loads the kernel directly, shaving 1-2 seconds but sacrificing the interactive U-Boot environment (no more TFTP boot or environment editing without reflashing).
Debugging Story: The Missing Block Device
A team building a custom SBC received "Kernel panic: VFS: Unable to mount root fs on unknown-block(0,0)" on every boot. The rootfs was correctly written to eMMC partition 2, bootargs had root=/dev/mmcblk0p2 rootfstype=ext4, and the same rootfs image worked fine on a reference board.
The clue was in unknown-block(0,0) — major=0, minor=0 means the kernel could not find ANY block device matching the root= parameter. The team checked the kernel config and found that the eMMC/SDHCI host controller driver was set to =m (module) instead of =y (built-in). The kernel could not probe the eMMC controller, so /dev/mmcblk0p2 never appeared.
The fix: change CONFIG_MMC_SDHCI=y and CONFIG_MMC_SDHCI_OF_ARASAN=y (for their specific SoC) in the kernel config and rebuild. Alternatively, they could have used an initramfs to load the module before mounting root.
The lesson: Always ensure the kernel has built-in (not module) support for the storage controller that holds the rootfs — unless you use an initramfs to load the module first. When you see unknown-block(0,0), it means the kernel has zero visibility of the storage device.
What Interviewers Want to Hear
- You can walk through the full boot chain without hesitation: ROM, SPL, U-Boot, kernel, init
- You understand that U-Boot is more than a bootloader — it is a development environment with network boot, scripting, and persistent environment variables
- You know the critical kernel command line parameters and what happens when each is missing
- You can explain when initramfs is necessary vs when it adds unnecessary complexity
- You can debug the most common boot failure (VFS mount panic) by checking kernel config and bootargs
- You have practical experience with boot time optimization and can name specific techniques with their tradeoffs
Interview Focus
Classic Interview Questions
Q1: "Walk me through the embedded Linux boot process from power-on to application ready."
Model Answer Starter: "The boot process is a chain of trust with four main stages. First, the ROM bootloader — code burned into the SoC at the factory — reads boot media configuration from pin strapping or eFuses, finds the first-stage bootloader (U-Boot SPL) on Flash, SD, or eMMC, and loads it into internal SRAM. Second, U-Boot SPL initializes external DRAM (which was not available until now) and loads the full U-Boot into DRAM. Third, full U-Boot provides a rich environment — it reads its environment variables, loads the kernel image, device tree blob, and optionally an initramfs from storage or network, sets up the kernel command line via bootargs, and jumps to the kernel entry point. Fourth, the kernel decompresses itself, initializes CPU, memory management, and device subsystems using the DTB, mounts the root filesystem as specified by the root= parameter, and executes /sbin/init as PID 1. From there, the init system (systemd, BusyBox init, or SysVinit) starts services until the application is ready."
Q2: "What is U-Boot and what does it do?"
Model Answer Starter: "U-Boot is the de facto standard bootloader for embedded Linux. It is much more than a simple loader — it is a full development environment. In the SPL stage, it initializes DRAM. In the full stage, it provides a command shell over serial console, supports loading files from eMMC, SD, NAND, NOR Flash, USB, and network (TFTP). Its persistent environment variables (bootcmd, bootargs, bootdelay, loadaddr) control the boot sequence and kernel parameters. During development, U-Boot enables TFTP kernel loading and NFS root for rapid iteration. For production, bootdelay is set to 0, and Falcon mode can skip the full U-Boot stage entirely to save 1-2 seconds of boot time."
Q3: "What are the most important kernel command line parameters?"
Model Answer Starter: "The critical parameters are: console= which sets the serial console device and baud rate for kernel messages and login, root= which tells the kernel where the root filesystem is located, rootfstype= which specifies the filesystem type so the kernel does not need to auto-detect, rootwait which tells the kernel to wait for the root device to appear rather than panicking immediately (essential for eMMC/SD which need time to probe), and init= which overrides the default init path. For production, quiet and loglevel=3 suppress kernel messages and can save 0.5-1 second of boot time. For debugging, removing quiet and setting loglevel=7 reveals all kernel output."
Q4: "When would you use an initramfs?"
Model Answer Starter: "An initramfs is needed when the kernel cannot directly access the root filesystem at boot time. The three main scenarios are: first, when the storage controller driver is compiled as a module rather than built-in — the initramfs loads the module so the kernel can then see the block device. Second, when the rootfs is encrypted — the initramfs runs the decryption setup before mounting. Third, for A/B partition selection — the initramfs contains logic to choose the correct root partition based on boot counters or flags. For simple embedded systems where all storage drivers are built-in and the rootfs is on a plain block device, you can skip initramfs entirely, which saves boot time and reduces complexity."
Q5: "How would you optimize boot time from 30 seconds to under 5 seconds?"
Model Answer Starter: "I would attack it in layers. First, the low-hanging fruit: add quiet to bootargs to suppress kernel messages (saves 0.5-1s), and run systemd-analyze blame to identify the slowest services — often network-wait and logging services can be deferred. Second, kernel pruning: run lsmod on the target to find which modules are actually needed, then rebuild the kernel with only those drivers built-in — this can save 2-5 seconds of module probing. Third, optimize the init sequence: start the main application early (before all services are up) and defer non-critical initialization. Fourth, if more speed is needed, consider U-Boot Falcon mode (SPL loads the kernel directly, skipping the full U-Boot stage) for another 1-2 seconds. The exact approach depends on where the time is spent — always measure first with grabserial or bootchart before optimizing."
Trap Alerts
- Don't say "U-Boot is just a bootloader" — it is a full development environment (network boot, scripting, environment variables, filesystem drivers)
- Don't forget
rootwait— without it, fast-booting kernels may panic because the storage device has not finished probing - Don't ignore the DTB — the kernel needs the device tree blob to know what hardware exists; without it, no platform devices probe and the system hangs silently
Follow-up Questions
- "What is U-Boot Falcon mode and what are the tradeoffs?"
- "How does the kernel know which device tree blob to use on a board with multiple hardware revisions?"
- "What happens if you set
init=/bin/shin bootargs? When is that useful?" - "How would you implement A/B partition switching in U-Boot?"
- "What is the difference between
zImage,Image, anduImage?"
Practice
❓ What does 'unknown-block(0,0)' mean in a kernel panic about root filesystem mounting?
❓ In the embedded Linux boot chain, what is the primary job of U-Boot SPL?
❓ Why is the 'rootwait' kernel parameter critical for eMMC and SD card boot?
❓ When can you safely skip using an initramfs in an embedded Linux system?
❓ Which U-Boot boot command is used for 64-bit ARM (AArch64) kernel images?
Real-World Tie-In
Industrial Gateway Boot Optimization — A factory automation gateway running on a Cortex-A7 with 256 MB RAM needed to reach its MQTT broker connection within 4 seconds of power-on. The team started at 28 seconds. They pruned the kernel from 2800 to 400 config options (saving 5s), switched from systemd to BusyBox init with a minimal rcS script (saving 8s), built all storage drivers as built-in to eliminate initramfs (saving 1s), added quiet and loglevel=0 (saving 1s), and started the MQTT application directly from inittab before network services finished initializing. Final boot: 3.2 seconds to first MQTT publish.
Automotive Fast-Boot with Rearview Camera — An automotive rearview camera system required video display within 2 seconds of ignition (regulatory requirement in some markets). The team used U-Boot Falcon mode (SPL loads kernel directly, skipping full U-Boot), a kernel stripped to only video, display, and camera drivers, and a minimal initramfs that started the camera application as PID 1 — no init system at all. The camera feed appeared in 1.6 seconds. Full Linux with connectivity services continued booting in the background via a switch_root to the real rootfs after the camera was active.