Operating Systems
The Boot Process (Firmware to Kernel)
Power-on to PID 1 — a chain of trusted handoffs
The boot process is the ordered chain of handoffs that turns a powered-off machine into a running operating system: the CPU comes out of reset executing firmware (BIOS or UEFI) from a fixed reset vector, POST validates and initializes the hardware, the firmware loads a bootloader such as GRUB from an MBR or GPT disk, the bootloader loads and decompresses the kernel plus an initramfs into RAM, and the kernel finally hands off to /sbin/init — systemd — running as PID 1. Each stage does just enough to find, verify, and start the next, and modern firmware uses Secure Boot to cryptographically check every link before it runs.
- First code to runFirmware at the CPU reset vector
- x86 reset vector0xFFFFFFF0 (top of 4 GiB)
- Legacy MBR load address0x7C00, 512-byte sector
- First userspace processinit / systemd = PID 1
- Firmware familiesBIOS (1975) · UEFI (2005)
- Partition schemesMBR (≤2 TB) · GPT (≤8 ZiB)
Interactive visualization
Press play, or step through manually. The visualization is yours to drive — try it before reading on.
Watch the 60-second explainer
A condensed visual walkthrough — narrated, captioned, under a minute.
Why the boot process matters
Booting is the one problem every computer solves the same way, billions of times a day, and almost nobody watches. It is a bootstrapping problem in the literal sense — the phrase "pull yourself up by your bootstraps" — because the machine must run software before any of its own software has loaded. The CPU wakes with no operating system, no drivers, and no filesystem it knows how to read. Getting from that blank state to a login prompt is a carefully staged relay race, where each runner carries the baton just far enough to hand it to a slightly more capable successor.
The staging is not arbitrary. Firmware is tiny, hardware-specific, and stored in flash — it cannot contain a full OS. So it does the minimum: wake the hardware and find a bootloader. The bootloader understands filesystems the firmware does not, but it still cannot mount an encrypted RAID root — so it hands off to a kernel that carries an initramfs full of exactly the drivers needed. Understanding this chain is what lets you fix a machine that shows a black screen, a "no bootable device" message, or drops you to an initramfs emergency shell. Every one of those failures maps to a specific link in the chain.
How it works, stage by stage
On x86, control flows through roughly six stages. Each ends with a jump into the next stage's entry point — a handoff.
- Power-on and reset. When power stabilizes, the CPU is held in reset until the power-good signal asserts. On release, every x86 core begins executing at the reset vector — physical address
0xFFFFFFF0, 16 bytes below the top of the 4 GiB space — which the chipset aliases to the firmware flash. The very first instruction is almost always a jump into the real firmware. - Firmware & POST. BIOS or UEFI runs the Power-On Self-Test: initialize the CPU and cache, train and test DRAM, bring up the chipset, enumerate PCIe/USB/NVMe, and build the ACPI and SMBIOS tables and a memory map the OS will later consume. A fatal fault here is reported by beep codes or POST codes, since there is no OS to print to a console.
- Boot device selection & bootloader load. The firmware consults its boot order. Legacy BIOS reads the first 512-byte sector (the MBR) of the chosen disk into memory at
0x7C00and jumps to it. UEFI instead mounts the FAT-formatted EFI System Partition (ESP) and executes a.efiapplication named in an NVRAM boot entry — for Linux, typicallyshimthengrubx64.efi. - Bootloader (GRUB). GRUB understands ext4, XFS, Btrfs, LVM, and more. It reads its config, presents a menu, and locates the kernel image and initramfs on the boot filesystem. On BIOS systems GRUB is split into stages (boot.img → core.img → modules) because 446 bytes of MBR code cannot hold a filesystem driver; the tiny stage-1 chain-loads the larger stages.
- Kernel load, decompress & setup. GRUB loads the compressed kernel (
bzImage) and the initramfs into RAM, sets up the boot parameters, and jumps to the kernel's setup stub. The self-extractor decompresses the kernel to its final address, then the kernel initializes memory management, the scheduler, and built-in drivers, and unpacks the initramfs into a tmpfs. - init / systemd (PID 1). Userspace in the initramfs finds, assembles, decrypts, and mounts the real root filesystem, then
switch_rootpivots onto it andexecs the real/sbin/init. That process is PID 1. systemd reads its units, brings up targets in dependency order, mounts filesystems, starts services, and eventually reachesgraphical.targetor a login prompt.
The invariant that makes the whole thing work: at every handoff, the outgoing stage has placed the incoming stage's code in memory and jumps to a well-defined entry point, passing along a small blob of state — the memory map, the ACPI pointer, the kernel command line. Nothing is loaded that hasn't first been located and prepared by the previous, less-capable stage.
BIOS vs UEFI: two firmware worlds
The single biggest fork in the boot road is which firmware you have. Legacy BIOS is 16-bit real-mode code that predates almost everything; UEFI is a specification with drivers, a boot manager, and cryptographic verification. The differences ripple through every later stage.
| Legacy BIOS | UEFI | |
|---|---|---|
| CPU mode at handoff | 16-bit real mode | 32/64-bit protected/long mode |
| Boot data on disk | MBR sector 0 (512 bytes) | .efi files on the FAT32 ESP |
| Partition scheme | MBR (≤ 2 TB, 4 primaries) | GPT (≤ 8 ZiB, 128 entries) |
| Bootloader location | MBR + subsequent sectors | Named entry in NVRAM → ESP |
| Secure Boot | No | Yes (PK/KEK/db/dbx) |
| Boot menu / manager | None (hand-rolled) | Built-in, editable entries |
| Network boot | PXE add-on | Native (HTTP/PXE) in spec |
| Introduced | 1975 (IBM/CP-M lineage) | 2005 (Intel EFI → UEFI Forum) |
Most UEFI firmware includes a Compatibility Support Module (CSM) that emulates a legacy BIOS environment, so an old MBR-based OS can still boot. Disabling the CSM forces pure UEFI booting — and is usually required to enable Secure Boot.
The boot chain as pseudocode
Stripped of hardware detail, the entire relay is a loop of "load the next stage, verify it, jump to it." Here is the UEFI + Linux path expressed as pseudocode:
# --- Stage 0: hardware brings the CPU out of reset ---
cpu.pc = 0xFFFFFFF0 # x86 reset vector, aliased to firmware flash
run(firmware) # jump into UEFI/BIOS
# --- Stage 1: firmware ---
def firmware():
post() # init + test CPU, DRAM, chipset, buses
build_tables() # ACPI, SMBIOS, UEFI memory map
for entry in nvram_boot_order(): # e.g. "ubuntu" -> \EFI\ubuntu\shimx64.efi
efi = read_from_esp(entry.path) # ESP is a FAT32 partition
if secure_boot_enabled and not verify_signature(efi, db, dbx):
continue # signature not trusted or revoked -> skip
return handoff(efi) # execute the .efi bootloader
halt("No bootable device")
# --- Stage 2: bootloader (shim -> GRUB) ---
def grub():
cfg = read_fs("/boot/grub/grub.cfg") # GRUB understands ext4/xfs/btrfs
choice = show_menu(cfg) or cfg.default
kernel = load_file(choice.kernel) # compressed bzImage
initrd = load_file(choice.initrd) # cpio.gz initramfs
cmdline = choice.cmdline # e.g. "root=UUID=... ro quiet"
verify_signature(kernel) # Secure Boot: shim checks the kernel
return handoff(kernel, initrd, cmdline)
# --- Stage 3: kernel ---
def kernel(initrd, cmdline):
self_decompress() # setup stub extracts the real kernel into RAM
init_mm(); init_sched(); init_builtin_drivers()
unpack(initrd, into="/") # populate a tmpfs as the temporary root
exec("/init") # first userspace program, still on initramfs
# --- Stage 4: initramfs userspace ---
def initramfs_init():
load_modules("nvme", "dm-crypt", "raid", "lvm") # drivers for the real root
real_root = find_and_assemble(cmdline["root"]) # LUKS unlock, RAID/LVM assemble
mount(real_root, "/sysroot")
switch_root("/sysroot", "/sbin/init") # pivot; exec real init as PID 1
# --- Stage 5: PID 1 ---
def systemd(): # this process has pid == 1
assert getpid() == 1
read_units("/etc/systemd/system", "/usr/lib/systemd/system")
reach_target("graphical.target") # mounts, services, login
reap_orphans_forever() # PID 1 must wait() on re-parented children
Notice the two escape hatches that cause the most support tickets: the halt("No bootable device") when nothing valid is found, and the moment find_and_assemble fails and drops you to an initramfs (initramfs) emergency shell because the root couldn't be located or decrypted.
Secure Boot and the chain of trust
Secure Boot answers a pointed question: if malware replaces your bootloader, how would you ever know? The firmware would happily run the tampered loader before any antivirus could exist. Secure Boot inserts a signature check before each executable runs. Firmware stores a hierarchy of keys — the Platform Key (PK) owned by the OEM, Key Exchange Keys (KEK), an allowed-signatures database db, and a revocation list dbx. Before launching any .efi, the firmware verifies its signature chains to db and is absent from dbx.
On Linux the practical trick is shim: a minimal first-stage loader signed by Microsoft's UEFI CA (which nearly every OEM trusts in db). Shim then verifies GRUB and the kernel against the distribution's own embedded key or a locally-enrolled Machine Owner Key (MOK). The result is an unbroken chain: firmware → shim → GRUB → kernel → signed modules. Crucially, Secure Boot proves authenticity and integrity, not confidentiality — it does not encrypt the disk. For that you add full-disk encryption (LUKS), often anchored to a TPM and to the boot measurements the firmware records.
Common misconceptions and pitfalls
- "UEFI is just a fancier BIOS menu." It is a different architecture: a driver-based runtime with its own executable format, boot manager, and NVRAM variables. The blue setup screen is one small part.
- "Secure Boot encrypts my drive." No — it verifies signatures. An unencrypted disk with Secure Boot on is still fully readable if the drive is removed. Encryption is a separate layer (LUKS/BitLocker).
- "The MBR is the bootloader." The 446 bytes of MBR boot code are only stage 1. It is far too small to hold a filesystem driver, so it chain-loads larger stages stored elsewhere on disk.
- "initramfs is the real root filesystem." It is a temporary, in-RAM root whose only job is to find and mount the real root, then get out of the way via
switch_root. It disappears from the mount table afterward. - "You can safely kill PID 1 like any process." The kernel ignores signals sent to PID 1 that lack an installed handler, and if PID 1 ever actually exits, the kernel panics. It is deliberately un-killable.
- "GPT and MBR are interchangeable formats." Firmware mode and partition scheme are coupled in practice: UEFI expects GPT + an ESP, legacy BIOS expects MBR boot code. Mixing them (GPT on pure BIOS, or MBR under Secure-Boot UEFI) is where "installed fine, won't boot" bugs live.
A short history of the handoff
The 512-byte MBR is a fossil of 1983 — the size of a floppy sector, with room for exactly four partition entries because that was generous at the time. That "temporary" limit shaped disk layouts for three decades and only fell when 2 TB drives made its 32-bit sector count unworkable. GPT arrived with Intel's EFI in the late 1990s to lift the cap, and EFI became the industry-standard UEFI in 2005. Meanwhile the init system evolved from the sequential SysV rc scripts of 1983 Unix, to Upstart's event model, to systemd (2010), which parallelized boot by expressing services as a dependency graph and starting everything it could at once. Each layer was replaced not for fashion but because a hard limit — disk size, boot time, hardware complexity — finally made the old design untenable. The relay itself, firmware → loader → kernel → init, has stayed remarkably constant since the first minicomputers.
Frequently asked questions
What is the difference between BIOS and UEFI?
BIOS is 16-bit real-mode firmware from 1975 that boots by loading the first 512-byte sector (the MBR) into memory at 0x7C00 and jumping to it. UEFI is a modern 32/64-bit firmware specification that runs a driver-based environment, reads a FAT-formatted EFI System Partition, and directly executes .efi bootloader files it finds there. UEFI supports GPT disks larger than 2 TB, Secure Boot, a boot manager with named entries in NVRAM, and network booting — none of which classic BIOS provides. Most UEFI firmware also offers a Compatibility Support Module (CSM) that emulates BIOS for legacy operating systems.
What does POST do during boot?
POST (Power-On Self-Test) is the firmware's first job after the CPU comes out of reset. It initializes and sanity-checks the CPU, memory controller, and core chipset, trains the DRAM, enumerates buses (PCIe, USB, SATA/NVMe), and builds tables the OS will later read (ACPI, SMBIOS, memory map). If a fatal fault is found — bad RAM, no display adapter — the firmware signals it with beep codes or POST codes because there is no OS yet to print an error. Only after POST succeeds does the firmware look for something to boot.
What is the difference between MBR and GPT?
MBR (Master Boot Record) is the legacy partitioning scheme: a single 512-byte sector holding 446 bytes of boot code, a 4-entry partition table, and the 0x55AA signature. It caps disks at 2 TB (32-bit LBA) and allows only four primary partitions. GPT (GUID Partition Table) is the UEFI-era replacement: it uses 64-bit LBAs (supporting disks up to 8 ZiB), typically 128 partition entries, CRC32 checksums on its headers, and a backup copy at the end of the disk. GPT also keeps a 'protective MBR' in sector 0 so old tools don't mistake the disk for empty.
What is initramfs and why is it needed?
initramfs (initial RAM filesystem) is a compressed cpio archive the bootloader loads into memory alongside the kernel. The kernel unpacks it into a tmpfs that becomes the temporary root filesystem. It exists to solve a chicken-and-egg problem: the real root filesystem may live on an NVMe drive, an LVM volume, a RAID array, or an encrypted (LUKS) partition whose drivers are not built into the kernel. The initramfs carries exactly those drivers and a small userspace so it can find, assemble, decrypt, and mount the real root, then pivot to it and exec the real init.
Why is init always PID 1?
PID 1 is the first userspace process the kernel starts, and by convention it is the init system (today usually systemd). It gets PID 1 because it is spawned first, and Linux gives it special status: it can never be killed by ordinary signals, and it becomes the reaper for orphaned processes — when any process's parent dies, the kernel re-parents the orphan to PID 1, which must call wait() to clear its exit status and prevent zombies. If PID 1 ever exits, the kernel panics because there is nothing left to manage userspace.
How does Secure Boot verify the boot chain?
Secure Boot is a UEFI feature that checks a digital signature on each executable before running it. Firmware holds a Platform Key (PK), Key Exchange Keys (KEK), and an allow/deny database (db/dbx). Before launching a bootloader (.efi), the firmware verifies its signature chains to a key in db and is not revoked in dbx. On Linux this is usually satisfied by 'shim', a small Microsoft-signed loader that then verifies GRUB and the kernel against a distro key. It establishes a chain of trust but does not encrypt anything — it only proves that each stage was signed by a trusted key and not tampered with.
Why does the kernel arrive compressed and how is it decompressed?
The kernel image (bzImage on x86) ships compressed — typically with gzip, LZ4, zstd, or xz — to save disk space and shorten the slow load from firmware into memory. The image has a small uncompressed 'real-mode/setup' stub prepended to it. The bootloader loads the whole bzImage, the firmware/bootloader jumps to that stub, and the stub's self-extractor decompresses the actual kernel into its final location in RAM before jumping to the kernel entry point. It is a classic trade: spend a few CPU-milliseconds decompressing to avoid moving a much larger image off disk.