What You Will Learn
In this tutorial you will learn:
- What GRUB is and where it sits in the boot process
- The structure of the GRUB2 configuration system
- How to make the GRUB menu always visible during development
- How to set boot timeouts and default kernel selection
- How to pass custom parameters to the kernel at boot
- How to switch between multiple installed kernels — critical for kernel developers
- GRUB2-specific tips for UEFI systems (which most modern machines use)
This is a practical, hands-on tutorial. Every command shown here is safe to run and reversible.
Topics Covered:
Boot Menu
/etc/default/grub
update-grub
Kernel Parameters
UEFI Boot
Dual Boot
Kernel Developer Workflow
Boot Timeout
GRUB Rescue
1. What is GRUB and Why Should Kernel Developers Care?
GRUB stands for GRand Unified Bootloader. It is the most widely used bootloader on x86 and x86-64 Linux systems. When you press the power button, GRUB is one of the first programs that runs. Its job is simple but critical: find the kernel, load it into memory, load the initramfs, and hand control to the kernel.
|
v
[BIOS/UEFI Firmware]
– POST (Power-On Self Test)
– Detects CPU, RAM, storage devices
– Finds the bootable device
|
v
[GRUB Stage 1] ← Tiny code in MBR or EFI partition
– Loads GRUB Stage 2 from disk
|
v
[GRUB Stage 2] ← This is what shows you the boot MENU
– Reads /boot/grub/grub.cfg
– Shows you the menu (if configured)
– Loads vmlinuz (kernel) + initramfs into RAM
– Passes kernel parameters (command line)
|
v
[Linux Kernel starts] ← Control handed over
|
v
[initramfs /init]
|
v
[Real root filesystem mounted]
|
v
[systemd / PID 1] ← Normal Linux boot
As a kernel developer, you will regularly compile new kernels and need to switch between them. GRUB is how you select which kernel to boot. Knowing how to configure it well saves enormous time during development.
2. Understanding the GRUB2 Configuration System
Many beginners make a mistake when learning GRUB: they edit grub.cfg directly. Do not do this. The file is auto-generated and your changes will be overwritten.
GRUB2 uses a two-level configuration system:
/etc/default/grub ← Main user settings (timeout, default OS, etc.)
/etc/grub.d/ ← Scripts that generate menu entries
/etc/grub.d/00_header ← Sets global GRUB options
/etc/grub.d/10_linux ← Auto-detects installed Linux kernels
/etc/grub.d/30_os-prober ← Detects other OSes (Windows etc.)
/etc/grub.d/40_custom ← Your custom menu entries go hereThen run:
sudo update-grub ← (Ubuntu/Debian)
sudo grub2-mkconfig -o /boot/grub2/grub.cfg ← (Fedora/RHEL)This auto-generates:
/boot/grub/grub.cfg ← DO NOT EDIT THIS DIRECTLY
The workflow is always: edit /etc/default/grub → run update-grub → reboot. The generated grub.cfg is what GRUB actually reads at boot time.
3. Step-by-Step: Customizing GRUB for Kernel Development
Let’s go through the most useful customizations one by one. These are tested on Ubuntu 22.04+ and work on Debian-based systems. Fedora/RHEL equivalents are noted where different.
Step 1 — Back up the config file first (always)
Before touching any system config file, always make a backup. This takes two seconds and saves hours of pain:
sudo cp /etc/default/grub /etc/default/grub.orig
If anything goes wrong, you can restore the original:
sudo cp /etc/default/grub.orig /etc/default/grub
sudo update-grub
Step 2 — Open the config file
sudo nano /etc/default/grub
Or use vi if you prefer:
sudo vi /etc/default/grub
Step 3 — Make the boot menu visible
By default on Ubuntu, GRUB hides the menu and boots immediately. This is great for end users but terrible for developers. To always show the menu:
# Find this line:
GRUB_TIMEOUT_STYLE=hidden
# Change it to:
GRUB_TIMEOUT_STYLE=menu
On older systems or some distros you might see:
# Find:
GRUB_HIDDEN_TIMEOUT_QUIET=true
# Change to:
GRUB_HIDDEN_TIMEOUT_QUIET=false
Both achieve the same result: the boot menu appears every time you reboot.
Step 4 — Set a comfortable timeout
The timeout controls how long GRUB waits for your input before booting the default kernel automatically:
# Find:
GRUB_TIMEOUT=0 (or whatever value is there)
# Change to (10 seconds gives you enough time to choose):
GRUB_TIMEOUT=10
During active kernel development, setting it to something like 15 or 20 seconds means you always have time to select the right kernel, even if you are not sitting right in front of the machine when it boots.
Step 5 — Apply the changes
After editing the file, regenerate the GRUB config:
# Ubuntu/Debian:
sudo update-grub
# Fedora/RHEL/CentOS (BIOS):
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# Fedora/RHEL/CentOS (UEFI):
sudo grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg
You will see output showing that it found your installed kernels and wrote the new config. Then reboot:
sudo reboot
You should now see the GRUB menu with a list of available kernels to boot.
4. A Typical /etc/default/grub File Explained Line by Line
Here is what a typical file looks like, with every important line explained:
# /etc/default/grub — GRUB2 user configuration
# Which menu entry to boot by default
# 0 means the first entry (usually the latest kernel)
# You can also use the full menu entry name as a string
GRUB_DEFAULT=0
# How long to wait (in seconds) for user input
# Set to -1 to wait forever (useful during development)
GRUB_TIMEOUT=10
# Whether to show the menu (menu = always show)
GRUB_TIMEOUT_STYLE=menu
# Parameters passed to the kernel at boot
# quiet = suppress most boot messages
# splash = show graphical splash screen
# Remove both to see all kernel messages (useful for debugging)
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
# Parameters ALWAYS passed to the kernel (even in recovery mode)
GRUB_CMDLINE_LINUX=""
# Uncomment to disable graphical boot (useful on headless servers)
# GRUB_TERMINAL=console
# Resolution for the GRUB menu if using graphical mode
GRUB_GFXMODE=640x480
Two of these settings are especially important for kernel developers:
GRUB_CMDLINE_LINUX_DEFAULT— removequiet splashduring development so you can see all kernel boot messages on the screen.GRUB_DEFAULT— usesavedas the value to make GRUB remember the last kernel you manually selected. This is very useful when switching between kernels.
5. Passing Custom Kernel Parameters — A Kernel Developer’s Power Tool
Kernel parameters (also called the kernel command line) are key-value options passed from GRUB to the kernel at boot. They let you change kernel behavior without recompiling. This is incredibly useful during development and debugging.
Making boot messages visible
During kernel development, the default quiet mode hides everything. Change this in /etc/default/grub:
# BEFORE (production mode):
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
# AFTER (developer mode — see all kernel messages):
GRUB_CMDLINE_LINUX_DEFAULT=""
Useful kernel parameters for developers
| Parameter | What it does |
|---|---|
| debug | Enable maximum kernel debug output |
| loglevel=7 | Show all log levels (0=emergency to 7=debug) |
| initcall_debug | Print every initcall as it runs (slow but informative) |
| nomodeset | Disable GPU mode setting (use if screen goes black) |
| maxcpus=1 | Boot with only 1 CPU (useful to isolate SMP bugs) |
| mem=512M | Limit available RAM (test memory-constrained scenarios) |
| panic=5 | Auto-reboot 5 seconds after a kernel panic |
| rd.break | Drop into initramfs shell before mounting real root |
| systemd.unit=rescue.target | Boot into rescue mode (single user) |
| earlyprintk=ttyS0 | Send earliest kernel messages to serial port (UART) |
Adding parameters permanently vs. temporarily
To add parameters permanently (every boot), edit /etc/default/grub and run update-grub.
To add parameters temporarily (just for one boot — perfect for testing), do this at the GRUB menu:
- At the GRUB menu, highlight the kernel you want to boot
- Press E to edit the boot entry
- Find the line starting with
linux— this is the kernel command line - Move to the end of that line and type your extra parameters
- Press Ctrl+X or F10 to boot with those parameters
This temporary change does not affect your permanent GRUB config.
6. Managing Multiple Kernels — The Daily Reality of Kernel Development
When you build and install a custom kernel (as covered in the earlier steps of this chapter), you will have multiple kernel versions installed at the same time. GRUB automatically detects all installed kernels and creates menu entries for each one. This is the key reason kernel developers need to be comfortable with GRUB.
List all installed kernels
# Ubuntu/Debian:
dpkg --list | grep linux-image
# Or check what GRUB found after running update-grub:
grep -i "menuentry" /boot/grub/grub.cfg | grep linux
Set a specific kernel as default permanently
If you just installed a custom kernel and want to test it as the default for a while:
# Use grub-set-default with the menu entry number (0-indexed)
sudo grub-set-default 1 # Make the second entry the default
# Or use the full entry name (more reliable across updates):
sudo grub-set-default "Advanced options for Ubuntu>Ubuntu, with Linux 6.9.0-custom"
# Enable saved default mode in /etc/default/grub:
GRUB_DEFAULT=saved
# Then set which entry to boot:
sudo grub-set-default 0
sudo update-grub
Boot a specific kernel just once
This is extremely useful. You want to test your new kernel once, but if it panics, GRUB should go back to your working kernel automatically on next boot:
# Boot entry 1 (0-indexed) just once, then revert to GRUB_DEFAULT
sudo grub-reboot 1
sudo reboot
If your new kernel crashes, the next reboot automatically uses the default kernel. This safety net is invaluable when testing experimental code.
7. Important: GRUB on UEFI Systems (Most Modern Hardware)
Almost all hardware made after 2012 uses UEFI instead of the old BIOS. GRUB works on both, but there are some differences you need to know.
Firmware → MBR (first 512 bytes of disk) → GRUB Stage 1
→ GRUB Stage 2 (/boot/grub/) → KernelUEFI Boot:
Firmware → EFI System Partition (ESP) → GRUB EFI binary
(/boot/efi/EFI/ubuntu/grubx64.efi)
→ GRUB reads /boot/efi/EFI/ubuntu/grub.cfg or /boot/grub/grub.cfg
→ Kernel
On UEFI systems:
- There is a special partition called the EFI System Partition (ESP) usually mounted at
/boot/efi - The GRUB binary lives in the ESP, not in the MBR
- The config file
/etc/default/gruband theupdate-grubworkflow are the same — you do not need to change your workflow - If you have Secure Boot enabled, custom-compiled kernels need to be signed. Most developers disable Secure Boot in UEFI settings when doing kernel development
Check if your system uses UEFI or BIOS
# If this directory exists, you are on UEFI:
ls /sys/firmware/efi
# Or check boot mode:
[ -d /sys/firmware/efi ] && echo "UEFI" || echo "BIOS"
Tip: Getting to the GRUB menu on UEFI systems
On BIOS systems, you hold Shift during boot to show the GRUB menu. On UEFI systems, this sometimes does not work. The reliable way is to set GRUB_TIMEOUT_STYLE=menu and GRUB_TIMEOUT=10 as described earlier. That always works regardless of BIOS or UEFI.
8. Common GRUB Mistakes and How to Avoid Them
Mistake 1: Editing /boot/grub/grub.cfg directly
This file is auto-generated. Your changes will be overwritten the next time update-grub runs (which happens automatically when you install a new kernel). Always edit /etc/default/grub instead.
Mistake 2: Forgetting to run update-grub after editing
Editing /etc/default/grub and rebooting without running update-grub means your changes have no effect. The generated grub.cfg is still the old one.
Mistake 3: Not backing up before editing
A syntax error in /etc/default/grub can prevent update-grub from running successfully, which can leave you in a state where the system boots with an old config. Always cp /etc/default/grub /etc/default/grub.orig first.
Mistake 4: Deleting the old kernel before testing the new one
Always keep at least one known-good kernel installed. If your new custom kernel does not boot, you need the old one to fall back to. Use grub-reboot for safer testing.
Recovery tip: GRUB rescue mode
If GRUB itself gets corrupted (rare but possible), boot from a live USB, mount your root partition, chroot into it, and run:
sudo grub-install /dev/sda # for BIOS
sudo update-grub
For UEFI recovery, the process involves reinstalling grub-efi-amd64. But if you follow the practices in this tutorial and always back up first, you should never need this.
9. See What the Kernel Printed at Boot
Even if you booted with quiet splash and saw nothing on screen, the kernel saved all its boot messages. After booting, you can read them:
# See all kernel messages (including boot messages) — kernel 6.x:
dmesg | less
# See only the most recent boot's messages:
dmesg --follow # keep watching in real time
# Filter for specific topics:
dmesg | grep -i usb
dmesg | grep -i error
dmesg | grep -i memory
# On systemd systems, see all boot logs:
journalctl -b # current boot
journalctl -b -1 # previous boot
journalctl -b -2 # two boots ago (great for debugging crashes)
The journalctl -b -1 command is particularly powerful for kernel development. If your new kernel panicked during the previous boot, you can still read what it logged before crashing.
Interview Questions — GRUB Bootloader
Q1. What is the difference between GRUB Legacy and GRUB 2?
GRUB Legacy (version 0.9x) was the original GNU bootloader. GRUB 2 is a complete rewrite with modular architecture, scripting support, dynamic module loading, UEFI support, and the ability to read from many filesystem types directly. Almost all modern Linux distributions use GRUB 2. The user-visible difference is that GRUB 2 uses a generated grub.cfg that you should not edit directly, while GRUB Legacy used a simpler menu.lst that you edited manually.
Q2. Where does GRUB store its configuration and which file should you actually edit?
The generated runtime config is at /boot/grub/grub.cfg (BIOS) or /boot/efi/EFI/<distro>/grub.cfg (UEFI). You should never edit this directly. The user configuration is at /etc/default/grub, and custom menu entries go in /etc/grub.d/40_custom. After editing, run update-grub (Ubuntu/Debian) or grub2-mkconfig (Fedora/RHEL) to regenerate grub.cfg.
Q3. How would you make a system always show the GRUB menu and not auto-boot?
In /etc/default/grub, set GRUB_TIMEOUT_STYLE=menu and GRUB_TIMEOUT=-1. Setting the timeout to -1 means GRUB waits indefinitely for user input. Then run sudo update-grub.
Q4. What is grub-reboot and how does it help in kernel development?
grub-reboot N tells GRUB to boot menu entry number N just one time on the next reboot. After that, GRUB reverts to the normal default. This lets kernel developers safely test a new kernel: if it crashes, the next reboot uses the old stable kernel automatically. It prevents you from getting permanently stuck in a broken kernel.
Q5. What is the GRUB command line (kernel parameters) and name three parameters useful for kernel debugging?
The kernel command line is a set of parameters passed from GRUB to the kernel at boot. They control kernel behavior without requiring a recompile. Three useful ones for debugging: (1) debug — enables maximum kernel debug output, (2) initcall_debug — prints every kernel initcall as it runs, useful for finding what hangs during boot, (3) panic=5 — makes the kernel automatically reboot 5 seconds after a panic, useful for unattended test systems.
Q6. What is the EFI System Partition and why does GRUB care about it?
The EFI System Partition (ESP) is a FAT32-formatted partition required by the UEFI specification. On UEFI systems, the firmware looks in this partition for bootloader binaries. GRUB installs its EFI binary (grubx64.efi) here so the UEFI firmware can find and execute it. On Ubuntu it is typically mounted at /boot/efi. If this partition is corrupted or accidentally unmounted, the system will not boot.
Q7. How do you add a permanent kernel parameter to suppress verbose boot messages for a production system?
In /etc/default/grub, ensure GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" is set. The quiet parameter suppresses most kernel messages, and splash shows a graphical boot screen. Then run sudo update-grub to apply. Conversely, removing these two words makes the kernel print all messages to the console during boot.
Q8. Your custom kernel panics on boot. The system is in front of you. How do you get back to a working kernel right now?
At the GRUB menu, if it is visible, select the previous working kernel under “Advanced options.” If the menu is not visible, hold Shift (BIOS) or set GRUB_TIMEOUT_STYLE=menu before this situation happens. Once booted into the working kernel, investigate the panic using journalctl -b -1 to read messages from the previous (panicked) boot session. Fix the kernel bug, rebuild, and use grub-reboot for safer testing next time.
Chapter 3 Complete!
You have now learned the full initramfs + GRUB bootloader flow. Next up: kernel modules — writing your first kernel module, loading and unloading it, and understanding the module lifecycle.
