EmbeddedPathashala › Free Linux Kernel Programming Course › Chapter 3
The Linux Boot Process on x86 — A Full Walkthrough
From the moment you press the power button to the shell prompt — every stage, explained clearly for students and engineers.
Topics Covered
MBR vs GPT
GRUB2
vmlinuz
initramfs
switch_root
systemd PID 1
Secure Boot
U-Boot ARM
Device Tree
What You Will Learn
- Every stage of the Linux x86 boot sequence — power-on to login prompt
- The difference between legacy BIOS and modern UEFI boot paths
- What GRUB2 does and why Linux needs a bootloader at all
- How the kernel initialises hardware and transitions through initramfs
- Why systemd replaced SysV init, and what it does that SysV could not
- How the embedded Linux boot path differs on ARM boards
📷 Suggested Image for This Post
A vertical flowchart image with five labelled boxes: Firmware → GRUB2 → Linux Kernel → initramfs → systemd, each box a different shade of blue-green. Alt text: Linux x86 boot sequence diagram showing all stages from BIOS to systemd.
Two Paths — BIOS and UEFI
Before going through the boot stages, you need to know that modern x86 hardware can boot in two very different ways. Which one your machine uses affects the early stages of the boot sequence significantly.
BIOS vs UEFI — Key Differences at a Glance
| Feature | Legacy BIOS | UEFI (Modern, 2012+) |
|---|---|---|
| Disk format | MBR — max 2 TB, 4 partitions | GPT — 9.4 ZB, 128 partitions |
| Boot entry point | First 512 bytes of disk (MBR) | EFI System Partition (FAT32) |
| Bootloader space | 446 bytes for Stage 1 code | Full .efi binary, no size limit |
| Security | None | Secure Boot (cryptographic signing) |
| GRUB on this path | Stage 1 → Stage 2 → GRUB | GRUB loaded directly as grubx64.efi |
The kernel initialisation steps from Step 4 onward are identical regardless of which firmware path was taken. The difference is only in how you get to the point where the kernel starts running.
The Linux Boot Sequence — Step by Step
Step 1 — Power On and POST
The instant the power button is pressed, the CPU begins executing instructions from a fixed address in ROM. This is where the firmware (BIOS or UEFI chip) lives. The very first thing it runs is POST — Power-On Self Test.
POST checks that the CPU, RAM modules, and basic hardware are functioning. If something critical fails, the system halts — on older machines you hear beep codes that indicate which component failed.
After POST, the firmware initialises the keyboard controller, display, storage controllers, and PCI bus. It then scans the configured boot order (NVMe SSD, USB, network) looking for a bootable device.
Step 2 — Stage 1 Bootloader (MBR) or EFI Handoff
💾 BIOS Path
Reads first 512 bytes of disk — the MBR. First 446 bytes = Stage 1 bootloader code. Just enough space to locate and load Stage 2 (which can read filesystems). Stage 2 then loads GRUB2.
⛅ UEFI Path
No MBR needed. Firmware reads the EFI System Partition (a small FAT32 partition) and loads grubx64.efi directly as a proper application. Much simpler — no Stage 1/Stage 2 complexity.
Step 3 — GRUB2 Runs
GRUB2 (Grand Unified Bootloader version 2) is the main bootloader used on virtually all x86 Linux systems. It reads its configuration from /boot/grub/grub.cfg and, if multiple kernels are installed, shows a menu.
GRUB’s main job is to load two files into RAM and jump to the kernel entry point:
/boot/vmlinuz-6.x.y— the compressed kernel image/boot/initrd.img-6.x.y— the compressed initramfs archive
# What a GRUB2 menu entry looks like in grub.cfg:
menuentry "Ubuntu 24.04, Linux 6.8.0-48-generic" {
linux /boot/vmlinuz-6.8.0-48-generic root=UUID=xxxx ro quiet splash
initrd /boot/initrd.img-6.8.0-48-generic
}
After loading both images, GRUB jumps to the kernel’s entry point. GRUB’s job is now done.
Step 4 — Kernel Takes Control and Initialises Hardware
The Linux kernel is now running. Its very first task is to decompress itself — the vmlinuz file is a self-extracting compressed archive. Once decompressed into RAM, the real kernel code starts executing.
A crucial design principle kicks in here: the kernel makes no assumptions about what the bootloader did. It re-initialises all hardware from scratch — CPU state, MMU (memory management unit), interrupt controllers, timers, PCI enumeration. This is what makes the kernel portable: it can boot correctly whether loaded by GRUB, U-Boot, or any other bootloader.
Step 5 — Kernel Detects and Unpacks initramfs
Once hardware initialisation is mostly done, the kernel checks whether CONFIG_BLK_DEV_INITRD=y is set (it always is on distribution kernels). It locates the initramfs archive that GRUB placed in RAM, decompresses the cpio archive, and mounts it as a temporary root filesystem in RAM.
At this moment the kernel’s / (root) is a tiny in-memory filesystem — not your hard drive. The kernel can now read files from it.
# Verify initramfs support in your running kernel:
grep CONFIG_BLK_DEV_INITRD /boot/config-$(uname -r)
# Output: CONFIG_BLK_DEV_INITRD=y
Step 6 — initramfs /init Script Runs, Loads Modules
The kernel executes /init inside the initramfs. This is a shell script (using busybox utilities) that does the heavy lifting:
- Loads the filesystem driver module —
ext4.ko,btrfs.ko, etc. — from the initramfs itself - If the disk is encrypted: runs
cryptsetupto prompt for a passphrase and unlock the LUKS volume - If LVM is used: activates volume groups with
lvm vgchange -ay - Locates the real root partition using the UUID or device label passed as a kernel parameter by GRUB
- Mounts the real root filesystem at
/rootinside the initramfs environment
Step 7 — switch_root Transitions to the Real Filesystem
Now that the real root filesystem is mounted and ready, the init script calls switch_root. This is the modern replacement for the older pivot_root system call.
switch_root atomically performs three actions:
- Makes the real disk filesystem the new
/for the running kernel - Unmounts and discards the initramfs tmpfs — freeing that RAM
- Execs
/sbin/initon the real filesystem (which is systemd on modern systems)
After this point, the kernel is running with your real disk as its root — the initramfs is completely gone from memory.
Step 8 — systemd Starts as PID 1
The first process the kernel launches in the real userspace is always PID 1. On virtually all modern Linux systems — including most embedded distributions — this is systemd, which replaced the older SysV /sbin/init.
systemd reads unit files from /etc/systemd/system/ and /lib/systemd/system/ and starts all required services in parallel, respecting dependency declarations between them.
# Confirm what is running as PID 1 on your system:
ps -p 1 -o comm=
# Output: systemd
ls -la /sbin/init
# /sbin/init -> /lib/systemd/systemd
Step 9 — System Services Come Up, Login Appears
systemd works through its targets — sysinit.target, basic.target, multi-user.target, and optionally graphical.target. Services like networking, udev, SSH, and the display manager start in parallel where dependencies allow. When all required services reach their target, the login prompt or desktop appears.
# See how long each stage of boot took:
systemd-analyze
# See which services took the most time:
systemd-analyze blame | head -20
The Complete Boot Sequence — Visual Overview
Linux x86 Boot Sequence — All Stages
BIOS: reads MBR | UEFI: reads EFI System Partition
Reads
/boot/grub/grub.cfg, shows menu, loads into RAM:›
vmlinuz-6.x.y (compressed kernel) › initrd.img-6.x.y (initramfs)Jumps to kernel entry point
Makes zero assumptions about what GRUB set up. Portable design.
Detects initramfs (CONFIG_BLK_DEV_INITRD=y) → unpacks cpio → mounts mini root in RAM
› Loads
ext4.ko / btrfs.ko from RAM › Unlocks LUKS (if encrypted) › Activates LVM› Finds real root by UUID › Mounts at
/rootswitch_root → real FS becomes
/, RAM freed, exec systemd› udev › networking › dbus › SSH › display manager
Reaches
multi-user.target / graphical.target → Login prompt appears ✓Why systemd Replaced SysV init
Older books (and older kernels) describe /sbin/init and SysV runlevels as PID 1. On modern Linux — including most embedded systems — that is now systemd. Understanding why helps you reason about boot behaviour and debug startup issues.
❌ Problems with SysV init
- Services start one at a time, sequentially — slow boot
- Each service is a shell script — hard to debug and maintain
- No dependency tracking — manual ordering required
- No socket activation — services must pre-start before clients connect
- Logging scattered across
/var/log/files with no central index
✓ What systemd Does Better
- Parallel start — independent services launch simultaneously
- Socket activation — start a service only when first connection arrives
- Declarative units — simple config files instead of shell scripts
- Dependency graph —
Requires=,After=,Wants= - journald — central structured log, queryable with
journalctl
# Analyse your boot timing:
systemd-analyze
# Which services take the most time:
systemd-analyze blame | head -15
# See the full dependency chain as an HTML graph:
systemd-analyze plot > /tmp/bootchart.html && xdg-open /tmp/bootchart.html
UEFI and Secure Boot — What You Must Know
Secure Boot works by having the UEFI firmware verify a cryptographic signature on everything it loads — the bootloader, and then the kernel itself. Ubuntu and Fedora ship pre-signed kernels and a shim that carries a Microsoft-trusted certificate, so they boot with Secure Boot on by default.
When you build your own kernel for this course, you have two options:
Options for Custom Kernel + Secure Boot
| Option | How | Downside |
|---|---|---|
| Disable Secure Boot | Go into UEFI settings and turn it off | Reduces firmware-level security |
| Enroll your own key | Generate a key pair, enroll with mokutil, sign kernel with sbsign |
More steps, must sign every kernel rebuild |
# Check if Secure Boot is active:
mokutil --sb-state
# Check if you booted via UEFI or legacy BIOS:
[ -d /sys/firmware/efi ] && echo "UEFI boot" || echo "Legacy BIOS boot"
# Check EFI variables are accessible (should exist on UEFI systems):
ls /sys/firmware/efi/efivars/ | head -5
How Embedded Linux Boot Differs (ARM)
Everything above covers x86 desktop and server hardware. On ARM-based embedded boards — Raspberry Pi, BeagleBone, industrial controllers, automotive ECUs — the boot flow follows the same logical phases but uses completely different software.
Embedded ARM Boot Flow vs x86
x86 Desktop
ROM firmware
reads grub.cfg
ACPI for hardware
separate file
ARM Embedded
baked into chip
sets up DDR RAM
loads kernel + DTB
Device Tree for hardware
Yocto / Buildroot
🎯 Frequently Asked Questions — Linux Boot Process
Commonly tested in Linux kernel, embedded systems, and system software interviews.
Q1. Walk me through the Linux boot sequence from power-on to the login prompt.
vmlinuz and initrd.img into RAM → kernel decompresses, re-initialises all hardware → kernel detects and unpacks initramfs → initramfs /init script loads FS modules, optionally unlocks LUKS, mounts real root → switch_root frees RAM, hands off to real / → systemd starts as PID 1 → parallel service startup → login prompt.Q2. What is GRUB2 and why does Linux need a bootloader at all?
Q3. What is PID 1 and what makes it special?
/sbin/init.Q4. What does “the kernel makes no assumptions about the bootloader” mean in practice?
Q5. What is the difference between BIOS and UEFI booting?
Q6. Why did systemd replace SysV init? Name three concrete improvements.
Requires=, After=, Wants= relationships, so systemd builds and respects a dependency graph automatically. SysV required manual numbering of scripts.Q7. How does the embedded ARM boot process differ from x86?
CONFIG_INITRAMFS_SOURCE rather than being a separate file; (5) The init system may be a lightweight BusyBox init rather than a full systemd, depending on the project (Yocto, Buildroot, etc.).Q8. What is Secure Boot and how does it affect custom kernel development?
mokutil and sbsign.Free Linux Kernel Programming Course
EmbeddedPathashala is a completely free learning platform covering Linux kernel programming, device drivers, BLE, and embedded systems from the ground up.
