Power-on, firmware, boot
Pressing the power button doesn't start the CPU running your code. It starts a multi-second cascade of microcontrollers, firmware blobs, security checks, and DRAM training before the main CPU ever fetches its first instruction. Modern computers have at least three independent processors that run before the OS does — the main CPU, a Management Engine, and various peripheral controllers. Understanding this layer is the difference between debugging a flaky machine and watching it boot into a black screen for the third time.
Nine phases, end to end
From the moment the power button closes the circuit to the moment the login prompt appears, a modern PC traverses roughly nine distinct phases, and it skips none of them. The phases form a relay. Each stage does just enough to find, verify, and start the next, then steps out of the way. No single piece of code runs the whole boot; control is handed from silicon mask ROM to firmware to a bootloader to the kernel to the first user-space process, and each handoff is a point where things can go right or fail in a way that looks, from the screen, like "nothing happened."
The mental model that helps most is this: boot is not one program starting. It is a chain of small programs, each loading the next from a slower, larger store into a faster one, until finally a real operating system is resident in RAM and running. The firmware lives in a tiny flash chip soldered to the board. The bootloader lives on disk. The kernel lives on disk. Each step copies the next stage into memory, checks it is what it claims to be, and jumps to it. Hold that picture and the rest of this page is just detail.
| # | Phase | Duration | What happens |
|---|---|---|---|
| 1 | Power-on reset | ~ms | Power supply stabilises voltage rails. CPU pins held in reset until clocks lock. PCH releases the reset signal once everything is ready. |
| 2 | Microcode load | ~ms | CPU loads its built-in microcode ROM. Modern Intel/AMD chips support runtime microcode patches; if a signed update is in firmware, it loads here. |
| 3 | Pre-firmware (ME / PSP) | ~100s ms | On Intel: the Management Engine boots a separate ARC/x86 core running its own OS. On AMD: the Platform Security Processor. These run before the main CPU does. |
| 4 | BIOS/UEFI early init | ~1 s | Main CPU starts in 16-bit real mode (legacy) or directly in long mode (UEFI). Initializes DRAM controller, sets up memory training, runs SMBus probes for hardware identification. |
| 5 | POST | ~1–10 s | Power-On Self-Test. Probes CPUs, memory, PCIe devices. Builds the ACPI tables that describe the hardware to the OS. |
| 6 | Boot device selection | ~ms | Reads the boot order from NVRAM. UEFI looks for an EFI System Partition; legacy BIOS reads the MBR. |
| 7 | Bootloader | ~ms | GRUB / systemd-boot / Windows Boot Manager / Apple iBoot. Reads the kernel image and initrd from disk into memory. Hands off control. |
| 8 | Kernel init | ~1–3 s | Kernel runs its early init: enables paging, brings up additional CPU cores, mounts the root filesystem, runs init/systemd. |
| 9 | User-space init | ~1–10 s | systemd / launchd / SMSS starts services in parallel. Login prompt appears. |
The reset vector
On x86, the CPU starts executing from a hardcoded address: 0xFFFFFFF0
— sixteen bytes from the top of 4 GB. The motherboard chipset arranges for the
BIOS/UEFI ROM to be mapped there at boot, so the first instruction the CPU
fetches is the firmware's entry point. On ARM the equivalent is the
reset vector at the start of the SoC's boot ROM, which is
small mask-programmed silicon (4–64 KB) that lives forever and contains just
enough code to load the next stage from external flash.
There is nothing special about that first instruction from the CPU's point of view. It runs the same fetch-decode-execute loop it will run for the rest of its life (the instruction cycle does not change because the machine just powered on). The only thing the reset vector does is guarantee a known starting program counter so that the chip, which has no idea what is on its disks, always begins at code the board vendor put in a place it can reach. Everything after that first instruction is software deciding what to run next.
On Apple silicon Macs, the boot ROM is signed and immutable. It loads
iBoot from a secure storage area, which loads the kernel. The
Secure Enclave bootstraps in parallel and verifies every step. There's no
"BIOS shell" to drop into and no equivalent of UEFI variables — the entire
chain is locked down end to end.
DRAM training
Bringing up DDR memory is one of the slowest parts of boot. The memory controller doesn't know the timing characteristics of the installed DIMMs in advance — it has to train them by sweeping a range of voltages, frequencies, and delay-line settings, looking for the values where signals are stable. This can take 1–10 seconds per channel on server hardware with 12-channel DDR5.
The trained values are cached in NVRAM so the next boot is faster ("warm boot"), but a cold boot or BIOS update reruns the full training. Datacenter operators notice this when rebooting a 2 TB-of-RAM server takes longer than they expect — most of the wall-clock time is DRAM training, not OS init.
Firmware lineage
| Firmware | Size | Era | Notes |
|---|---|---|---|
| Legacy BIOS | ~1–4 MB | 1980s–2010s | 16-bit real mode at boot. MBR-only. Limited to ~2 TB disks. Mostly retired. |
| UEFI | ~16 MB | 2010s–today | Standard on every modern x86 PC and server. Supports GPT, Secure Boot, network boot. |
| Coreboot | ~256 KB | 2000s–today | Open-source BIOS replacement. Used on Chromebooks, some servers, Framework laptops. |
| Open Firmware | ~512 KB | 1990s–2000s | IEEE 1275, Forth-based. Used on PowerPC Macs and Sun servers. |
| iBoot (Apple) | ~4 MB | iPhone/Mac | Apple's custom bootloader for iOS, iPadOS, and Apple silicon Macs. Tightly integrated with Secure Enclave. |
| OpenSBI | ~256 KB | 2020s–today | RISC-V Supervisor Binary Interface. Equivalent of UEFI for RISC-V boards. |
UEFI is what almost every modern PC and server runs. Inside, it's a roughly POSIX- like environment with a shell, file system access (FAT32 typically), a network stack, and pre-OS drivers. UEFI is itself an OS, small and real-mode-free, and it is intended to hand off to a "real" OS, but it can run before any kernel boots.
Finding the boot device
Once POST is done and the hardware is described, the firmware has to decide what to boot. This is the moment the two worlds diverge sharply, and it is worth seeing both side by side because most engineers learned one and then quietly assumed the other worked the same way.
On legacy BIOS, the firmware reads the very first 512-byte sector of
the boot disk: the Master Boot Record (MBR). The first 446 bytes of that sector are
executable code; the next 64 bytes are the partition table; the last two bytes are a
magic signature (0x55AA) that tells the BIOS "yes, this is bootable." The
BIOS copies those 446 bytes to a fixed address (0x7C00) and jumps to them.
That is all the room there is. 446 bytes cannot load a kernel, so MBR code is just a
stub whose only job is to find and load a bigger bootloader from elsewhere on the disk.
This is why old-school booting has "stages": there is no space to do it in one shot.
On UEFI, there is no magic 512-byte sector. The firmware understands the
GUID Partition Table and the FAT32 filesystem directly. It looks for an EFI System
Partition, opens it like a normal disk, and runs a regular file: a .efi
executable, usually at a well-known path such as
\EFI\BOOT\BOOTX64.EFI. There is no tiny assembly stub, no chain of
cramped stages. The bootloader is just a program the firmware knows how to run, which
is why UEFI bootloaders can be large, written in C, and even ship their own drivers.
The bootloader, in stages
The bootloader's one job is to find a kernel, load it into memory along with an initial ramdisk, set up the handoff data the kernel expects, and jump to it. The best-known example on Linux is GRUB (the GRand Unified Bootloader), and its internal structure is a clean illustration of why this is harder than it sounds.
On a legacy install, GRUB is split into pieces that match the space available at each
point. stage 1 is the 446-byte MBR stub. It is too small to understand
a filesystem, so all it knows is a hardcoded disk sector to load next. That sector holds
stage 1.5, which lives in the gap between the MBR and the first
partition and contains just enough filesystem code to read files by name. stage 1.5 then
loads stage 2, the full GRUB: the menu you see, the config parsing, the
ability to read /boot/grub/grub.cfg, edit kernel command lines, and load the
kernel and initrd. On a UEFI install the dance collapses: GRUB is a single
grubx64.efi file the firmware runs directly, with no stages, because the
firmware already handed it a working filesystem.
Whatever the path, the bootloader ends the same way. It loads the kernel image, loads the initramfs (a compressed cpio archive containing a minimal root filesystem with just enough tools and drivers to find and mount the real root), fills in a structure describing memory, the command line, and the firmware tables, and transfers control to the kernel's entry point. From that instruction on, the firmware and bootloader are done. They will not run again until the next boot.
Kernel init and the handoff to PID 1
When the bootloader jumps to the kernel, the machine is still half-built. Early kernel init is the kernel finishing the job: it sets up its own page tables and turns on paging so the rest of the kernel can run in the virtual address space it expects (the same virtual memory machinery every later process relies on), parses the firmware-provided memory map, sets up interrupt handling, initialises the scheduler, and brings the other CPU cores online (see "Bringing up additional cores" below). It decompresses and unpacks the initramfs into a RAM filesystem and mounts it as the temporary root.
Then comes the most important handoff of the whole sequence. The kernel runs the init
program out of the initramfs, which loads the drivers needed for the real root device,
unlocks and mounts the real root filesystem, and then performs a pivot_root to
switch the root from the throwaway ramdisk to the real disk. Finally the kernel executes the
real init binary, conventionally at /sbin/init, as process number 1. From here
the kernel never starts another top-level process directly. Everything else, every daemon,
every login shell, every browser, descends from PID 1 by being forked
(how processes are
created and managed is its own topic). If PID 1 ever dies, the kernel panics, because
there is nothing left to parent the system.
On most Linux systems PID 1 is systemd, which reads unit files describing
services and their dependencies and starts as many as it can in parallel, which is a large
part of why modern Linux boots faster than the old sequential SysV init scripts that ran one
shell script after another. On macOS the equivalent is launchd; on older Unix
it was the SysV init with its numbered runlevels; on Windows the chain runs
through the Session Manager (smss.exe) into wininit.exe and the
service control manager. Different names, same shape: one privileged ancestor process that
brings up everything else and then stays resident as the root of the process tree for the
life of the machine.
Microcode — the silicon's patch layer
Modern x86 chips internally translate complex instructions into RISC-shaped µops. The translation is implemented in microcode — firmware that lives in the CPU's microcode ROM. Most µops come from a fast hardwired path, but rarely- used or particularly complex instructions (CPUID, RDTSC, REP MOVSB strings) come from microcode.
Critically: the microcode is patchable at runtime. The CPU vendor publishes signed updates that the BIOS/UEFI loads at boot, and the OS reloads at every boot afterward. This is how Spectre, Meltdown, Zenbleed, Downfall, Reptar, and dozens of other CPU bugs have been mitigated without swapping silicon. Microcode updates are the security industry's most underrated patch path — they're what keeps ten-year-old chips secure against new vulnerabilities.
The hidden coprocessors
Modern computers run multiple processors before, alongside, and after the main CPU. Most users never see them. Most are unkillable. Some have been the source of significant security disclosures.
| Coprocessor | Role |
|---|---|
| Intel Management Engine (ME) | ARC core (older), x86 mini-core (recent). Runs Minix-based firmware. Implements AMT (remote management), Boot Guard, anti-theft. Cannot be disabled completely on most chips. Critical CVEs in 2017 (SA-00086) prompted disclosure debates. |
| AMD Platform Security Processor (PSP) | ARM Cortex-A5 inside every Zen and post-Zen chip. Runs trustlets for cryptographic operations. Equivalent role to Intel ME. |
| Apple Secure Enclave | Separate ARM core on the Apple SoC. Manages TouchID/FaceID, Apple Pay keys, FileVault. Communicates with main CPU via mailbox protocol; runs sepOS. |
| Baseboard Management Controller (BMC) | On servers: a separate ARM SoC (e.g., AST2600) running OpenBMC or vendor firmware. Provides IPMI / Redfish / KVM-over-LAN. Fully independent of the main CPU. |
| Embedded Controller (EC) | On laptops: a separate microcontroller managing keyboard, fans, battery charging, lid switch, power button. Runs its own firmware, often customizable on Chromebooks via System76 EC or Framework EC. |
On a typical Lenovo or Dell business laptop in 2026, there are at minimum: the main CPU + integrated GPU, the Management Engine (Intel) or PSP (AMD), the Embedded Controller, the WiFi card's microcontroller, the SSD's controller, the Thunderbolt controller, the trackpad's microcontroller, and possibly a TPM. Eight to twelve programmable processors per machine, only one of which the OS controls.
Secure Boot and the chain of trust
Secure Boot is UEFI's mechanism for verifying that every stage of boot is signed by a trusted authority. The UEFI firmware contains a list of trusted public keys (Microsoft's, the OEM's, optionally the user's). When loading the bootloader, UEFI verifies its signature against those keys; the bootloader verifies the kernel; the kernel verifies its modules. Each stage extends the chain of trust to the next.
The reason this works is that trust has to start somewhere it cannot be rewritten. That somewhere is the root of trust: on x86 it is keys fused into the silicon and the immutable early firmware (Intel Boot Guard, AMD Platform Secure Boot); on Apple silicon it is the mask-ROM Boot ROM. That root is the only link in the chain nobody can replace without replacing the chip. Everything after it is verified before it runs, so a single unmodifiable anchor at the bottom guarantees the integrity of a long mutable chain on top. Break any link and verification fails at that point; the machine refuses to advance.
Practical limitations: most distros need to ship a "shim" bootloader signed by Microsoft (the only authority that's universally trusted), which then loads the distro's actual bootloader. Self-signed firmware on consumer hardware works but requires manual key enrollment. Apple silicon takes the chain further: every byte of firmware on the SoC is signed by Apple, with no user override.
TPM and measured boot
A Trusted Platform Module is a small dedicated security chip (sometimes integrated into the CPU as fTPM on AMD, or PTT on Intel). It stores cryptographic keys in tamper-resistant hardware and provides services like random number generation, key sealing, and remote attestation.
During boot, each firmware stage measures (hashes) the next stage and extends the hash into the TPM's PCR registers. The final PCR values uniquely identify the entire boot chain. If any stage is modified — a malicious bootloader, a tampered kernel — the PCRs differ. BitLocker / FileVault / LUKS bind disk encryption keys to specific PCR values; if the boot chain is tampered with, the keys can't be unsealed and the disk stays encrypted.
This is what "your laptop refuses to boot after a BIOS update because BitLocker is asking for a recovery key" actually is: the BIOS update changed PCR 7 (the BIOS hash), so the TPM won't release the BitLocker key. Recovery keys exist as the explicit out-of-band escape hatch.
x86's mode tour
x86's history is visible at boot. The CPU starts in real mode — 16-bit registers, segmented memory, no protection. The BIOS sets up the GDT (Global Descriptor Table), enables the A20 line, and switches to protected mode. UEFI skips the real-mode dance and starts directly in long mode (64-bit). Either way, the kernel runs entirely in long mode with paging on.
x86 modes traversed at boot:
Legacy BIOS: Real mode (16-bit, 1 MB)
→ Protected mode (32-bit, 4 GB)
→ Long mode (64-bit, 256 TB / 128 PB)
UEFI: Long mode (64-bit) from the start
→ Kernel takes over in long mode
Secure boot + Apple silicon: No mode transitions visible to user code.
The SoC bootstraps directly into the OS.Bringing up additional cores
A multi-core CPU starts with only the BSP (Bootstrap Processor) running. The other cores — APs (Application Processors) — are held in reset until the kernel explicitly wakes them. The kernel sends a sequence of inter-processor interrupts (INIT, then SIPI — Startup Inter-Processor Interrupt), each AP starts at a kernel-provided trampoline, sets up its own stack and page tables, and joins the scheduler.
This sequence is why dmesg on Linux shows "smpboot: Booting Node 0
Processor 1 APIC 0x2" messages during boot. Each core takes ~10–50 µs to come
online; bringing up 256 cores on a big EPYC is itself a measurable fraction of
the boot time.
Phones and embedded boards
The PC story is the most baroque version. Phones and embedded systems run the same relay with fewer, more locked-down links. The shape is identical: an immutable boot ROM in silicon loads a first-stage loader, which loads a second-stage loader, which loads the kernel, each step verified against keys fused into the chip.
On an Android phone the chain runs through the SoC's boot ROM into a primary bootloader, then into U-Boot or a vendor loader, then into the Android boot image (kernel plus ramdisk). The "unlock the bootloader" toggle that voids your warranty is literally a fuse-backed flag that tells the verified-boot stage whether to enforce signature checks on the next link. On iPhones the chain is Boot ROM into iBoot into the kernel, every byte signed by Apple, with the Secure Enclave verifying in parallel and no override at all. On a small Linux board or a microcontroller the chain can be as short as a ROM that copies one image from flash to RAM and jumps to it, with no filesystem, no menu, and no kernel in the operating-system sense at all, just your firmware running on bare metal.
The pattern to take away is that "boot" is not an x86 thing. It is the universal problem of a chip that wakes up knowing nothing having to find, verify, and start trustworthy software, and every computing device from a thermostat to a datacenter server solves it with some version of the same staged, verified relay.
Common misconceptions
- "The BIOS / UEFI is just a few kilobytes of code." Modern UEFI is ~16 MB compressed and runs on top of millions of lines of code. EFI System Partitions can be several GB. UEFI is more "small OS" than "boot ROM".
- "You can disable Intel ME." You can disable some user-facing parts (AMT, vPro) but the ME core itself runs whether you want it to or not, on every Intel chip since 2008. The "HAP bit" disables most ME functionality but isn't supported on consumer chips. On AMD, the PSP is similarly unkillable.
- "Secure Boot is unbreakable." Several Secure Boot bypasses have been found (BootHole in 2020, others since). It's a defence-in-depth layer, not a guarantee. Combine with verified boot, measured boot, and disk encryption.
- "Faster SSDs make boot faster." Past a point, no. UEFI POST and DRAM training dominate cold boot. From SSD-read perspective, the bootloader is <100 KB and the kernel + initrd is <200 MB; modern NVMe loads them in milliseconds. The slow parts are firmware, not storage.
Numbers worth remembering
| Quantity | Value |
|---|---|
| x86 reset vector address | 0xFFFFFFF0 |
| UEFI image size, typical | ~16 MB |
| BIOS image size, legacy | ~1–4 MB |
| Coreboot image size | ~256 KB |
| DRAM training time, cold boot, 12-channel server | 1–10 s |
| Secure Boot trust anchor count, typical | 3–10 keys |
| TPM 2.0 PCR count | 24 registers |
| AP startup IPI sequence | INIT + SIPI + SIPI |
| Intel ME firmware version, recent | ~16.x (2024-25) |
| Apple Boot ROM size | ~4 KB (immutable mask ROM) |
| Typical cold boot time, modern laptop | ~10–20 s |
| Typical cold boot time, big server | ~1–3 min |
Further reading
- UEFI Specification — the authoritative reference (~2,500 pages).
- Coreboot — open-source firmware, the easiest way to read modern boot code.
- Wikipedia — UEFI
- Wikipedia — Trusted Platform Module
- Wikipedia — Intel Management Engine — including the security-disclosure history.
- Linux kernel — x86 boot protocol — exactly what UEFI/bootloader hands to the kernel.
- Coreboot architecture overview — modern PC boot flow at the source level.
- Bryant & O'Hallaron — Computer Systems: A Programmer's Perspective. Chapter 9 covers boot loosely from the OS perspective.