A bootloader is the first piece of software that runs when a device is switched on. The processor wakes up knowing almost nothing: memory may be uninitialized, peripherals are unconfigured, and there is no operating system yet. The bootloader’s job is to bring the machine from that raw state to one where a real program, usually an operating system kernel, can be loaded and started. It is the bridge between bare silicon and running software.
The canonical open-source example is Das U-Boot, the Universal Boot Loader, used across an enormous range of embedded devices and processor architectures. Its documentation describes it as a loader that initializes the hardware and loads the device’s operating system, but adds that U-Boot is “more than a simple boot loader”: it provides an interactive command-line shell that lets users and developers load and boot a kernel from many sources, including flash memory, SD cards, SATA drives, or over a network using TFTP. That flexibility is why U-Boot dominates the embedded Linux world.
Booting is rarely a single step. On constrained hardware the very first code must fit in a tiny on-chip memory before main DRAM even works, so booting is split into stages. U-Boot’s documentation describes this multi-stage model with a Tertiary Program Loader (TPL), Secondary Program Loader (SPL), and U-Boot proper. The early stages are deliberately minimal: TPL is “as tiny as possible” and is responsible for DRAM initialization, after which SPL “sets up SDRAM and loads U-Boot proper.” Each stage initializes a little more of the system and hands off to the next, climbing from a few kilobytes of scratch memory up to a full-featured loader.
This staged pattern mirrors how general-purpose computers boot. A small immutable boot ROM or BIOS runs first, locates a bootloader on disk, and that loader in turn loads the operating system. The microcontroller world has its own miniature version: the Arduino bootloader is a small program pre-burned into the chip that lets new sketches be uploaded over a serial connection without dedicated hardware, then jumps to the freshly loaded user code. In every case the principle is the same, a chain of progressively more capable loaders.
Because the bootloader runs before any operating system, it operates with complete control and no safety net. It configures clocks and memory controllers, often sets up the watchdog, and may verify the integrity and signature of the image it is about to run. A compromised or buggy bootloader can render a device unbootable, which is why this code is small, carefully written, and frequently stored in a protected or read-only region.
The bootloader is thus the foundation of trust and function for everything above it. It is short-lived, running only for the moment between power-on and handoff, but nothing else can run until it has done its work.