When an embedded Linux device boots slowly, an application does not start, a driver does not load, or a network service fails, people often jump straight to application logs.
But the application is only the last part of the boot chain. After power-on, the CPU does not directly jump to business logic. It starts from a fixed entry, initializes the minimal hardware environment, enters the bootloader, loads the Linux kernel, Device Tree, and rootfs-related information, waits for the kernel to reach user space, and only then reaches the application.
The safest first model is this: boot is not one function call. It is a staged handoff chain. Each stage brings the system to a state where the next stage can run.
power-on/reset
-> Boot ROM / early startup code
-> bootloader
-> Linux kernel
-> Device Tree / boot arguments
-> root filesystem
-> init / service manager
-> application services
Platform details vary, but the “each stage prepares the next stage” line is stable. Embedded Linux is special because the boot path crosses the bootloader, kernel, board description, rootfs, and user-space services; a failure in any of them can appear as “the application did not start.”
Where the CPU Starts After Reset
After power-on or reset, the CPU does not randomly search for code. It starts at the reset entry defined by the architecture and chip.
That entry may be:
- internal chip ROM
- flash at a fixed address
- reset handler in a vector table
- boot media selected by Boot ROM based on pins or fuses
The earliest code can rely on very little. The memory controller may not be initialized, stack may not be ready, clocks may still be at default rate, and peripherals are not configured.
Early startup code usually does minimal work:
- set up stack
- initialize clocks
- initialize SRAM or DRAM
- disable or configure watchdog
- set interrupt vector table
- clear BSS section
- prepare C runtime
- jump to the next stage
That is why early boot problems are hard to debug. Debug tools, serial logs, and even memory may not be ready yet.
What the Bootloader Solves
The bootloader’s job is not to run business logic. It brings the system to a state where it can load the operating system or main firmware.
It commonly handles:
- DRAM initialization
- storage controller initialization
- loading images from flash, eMMC, SD, network, or USB
- image integrity checks
- boot partition selection
- update rollback
- device tree or boot arguments
- jump to kernel or application entry
In Linux systems, the bootloader often loads the kernel, Device Tree, and initramfs/rootfs information.
So the bootloader is a handoff stage. It must understand both the hardware boot media and what the next stage needs.
Why Device Tree and Boot Arguments Matter
In many embedded Linux systems, the kernel image does not hardcode every board-level hardware detail. Device tree describes the hardware.
Device tree tells the kernel:
- CPUs, memory, and buses
- peripheral register addresses and interrupt numbers
- clock, reset, GPIO, and pinctrl configuration
- which devices are enabled or disabled
- board parameters needed by drivers
If the device tree is wrong, the kernel may boot while a device does not work:
- driver does not match the node
- interrupt number is wrong
- register address is wrong
- GPIO polarity is inverted
- clock is not enabled
- pinmux is not set to the right function
This can look like a driver bug, but the hardware description passed at boot may be wrong.
Boot arguments matter too. Root filesystem path, console, kernel log level, init program, and partition parameters can all decide whether the system reaches user space.
What Kernel Boot Does
After the Linux kernel takes over, it initializes its runtime environment.
Typical work includes:
- decompress or locate kernel image
- set up page tables and memory management
- initialize scheduler
- initialize interrupt system
- initialize timers
- initialize driver model
- parse device tree or ACPI
- mount root filesystem
- start the first user-space process
Kernel logs map to subsystems becoming available step by step.
If the system is stuck in the kernel stage, the application has not had a chance to run. Look at kernel logs, serial console, panic messages, rootfs mount errors, and driver probe errors, not application service logs.
Why Root Filesystem Is Critical for Linux Boot
After Linux reaches a certain point, it must mount the root filesystem.
The root filesystem contains:
/sbin/initor systemd- base libraries
- configuration files
- device nodes
- applications and service scripts
- mount points and runtime directories
If rootfs cannot be mounted, the kernel usually cannot enter normal user space.
Common causes include:
- wrong root device in boot arguments
- storage driver not loaded
- wrong partition table
- unsupported filesystem type
- corrupted rootfs
- init program missing or not executable
So “the kernel booted but the system did not” often means the failure is around rootfs or init.
What init and Service Management Do
After the kernel starts the first user-space process, the system enters user-space initialization.
On modern Linux, this is often systemd or another init system. It handles:
- mounting other filesystems
- creating device nodes or waiting for udev
- initializing network
- starting logging
- loading configuration
- starting services by dependency
- monitoring and restarting services
If the application did not start, the application itself is not always broken. Its dependencies may not be ready:
- network is not ready
- data partition is not mounted
- device node has not appeared
- permission is wrong
- prerequisite service failed
- environment variable or configuration is missing
The service manager cares about dependency graphs. Startup order is not simply filename or script order; it depends on service relationships and conditions.
Why Update and Rollback Belong to Boot
Devices do not only boot once. They often support OTA, dual partitions, rollback, and secure boot.
That adds decisions to the boot chain:
- boot A partition or B partition
- whether the new image passes verification
- whether the previous boot was marked successful
- whether failure count exceeded threshold
- whether to roll back to old version
- whether signature or hash is trusted
These decisions usually happen in the bootloader or early user space.
If this layer is not robust, the device may:
- fail to boot after update
- flip between old and new versions
- brick after boot marker corruption
- bypass security verification
- get stuck in a half-updated state after power loss
Boot is not only “run the system.” It decides which version to run and whether there is a recovery path.
Debug Boot Problems by Locating the Stage
The worst way to debug boot is to modify the application first.
First locate the stage:
- no logs at all: power, reset, clock, boot media, early ROM, or serial setup
- bootloader logs exist: image loading, verification, partition choice, device tree, boot arguments
- early kernel logs exist: memory, device tree, panic, interrupts, clocks, driver probe
- stuck at rootfs: root argument, storage driver, partition, filesystem, init
- user space entered but service not started: init/systemd logs, dependencies, permissions, device nodes, configuration
- service started but business unavailable: network, peripherals, database, config, application logs
Each stage has different observation points. Once the stage is known, the problem scope shrinks quickly.
What to Remember in Practice
From power-on to application start, the device does not jump straight to business code. It runs through a handoff chain.
Early startup prepares the minimal runtime environment. The bootloader loads and selects the next stage. The Linux kernel establishes scheduling, memory, interrupts, and device models, then mounts rootfs, starts init, and starts services by dependency.
For boot problems, ask:
- did the CPU reach the reset entry
- did the bootloader load the correct image
- are device tree and boot arguments correct
- did the kernel finish initialization
- did rootfs mount
- did init start
- are application dependencies satisfied
Splitting the boot chain by stages turns “the device did not start” into a path that can be verified step by step.