How Linux Boots: From BIOS/UEFI to Login
What You'll Learn
- The exact order of events from power-on to the login prompt, traced as a single line
- How to tell which stage failed when a machine won't boot
- How to observe your own machine's boot with
systemd-analyzeandjournalctl -b
The 5 boot stages
- Firmware (BIOS / UEFI) … initializes hardware, finds the boot device
- Bootloader (GRUB) … loads the kernel and initramfs into memory
- Kernel … takes control of hardware, unpacks initramfs as a temporary root
- init (systemd, PID 1) … switches to the real root, starts services in parallel
- Login … getty or a display manager shows the prompt
Assumptions (target environment)
- A typical x86_64 Linux (UEFI + GRUB 2 + systemd)
- BIOS-only machines, other bootloaders (e.g. systemd-boot), or other init systems (e.g. OpenRC) change some of the names
How many stages are there in a Linux boot?
Conclusion: Five stages: firmware → bootloader → kernel → init → login. Each stage's only job is to start the next one, so pinpointing where it stalled instantly narrows down the cause.
Booting is not magic; it's a relay race. At power-on the only thing you can trust is the CPU, and from there the "circle of trust" widens one step at a time. Each stage loads the next into memory, hands over control, and bows out.
Power ON │ ▼ (1) Firmware (BIOS / UEFI) init hardware, pick boot device ▼ (2) Bootloader (GRUB) load kernel + initramfs ▼ (3) Kernel drive hardware, unpack initramfs ▼ (4) init (systemd / PID 1) start services, reach target ▼ (5) Login (getty / DM) show prompt Usable system
"How far did it get?" is the single most useful piece of troubleshooting information. If you see the GRUB menu, stages (1) and (2) succeeded; if kernel messages scroll by, you reached (3). The visible symptom lets you work backwards to the stage.
What do BIOS and UEFI actually do?
Conclusion: The firmware (BIOS / UEFI) initializes hardware and locates a bootable device, then loads the first program into memory. UEFI can launch a
.efifile from the EFI System Partition directly, which is the key difference from BIOS.
After power-on, the first thing to run is the firmware on the motherboard. It has two jobs.
- POST (Power-On Self-Test): checks that core hardware (CPU, RAM, storage) is present and healthy
- Boot device selection: scans disks, USB, and network in the configured order to find something bootable
This is where BIOS and UEFI diverge.
| Aspect | BIOS (legacy) | UEFI (modern) |
|---|---|---|
| Boot method | Runs first 446 bytes of MBR | Launches a .efi file on the ESP |
| Disk size limit | 2 TB (MBR) | 9.4 ZB (GPT) |
| Secure boot | None | Supports Secure Boot |
| Settings store | CMOS | NVRAM (managed via efibootmgr) |
On a UEFI machine, the bootloader executable (e.g. /EFI/ubuntu/grubx64.efi) lives on the ESP (EFI System Partition), a small FAT32 area. UEFI launches it directly, so the old BIOS trick of embedding code in the MBR is no longer needed.
# Check whether you booted via UEFI (this directory exists only on UEFI boots) $ ls /sys/firmware/efi
If /sys/firmware/efi exists, you booted via UEFI; if not, it's a legacy BIOS boot. For dual-boot or install problems, settling this one fact first removes a lot of dead-end diagnosis.
What is the bootloader (GRUB) for?
Conclusion: The bootloader reads the kernel and initramfs from disk into memory and hands control to the kernel with boot parameters. GRUB can also show a menu, let you pick a kernel, and edit parameters on the fly.
The firmware launches the bootloader, and on Linux that is most commonly GRUB 2. GRUB's tasks are:
- Choose which kernel / OS to boot (that black selection menu)
- Load the chosen kernel (
vmlinuz) and initramfs (initrd.img) into memory - Hand off to the kernel with kernel parameters (the cmdline)
Its configuration is generated at /boot/grub/grub.cfg, but that's an auto-generated file you should never edit directly. The sources are /etc/default/grub and a set of templates.
# Show the kernel and parameters used for this boot $ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.8.0-31-generic root=UUID=... ro quiet splash
root=UUID=... says "this is the real root filesystem," and ro means "mount it read-only at first." When something breaks, pressing e at the GRUB menu lets you edit this line in place (for example, remove quiet splash and add single) to boot into a rescue mode.
A visible GRUB menu means stages (1) and (2) succeeded. If it goes no further (no kernel messages), suspect a corrupt kernel or initramfs, or a wrong root=. If you don't even get the GRUB menu, the cause lies in firmware settings or the ESP / bootloader itself.
What are the kernel and initramfs doing?
Conclusion: The kernel takes control of memory, CPUs, and devices, then unpacks initramfs as a temporary root. initramfs holds just enough drivers to mount the real root; once that's ready, it switches over to the real root.
Once GRUB hands over control, the kernel unpacks itself and starts managing the hardware. It brings up memory management and the process scheduler, enables all CPU cores, and initializes drivers.
The key player here is initramfs (initial RAM filesystem). Why is it needed? If the real root filesystem sits on top of encryption (LUKS), LVM, RAID, or an exotic disk driver, the kernel needs "the driver to mount it" before it can mount it. It's a chicken-and-egg problem.
initramfs solves this as a small temporary root. GRUB loaded this archive into memory alongside the kernel; the kernel unpacks it in RAM and runs its init script, which roughly:
- Loads required kernel modules (storage, encryption, etc.)
- Activates LVM, decrypts LUKS, and otherwise makes the real root visible
- Mounts the real root and uses
switch_rootto change the root over to it
# The kernel's detection and init steps are kept in a ring buffer $ dmesg | head
initramfs's job ends here; from now on /sbin/init (i.e. systemd) on the real root takes the stage. This "temporary root -> real root" switch is the midpoint climax of boot, and it's where an encrypted-disk passphrase prompt appears.
What does init (systemd / PID 1) start?
Conclusion: The first process started on the real root is init, today usually systemd (PID 1). systemd resolves dependencies and starts services (units) in parallel, aiming to reach a goal state (a target).
After switch_root, the first userspace process the kernel starts from the real root is PID 1, init. On most modern distros that role belongs to systemd. Its hallmark is treating services as a dependency graph and starting independent ones in parallel (in contrast to old SysVinit, which ran boot scripts serially).
The startup units systemd manages are called units.
*.service… daemons / programs (e.g.sshd.service)*.mount… filesystem mounts*.socket… socket listeners*.target… a goal grouping many units (the successor to runlevels)
The goal of boot is reaching the default target. Servers typically use multi-user.target (CLI); desktops use graphical.target (GUI).
# Show the default target (successor to runlevels) $ systemctl get-default
graphical.target
| Old runlevel | systemd target | Meaning |
|---|---|---|
| 0 | poweroff.target |
Shutdown |
| 1 | rescue.target |
Single user (recovery) |
| 3 | multi-user.target |
CLI multi-user |
| 5 | graphical.target |
GUI |
| 6 | reboot.target |
Reboot |
systemd follows dependencies out from default.target and starts the needed units. Because other units proceed even if one fails, you can isolate cases like "it booted, but only this one service is down."
systemd controls each service with signals. The "send SIGTERM, and if it doesn't respond, SIGKILL" flow is exactly how graceful shutdown works. See Understanding Linux Signals for details.
Where does the login prompt come from?
Conclusion: At the final step of reaching the target, a CLI uses getty to show a
login:prompt on a virtual terminal, while a GUI uses a display manager (e.g. gdm) to show a graphical login. Once you're here, boot is complete.
Reaching the target brings up the entry point you interact with.
- CLI (
multi-user.target):getty(agetty) shows alogin:prompt on each virtual terminal (tty1, etc.). The plain text terminals you reach withCtrl+Alt+F2are these. - GUI (
graphical.target): a display manager (gdm/sddm/lightdm, etc.) shows a graphical login screen and, after authentication, starts a desktop session.
Authentication is handled by PAM (Pluggable Authentication Modules). On success, a shell (CLI) or desktop environment (GUI) starts and the system is finally "usable." This is the finish line of the boot relay.
How do I observe my own machine's boot?
Conclusion: Use
systemd-analyzefor total time and slow units, andjournalctl -bfor the full log of the current boot. "It's slow" and "this service won't start" are almost always solvable with these two.
Let's verify the theory on your own machine. systemd measures and records each boot stage, so visualizing it is easy.
# Total boot time (firmware -> kernel -> userspace) $ systemd-analyze
Startup finished in 4.123s (firmware) + 2.001s (loader) + 1.892s (kernel) + 6.540s (userspace) = 14.557s
The firmware / loader / kernel / userspace breakdown maps exactly to stages (1)-(4) of this article, so you can see at a glance where the time goes.
# Units that slowed the boot, slowest first $ systemd-analyze blame
# Read only the current boot's log (-b = current boot) $ journalctl -b
Because of parallel startup, the numbers from systemd-analyze blame don't add up to a simple total (concurrent work is double-counted). For order-dependent delays, systemd-analyze critical-chain is closer to reality.
Summary: boot stages and a diagnosis cheat sheet
Conclusion: "What appeared on screen" tells you the stage reached. GRUB menu = (1)(2) ok, kernel log = reached (3), emergency prompt = (4) failed to mount root, login = full success. Translate the symptom into a stage and the cause range is fixed.
| Stage | Owner | What success looks like | Likely cause when stuck |
|---|---|---|---|
| (1) Firmware | BIOS / UEFI | Vendor logo | Boot order, ESP, hardware fault |
| (2) Bootloader | GRUB | GRUB menu | grub.cfg, corrupt kernel/initrd |
| (3) Kernel | kernel + initramfs | Kernel log scrolls | Missing driver, wrong root= |
| (4) init | systemd (PID 1) | Service start messages | Root mount fails, broken unit |
| (5) Login | getty / DM | Login prompt | DM config, PAM, GPU driver |
Keep the boot flow in mind as five stages of responsibility, and a vague "it won't boot" becomes a question of which stage failed. From there, reading that stage's log (dmesg / journalctl -b) takes you straight to the cause.