The Cold Start Problem
Here is the paradox at the heart of every computer: to run a program, the CPU needs instructions in RAM — but RAM is empty when the power is off. So how does the computer know what to do the moment it turns on?
Think of it like waking up with amnesia every single morning. You have no idea who you are or where you work. But taped to your forehead is a note that says: "Check your nightstand drawer — it has instructions." That note is the firmware, always there even when everything else is blank.
The solution is a small chip on the motherboard called ROM (Read-Only Memory). Unlike RAM, ROM keeps its contents even with no power. The moment electricity flows, the CPU knows to look at a fixed memory address — always the same address, hardwired — and start executing whatever code is there. That code is the firmware, and its entire job is to bootstrap everything else.
The word "booting" comes from "bootstrapping" — the old expression for pulling yourself up by your own bootstraps. The computer, starting from nothing, uses a tiny piece of persistent code to pull itself up into a fully running system. Every computer, every phone, every microwave with a display does this same thing at power-on.
The Boot Sequence — Step by Step
The boot process has four major stages. Each stage does one job and then hands control to the next. Think of it as a relay race — each runner goes as far as they can, then passes the baton.
The power supply sends voltage to the motherboard. The CPU's internal reset logic sets the instruction pointer to a fixed, hardcoded address (e.g., 0xFFFFFFF0 on x86). That address points directly into the ROM chip. The CPU has no choice but to start executing whatever is there.
The firmware initialises the CPU, RAM, storage controllers, and other hardware. It runs a self-test called POST to confirm everything is working. Then it scans connected storage devices (hard drive, SSD, USB) looking for a valid bootloader. When it finds one, it loads it into RAM and jumps to it.
The bootloader is a small program (e.g., GRUB on Linux, Windows Boot Manager) stored at the very start of the disk. Its only job is to find the operating system kernel on the disk, load it into RAM, and start it running. On multi-boot systems, the bootloader shows a menu letting you pick which OS to start.
The kernel is the core of the operating system. Once loaded, it detects all hardware (CPU cores, memory, graphics card, network), loads drivers, mounts the file system, and starts system services. Finally it starts the login screen or desktop — and the boot process is complete.
Each stage is only big enough to do one job. Stage 0 (firmware) can only find Stage 1 (bootloader). Stage 1 (bootloader) can only find Stage 2 (kernel). This chain keeps each piece small and replaceable — you can swap the bootloader without touching the firmware, or update the OS without touching the bootloader.
Stage 1 — Firmware (BIOS / UEFI)
The firmware is the first code the CPU ever runs. On PCs made before 2012, this was BIOS (Basic Input/Output System), a program that dates back to the 1970s. On modern computers it is UEFI (Unified Extensible Firmware Interface), which is faster and more capable. We'll cover both, but they do the same fundamental job.
What the Firmware Actually Does
The firmware does its work in a specific order, every single time the computer turns on:
- CPU initialisation — Sets the CPU to a known state. On x86, this means starting in 16-bit "real mode" (BIOS) or 32/64-bit mode (UEFI).
- Memory controller setup — Detects how much RAM is installed and configures the memory controller so the CPU can read and write to RAM.
- Hardware enumeration — Scans the PCI/PCIe bus to discover what hardware is connected: storage controllers, network cards, graphics cards.
- POST (Power-On Self Test) — Runs health checks on all hardware. If something fails (RAM test fails, CPU overheats), it signals an error with beep codes or on-screen messages before stopping.
- Boot device selection — Checks your boot order setting (configured in the BIOS setup menu). Looks through the ordered list of devices (e.g., USB first, then SSD) for a valid bootloader.
- Hand off — Loads the bootloader from the chosen device into RAM and jumps to it.
The BIOS/UEFI setup screen — accessible by pressing a key (Del, F2, F10, Esc) during boot — is where you configure this process: change the boot order, enable/disable Secure Boot, set a hardware clock, or adjust memory timings.
Stage 2 — POST: The Hardware Health Check
POST stands for Power-On Self Test. It runs automatically as part of the firmware stage and checks that the basic hardware is working before attempting to load any software. Think of it as the computer's morning checklist.
POST checks include:
- CPU test — Runs a few simple arithmetic instructions and checks the results.
- RAM test — Writes patterns to memory locations and reads them back. If the RAM is faulty, POST stops here.
- Graphics card — Checks the display adapter so the firmware can show messages on screen.
- Storage controllers — Detects connected drives (SATA, NVMe, USB).
- Keyboard / mouse — Basic input device detection.
If your computer powers on but shows nothing on screen and beeps repeatedly — that's POST signalling a hardware failure. One long beep + two short beeps, three rapid beeps — these beep codes are actually error messages. Each BIOS manufacturer (AMI, Award, Phoenix) has its own beep code table that tells you exactly which hardware failed.
If POST passes all checks, the firmware displays a brief splash screen (or none at all on fast UEFI systems) and immediately moves on to finding the bootloader. The entire POST process takes less than one second on a healthy modern machine.
Stage 3 — The Bootloader
The bootloader is the bridge between the firmware and the operating system. It is a tiny program — often just a few kilobytes — that does one thing: find the OS kernel on disk and load it into RAM.
Where the Bootloader Lives
On a traditional BIOS system, the bootloader lives in the MBR (Master Boot Record) — the very first 512 bytes of the disk. The layout of those 512 bytes is precise:
0x55 0xAA — Boot signatureThe BIOS loads these 512 bytes into RAM at address 0x7C00 and jumps to it. The code there is Stage 1 of the bootloader — it is just large enough to find and load Stage 2, which is larger and smarter and can actually locate and load the kernel.
GRUB — The Most Common Linux Bootloader
GRUB (Grand Unified Bootloader) works in stages. Stage 1 lives in the MBR (446 bytes). Stage 1.5 and Stage 2 live on the disk filesystem and contain the logic to understand file systems (ext4, NTFS, FAT32), read the kernel file (/boot/vmlinuz), and set up the initial RAM disk (initrd). GRUB's menu — the list of OS choices you see on a multi-boot system — comes from the config file at /boot/grub/grub.cfg.
U-Boot — The Bootloader for Embedded Systems
On embedded Linux boards (Raspberry Pi, BeagleBone, Android phones), the bootloader is typically U-Boot. It does the same job as GRUB but is designed for hardware with no disk — booting from an SD card, eMMC flash, or even over a network (TFTP). U-Boot can load a kernel from a file system, verify it with a cryptographic signature, and pass hardware description data (a device tree blob) to the kernel so it knows what hardware is present.
Stage 4 — The OS Kernel
The kernel is the heart of the operating system. Once the bootloader loads it into RAM and jumps to it, the kernel takes over the machine completely and does the heavy lifting of turning raw hardware into a usable computer.
What the Kernel Does on Startup
- Decompress itself — The kernel image on disk is compressed to save space. The first thing it does is decompress itself in RAM. On Linux you can see this: the kernel file is called
vmlinuz— the "z" means it is compressed. - Set up memory management — Configures virtual memory, page tables, and the memory allocator. From this point, all programs think they have their own private memory space.
- Probe and initialise hardware — Walks through all discovered hardware and loads the matching driver. Your graphics card, network interface, and USB controller all come alive here.
- Mount the root file system — Finds and mounts the main disk partition containing the OS files (
/on Linux,C:\on Windows). - Start PID 1 — Launches the first user-space process. On Linux this is
systemd(oriniton older systems). On Windows it issmss.exe. This process then starts all other services — networking, audio, display manager — and eventually shows you the login screen.
On Linux you can watch every step of kernel boot in real time by adding noquiet to the kernel boot parameters in GRUB. You'll see hundreds of lines fly by — each one is the kernel detecting a piece of hardware or starting a service.
Working Example — A Real Boot Sector
Here is a complete, working boot sector written in x86 assembly. When run, it prints "Hello! Booting..." to the screen and then loops forever. This is exactly what the BIOS loads and runs — 512 bytes, ending in the magic boot signature 0x55AA.
This code runs before any OS exists. There is no C runtime, no standard library, no file system. Just the CPU, RAM, and BIOS interrupt calls. This is the lowest level of software a computer can run.
; ───────────────────────────────────────────────────────────────────────────── ; Simple x86 Boot Sector ; Assembled with: nasm -f bin boot.asm -o boot.bin ; Tested with: qemu-system-x86_64 -drive format=raw,file=boot.bin ; ; The BIOS loads the first 512 bytes of the disk into RAM at 0x7C00 ; and jumps to it. This code runs in 16-bit "real mode". ; ───────────────────────────────────────────────────────────────────────────── [BITS 16] ; Tell assembler we are in 16-bit mode [ORG 0x7C00] ; BIOS loads us here — all addresses offset from 0x7C00 start: ; Clear segment registers — good practice in real mode xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, 0x7C00 ; Stack grows downward from our load address ; Point SI to the message string mov si, msg .print_loop: lodsb ; Load byte at [SI] into AL, advance SI or al, al ; Is the byte zero? (null terminator) jz .done ; If yes, we're finished printing ; BIOS interrupt 0x10, function 0x0E = "teletype output" mov ah, 0x0E ; Function: write character + advance cursor mov bh, 0x00 ; Page number 0 int 0x10 ; Call the BIOS jmp .print_loop .done: jmp $ ; Infinite loop — halt the bootloader msg: db 'Hello! Booting...', 0 ; Null-terminated string ; ─── Pad to exactly 510 bytes, then add the boot signature ─────────────────── times 510 - ($ - $$) db 0 ; Fill remaining space with zeros dw 0xAA55 ; Magic number — BIOS checks bytes 510-511 == 0x55 0xAA
How to Run It (No Physical Hardware Needed)
You need two tools: NASM (the assembler, converts assembly text to binary) and QEMU (a virtual machine that can boot any raw disk image).
# Step 1: Install the tools (Ubuntu/Debian) sudo apt install nasm qemu-system-x86 # Step 2: Assemble — converts boot.asm → boot.bin (exactly 512 bytes) nasm -f bin boot.asm -o boot.bin # Step 3: Confirm the file is exactly 512 bytes ls -l boot.bin # Should show: -rw-r--r-- 1 user user 512 ... # Step 4: Verify the boot signature is at the end xxd boot.bin | tail -2 # Last line should end with: ... 55 aa # Step 5: Boot it in QEMU — a window opens showing "Hello! Booting..." qemu-system-x86_64 -drive format=raw,file=boot.bin
When QEMU runs this, it behaves exactly like a real PC's BIOS: reads the first 512 bytes of "disk" (your boot.bin file), checks that bytes 510–511 are 0x55 0xAA, loads it to address 0x7C00, and jumps there. The assembly code runs, calls the BIOS video interrupt, and prints the message. That is the complete boot process — just compressed into 512 bytes.
What Each Part Does
[BITS 16]— The BIOS hands control in 16-bit real mode. Every x86 CPU starts this way regardless of how modern it is.[ORG 0x7C00]— Tells the assembler that our code will be at address 0x7C00 in RAM, so all memory references are calculated correctly.int 0x10— A BIOS interrupt call. Before the OS exists, the only way to interact with hardware is through BIOS interrupts — the BIOS provides these services like a tiny OS of its own.dw 0xAA55— The two magic bytes the BIOS checks. Without this exact value at the end, the BIOS will refuse to boot from this disk.times 510 - ($ - $$) db 0— Pads the file to exactly 510 bytes. Combined with the 2-byte signature, total is 512 bytes — exactly one disk sector.
Embedded Booting — Raspberry Pi Example
The Raspberry Pi is a great example of how booting works on embedded hardware, and it is quite different from a PC. There is no BIOS chip. Instead, the boot process is baked into the GPU (yes, the GPU!) of the Broadcom SoC.
Raspberry Pi Boot Sequence
- GPU ROM boots first — The Broadcom BCM2837 SoC has a small ROM inside the GPU. At power-on, the GPU core starts executing this ROM code (the CPU is not running yet).
- GPU reads
bootcode.binfrom SD card — The GPU's ROM code knows how to read the SD card. It loadsbootcode.binfrom the FAT32 partition into its own small cache memory. bootcode.binloadsstart.elf— This is Broadcom's proprietary GPU firmware. It initialises SDRAM and hands control to the main CPU for the first time.config.txtis read — This plain-text configuration file controls memory split, overclocking, display settings, and kernel parameters. It is human-readable and easy to edit.- Kernel is loaded —
start.elfloads the Linux kernel file (kernel8.imgfor 64-bit,kernel7.imgfor 32-bit) into RAM and starts the ARM CPU running it. - Linux boots normally — From here it is standard Linux: kernel decompresses, detects hardware via the device tree blob (
bcm2837-rpi-3-b.dtb), mounts the ext4 partition, and startssystemd.
If your Raspberry Pi won't boot, the most common fix is to replace the files on the FAT32 boot partition of the SD card — specifically bootcode.bin, start.elf, and fixup.dat. These are the equivalent of the BIOS on a PC.
The Raspberry Pi boot sequence shows a key principle of embedded systems: there is no one-size-fits-all boot process. Every embedded platform has its own sequence, designed around the specific hardware. Android phones, smart TVs, car infotainment systems, and industrial PLCs all have custom boot chains — but they all follow the same fundamental idea: small code finds slightly bigger code, which finds the OS.
BIOS vs UEFI
Modern computers use UEFI instead of the classic BIOS. Both are firmware that starts the boot process, but they work differently and UEFI is significantly more capable.
| Feature | BIOS (Legacy) | UEFI (Modern) |
|---|---|---|
| Year introduced | 1975 | 2002 (widespread from 2011) |
| CPU mode at startup | 16-bit real mode | 32-bit or 64-bit mode |
| Max disk size | 2 TB (MBR limit) | 9.4 ZB (GPT — effectively unlimited) |
| Partition table | MBR (4 primary partitions max) | GPT (128 partitions) |
| Boot speed | Slower (initialises all hardware sequentially) | Faster (parallel init, faster POST) |
| Secure Boot | No | Yes — verifies bootloader signature to prevent malware |
| Interface | Text-only, keyboard only | GUI with mouse support |
| Network boot | Limited (PXE with option ROM) | Built-in PXE and HTTP boot support |
| Bootloader location | MBR (first 446 bytes of disk) | EFI System Partition (a dedicated FAT32 partition) |
Secure Boot
One of UEFI's most important features is Secure Boot. When Secure Boot is enabled, the firmware will only load a bootloader that has been cryptographically signed by a trusted authority. This prevents malware from replacing your bootloader — a type of attack called a "bootkit" that is nearly impossible to detect or remove once installed, because it runs before the OS and can hide from it. Microsoft signs the Windows Boot Manager; Linux distributions sign their GRUB builds and kernels. If you install a new operating system and get a "Secure Boot violation" error, it means the firmware doesn't recognise the bootloader's signature — you need to enrol the key or temporarily disable Secure Boot.
Frequently Asked Questions
What does booting a computer mean?
What is BIOS and what does it do?
What is the difference between BIOS and UEFI?
What is a bootloader?
What is the MBR (Master Boot Record)?
What happens if the boot sector is missing or corrupt?
grub-install, on Windows with bootrec /fixmbr from the recovery environment.Why does my computer take longer to boot sometimes?
systemd-analyze blame to see exactly which service took the most time during boot.