A bootloader is a small program that runs when an ARM-based system first powers on. It is responsible for initializing hardware, validating firmware, and loading the operating system. The bootloader plays a crucial role in the boot process on ARM devices like smartphones, tablets, and embedded systems.
Main Functions of an ARM Bootloader
The primary jobs of an ARM bootloader include:
- Initializing the processor and hardware – The bootloader sets up essential hardware like DRAM and clocks to get the system into a usable state.
- Establishing the stack – It sets up a stack for further execution. This provides memory for other software components to run.
- Locating, validating, and loading the kernel – It finds the kernel image, verifies integrity by checksums, and copies it to RAM.
- Passing control to the kernel – Finally, it jumps to the kernel’s entry point to begin normal OS boot.
The bootloader may also initialize peripherals, load device trees, and pass information like the system memory map to the kernel. Optionally, it can implement security features like encrypted boot. Overall, the ARM bootloader brings up the hardware and firmware to a state where loading the actual OS is possible.
There are two common types of bootloaders used with ARM systems:
The primary bootloader executes first after resetting the ARM processor. As it runs in a limited environment, primary bootloaders are compact programs focused on initializing key hardware and locating the secondary bootloader. For example, U-Boot SPL (Secondary Program Loader) is a widely used primary bootloader.
Primary bootloaders may reside in ROM or flash chips. They run in either ARM or Thumb execution states. Startup code in Cortex-M microcontrollers can also be viewed as a primary bootloader.
Secondary bootloaders offer more functionality for loading the OS compared to primary bootloaders. They can initialize more complex peripherals, load larger device trees, and include features like scripting or a command line interface.
U-Boot proper is a popular open source secondary bootloader. Others like Trusted Firmware-A and UEFI are also used. Secondary bootloaders normally run from RAM and use higher level languages like C.
A typical ARM boot sequence involves several stages:
- Reset – The processor comes out of reset and CPU registers get initialized.
- First stage bootloader – A minimal primary bootloader sets up DRAM and clocks.
- Second stage bootloader – The secondary bootloader runs from RAM and initializes devices.
- Kernel boot – The bootloader loads the kernel image into memory and passes control to it.
- Initialization – The kernel initializes the OS and launches initial processes.
Optional stages may exist as well, like an initial machine mode stage before the first bootloader. The boot sequence can also progress linearly or have more branching points.
Developing a bootloader for ARM involves dealing with constraints like:
- Limited environment – Initial bootloaders must load quickly without OS support.
- Memory restrictions – Small RAM sizes are common in embedded ARM designs.
- Hardware diversity – Supporting the wide variety of ARM-based platforms is difficult.
- Security – Attackers often target bootloaders, so security is a prime concern.
Teams spend significant time building, testing, and validating bootloaders. While some general frameworks exist, achieving robust boot sequences requires customization for ARM platforms.
ARM Bootloader Development
Engineers use different techniques to build ARM bootloaders including:
- Bare metal code – The bootloader is handwritten in C/assembly without the help of an OS.
- Libraries – Bootloader frameworks like ARM Trusted Firmware provide reusable modules.
- Chainloading – Multiple small bootloader stages chainload each other to minimize individual complexity.
- Configuration – Toolchains auto-generate bootloader code from platform descriptions.
For prototyping, QEMU user mode emulation allows testing ARM bootloaders on a Linux host computer. This avoids needing real hardware in the early development phases.
Bootloader Best Practices
Experts recommend several practices when architecting ARM boot sequences:
- Minimize boot time by deferring complex tasks until later stages.
- Reduce size using efficient coding techniques in primary bootloaders.
- Validate supplied data to prevent security issues.
- Allow fallbacks to known good images in case of boot failures.
- Test thoroughly and audit code since bootloaders are security critical.
Following industry guidelines for designing and hardening bootloaders enhances reliability and security.
ARM Bootloader Example Walkthrough
Here is an overview of a typical ARM boot sequence on a smartphone:
- The application processor resets, running first stage ROM code.
- This ROM code locates and verifies the secondary bootloader in flash.
- The secondary bootloader initializes DRAM and loads the Linux kernel image.
- It passes control to the kernel, which decompresses itself into RAM.
- The kernel mounts the root filesystem from flash storage.
- Userspace init processes then start launching daemons and applications.
Optional steps like loading a device tree binary or checking signatures can also occur. This example shows the staged bring up process directed by the ARM bootloader.
Bootloader Relationship with Kernel
The ARM bootloader and Linux kernel work closely together during system startup. Key ways they interact include:
- The bootloader finds the kernel image in storage, validates it, and copies it to RAM.
- It parses information like the machine ID, kernel command line, and RAM disk out of the kernel image.
- Board details like memory layout get passed from the bootloader to kernel.
- The bootloader may also load and unpack the device tree blob used by Linux.
- Handoff to the kernel happens by jumping to its defined entry point.
Parameters from the bootloader influence how the kernel configures itself. The kernel build system integrates with the bootloader to generate images bootable on a platform.
Bootloader Interaction with Other Firmware
In addition to the kernel, ARM bootloaders may load other firmware images including:
- Runtime firmware – Loads components like microcode and vendor libraries.
- Baseband firmware – Handles modem and wireless connectivity.
- Coprocessor firmware – Manages optional processing units.
- Sensor firmware – Boots code for sensor hubs and camera ISPs.
- Graphics drivers – Sets up firmware for GPUs.
The bootloader is the common starting point for all processor and device firmware. It acts as the foundation launching other program images.
The ARM bootloader plays a critical role in starting up an ARM system like a phone, IoT device, or server. It initializes hardware, validates firmware, and kicks off the kernel and OS boot process. Bootloader challenges like security prompted innovations including trusted boot. As ARM platforms continue diversifying, the flexibility of the bootloader architecture enables supporting this vast ecosystem.