Stage 1 loaded a small piece of code that can read a filesystem. That code loaded GRUB's main body into memory. Now, for the first time in the boot process, the machine is running a program that can do more than just load the next sector. GRUB can read configuration files, display a menu, accept keyboard input, and -- most importantly -- find and load a Linux kernel.
GRUB stands for GRand Unified Bootloader. The "unified" part matters: GRUB can boot Linux, Windows, BSD, and other operating systems from a single menu. But its core job on a Linux system is straightforward. Read a config file. Show a menu. Load the kernel and an initial RAM filesystem into memory. Hand control to the kernel.
GRUB's Architecture
GRUB is not a single program. It is a modular system built from a small core and a collection of loadable modules. The core provides the command-line interpreter, the module loader, and basic device access. Modules add specific capabilities: filesystem drivers, compression support, graphical terminal rendering, network booting, and more.
When GRUB's core starts, it loads the normal module, which provides the familiar menu interface. The normal module then reads the configuration file and builds the menu entries. If the configuration file is missing or corrupt, GRUB drops to a rescue shell -- a minimal command line where you can manually type commands to boot the system.
The Configuration File
GRUB's behavior is controlled by a file called grub.cfg, usually found at /boot/grub/grub.cfg or /boot/grub2/grub.cfg. You are not meant to edit this file by hand. It is generated automatically by the grub-mkconfig command (or grub2-mkconfig on Fedora/RHEL systems), which scans your system for installed kernels and writes the appropriate menu entries.
A typical grub.cfg entry looks like this:
menuentry 'Ubuntu' --class ubuntu --class os {
set root='hd0,gpt2'
linux /vmlinuz-6.2.0 root=/dev/sda3 ro quiet splash
initrd /initrd.img-6.2.0
}
Each line does something specific:
set root='hd0,gpt2'tells GRUB which partition to read files from.hd0is the first disk,gpt2is the second GPT partition.linux /vmlinuz-6.2.0 ...tells GRUB to load the kernel image from the specified path, and passes everything after the filename as kernel command-line parameters.initrd /initrd.img-6.2.0tells GRUB to load the initial RAM disk alongside the kernel.
How GRUB Identifies Disks and Partitions
GRUB uses its own naming convention for storage devices. The first hard disk is hd0, the second is hd1, and so on. Partitions are numbered starting from 1: hd0,msdos1 for the first MBR partition on the first disk, or hd0,gpt1 for the first GPT partition. This naming is independent of how Linux names the same devices (/dev/sda1, /dev/nvme0n1p1, etc.).
GRUB resolves these names using its disk and partition modules. It reads partition tables directly -- it does not rely on the operating system, because the operating system is not running yet. GRUB carries its own partition table parsers (part_msdos.mod for MBR, part_gpt.mod for GPT) and its own filesystem drivers.
How GRUB Reads Filesystems
This is the capability that separates GRUB from the tiny Stage 1 code. Stage 1 can only read raw sectors by number. GRUB can read files by path.
GRUB includes filesystem driver modules for ext2/ext3/ext4, XFS, Btrfs, ZFS, FAT, NTFS, and others. When GRUB needs to read a file, it:
- Identifies the disk and partition from the device name.
- Reads the partition's superblock to determine the filesystem type.
- Loads the appropriate filesystem module if it is not already loaded.
- Navigates the filesystem's internal structures (inodes, directory entries, extent trees) to locate the file.
- Reads the file's data blocks into memory.
This is the same work that the Linux kernel does when you run cat /boot/vmlinuz, but GRUB does it with its own code, running before the kernel exists. GRUB's filesystem drivers are simpler than the kernel's -- they only need to read, never write -- but they must be correct. A bug in GRUB's ext4 driver means an unbootable system.
The Menu and the Timeout
When GRUB finishes loading its configuration, it displays a menu. If you have a single operating system, the menu might be hidden -- GRUB waits for a configurable timeout (often 5 or 10 seconds) and then boots the default entry automatically. Press Shift or Escape during this timeout to reveal the menu.
The menu lets you choose between different kernels (useful after a bad kernel upgrade), different operating systems (dual-boot setups), or recovery modes. Each menu entry is a menuentry block in grub.cfg containing the commands GRUB will execute when that entry is selected.
You can also press c at the menu to drop into GRUB's command line, where you can type commands manually. This is invaluable for recovery. If your grub.cfg is corrupt but you know where your kernel lives, you can type:
set root=(hd0,gpt2)
linux /vmlinuz root=/dev/sda3
initrd /initrd.img
boot
Those four commands do exactly what a menuentry block does, but typed by hand.
Loading the Kernel and Initramfs
When you select a menu entry (or the timeout expires), GRUB executes the commands in that entry. The linux command is the critical one. It does several things:
- Opens the kernel image file (
vmlinuz) from the specified partition and path. - Reads the kernel's setup header, which is embedded in the first few kilobytes of the image. The header tells GRUB the kernel's version, required load address, command-line format, and other parameters.
- Copies the kernel image into memory at the address the header specifies.
- Stores the kernel command-line string (everything after the filename on the
linuxline) in a designated memory area.
The initrd command then loads the initial RAM filesystem image into another region of memory and records its address and size so the kernel can find it later.
The Boot Command
After the linux and initrd commands have loaded their data, the boot command (usually implicit at the end of a menuentry block) triggers the actual handoff. GRUB fills in a data structure called the boot parameters (or "zero page") with everything the kernel needs to know: the address and size of the initrd, the command-line location, the video mode, the memory map from the BIOS, and more.
Then GRUB jumps to the kernel's entry point. At this moment, GRUB's job is done. It will never run again (until the next reboot). The kernel takes over, and the bootloader is gone.
GRUB on UEFI Systems
Everything described so far assumes legacy BIOS booting. On UEFI systems, the picture is different. UEFI firmware can read FAT-formatted partitions natively, so GRUB does not need the Stage 1 / Stage 1.5 chain. Instead, GRUB is compiled as a UEFI application -- an EFI executable stored on the EFI System Partition (usually at /EFI/ubuntu/grubx64.efi or similar).
The firmware loads this EFI application directly. There is no MBR boot code, no INT 0x13, no real mode. The UEFI version of GRUB uses UEFI boot services instead of BIOS interrupts for disk access and video output. But once GRUB is running, the user-facing experience is the same: same config file, same menu, same linux and initrd commands.
When Things Go Wrong
GRUB failures are common enough that every Linux administrator encounters them. The most frequent scenarios:
"error: unknown filesystem" -- GRUB cannot read the partition containing its modules or configuration. This happens when a filesystem is corrupted, when you resize a partition without updating GRUB, or when a GRUB module for the filesystem type was not installed.
"error: file not found" -- GRUB can read the filesystem but cannot find grub.cfg or the kernel. This happens after a kernel upgrade that did not regenerate grub.cfg, or after moving files around in /boot.
Rescue shell -- GRUB loaded its core but could not load normal.mod. You get a grub rescue> prompt with minimal commands. The fix is usually set prefix=(hd0,gpt2)/boot/grub followed by insmod normal and then normal.
In all these cases, the fix involves booting from a live USB, mounting the installed system, and running grub-install and grub-mkconfig to rebuild GRUB from scratch.
What Happens Next
GRUB has loaded the kernel image and the initramfs into memory. It has passed the kernel command line and a block of boot parameters. Now the kernel needs to actually start running. But the kernel image on disk is not a simple executable -- it is compressed, and it contains multiple parts. GRUB has found it; now the kernel must find itself.
Next: Finding the Kernel