GRUB2 Bootloader Configuration-Free Linux kernel development course

 

Previous Lecture                                                                                                                                                                                                            Next Lecture

GRUB2 Bootloader Configuration
Chapter 3 · Linux Kernel Development Series · EmbeddedPathashala
Setting timeout · Choosing default kernel · Booting your custom kernel
🥾
Bootloader
⚙️
GRUB2
🐧
Kernel 6.x
🆓
Free Course

What you will learn in this tutorial

You have compiled your first custom Linux kernel. Now what? Before you can actually run it,
you need to tell your system which kernel to boot. That is the job of the bootloader —
in almost all Linux systems today, that is GRUB2 (GNU GRand Unified Bootloader version 2).

In this tutorial you will understand exactly what GRUB2 does, how to control the boot timeout,
how to select which kernel boots by default, and how to safely boot your freshly compiled kernel
without losing the ability to fall back to your original one.

Topics covered
GRUB2 overview
GRUB timeout settings
Default kernel selection
/etc/default/grub
update-grub command
Booting custom kernel
Kernel fallback strategy
Linux 6.x boot process

What exactly is GRUB2?

When you press the power button, your computer’s firmware (BIOS or UEFI) does some hardware checks
and then hands over control to the bootloader. On most Linux systems, that bootloader is GRUB2.

GRUB2’s main job is simple: present you a menu of kernels and let you pick one. Once you pick
(or the timeout expires and it picks automatically), GRUB2 loads that kernel image into memory,
passes some parameters to it, and steps aside. The kernel takes over from there.

Linux Boot Flow — From Power-On to Kernel Running
1. Power ON
Hardware initialises
2. BIOS / UEFI
POST, finds boot device
3. GRUB2
Shows kernel menu, loads kernel
4. Linux Kernel
Boots, mounts rootfs, runs init

GRUB2 reads its configuration from /boot/grub/grub.cfg. But here is the important rule:
you must never edit that file directly. It is auto-generated. All your changes
go into /etc/default/grub, and after saving, you run sudo update-grub
to regenerate grub.cfg from your settings.

GRUB2 Configuration — How it works
You edit this:
/etc/default/grub
Simple key=value settings. Safe to edit.
+

/etc/grub.d/ scripts
sudo
update-grub
Auto-generated (do NOT touch):
/boot/grub/grub.cfg
Complex GRUB script. Regenerated every time.

Controlling the GRUB boot menu timeout

When GRUB2 shows its menu, it waits for a few seconds before automatically booting the default
kernel. This wait time is set by the GRUB_TIMEOUT directive inside
/etc/default/grub.

By default in Ubuntu and many Debian-based distros, the timeout is set to a short duration or even
hidden. When you are doing kernel development, you want to see the menu and be able to pick your
newly compiled kernel. So you need to make the menu visible and give yourself enough time to choose.

Step-by-step: Making the GRUB menu visible and setting the timeout

1

Open the GRUB defaults file with superuser privileges:

sudo nano /etc/default/grub
2
Find the GRUB_TIMEOUT line and set it to how many seconds you want the menu to wait.
A value of 5 or 10 seconds is comfortable for development:

GRUB_TIMEOUT=5

The special values 0 (boot immediately, skip menu) and -1 (wait forever, never auto-boot) also work.

3
Make sure the menu is actually shown and not hidden. Look for a line with
GRUB_TIMEOUT_STYLE. If it says hidden, change it to menu:

GRUB_TIMEOUT_STYLE=menu

If you see a line like GRUB_HIDDEN_TIMEOUT=1, comment it out by putting a # in front:

#GRUB_HIDDEN_TIMEOUT=1
4

Save the file and apply your changes:

sudo update-grub

This command scans your /boot directory, finds all installed kernels, and regenerates
the grub.cfg file. It also typically refreshes the initramfs images.

📝 Note for modern Ubuntu (22.04 / 24.04 and later):
In newer Ubuntu versions the old GRUB_HIDDEN_TIMEOUT directive is no longer used.
The correct setting to control menu visibility is GRUB_TIMEOUT_STYLE.
Set it to menu so the boot menu always appears. The deprecated
GRUB_HIDDEN_TIMEOUT_QUIET setting from older tutorials can be safely ignored
on Linux 6.x systems.

GRUB_TIMEOUT behaviour — visual summary
Setting value What happens When to use
GRUB_TIMEOUT=0 Boots immediately, no menu shown Production systems, not for development
GRUB_TIMEOUT=5 Menu shows for 5 seconds then auto-boots default Good for kernel development (recommended)
GRUB_TIMEOUT=10 Menu shows for 10 seconds If you need more time to read and decide
GRUB_TIMEOUT=-1 Menu waits indefinitely, never auto-boots Debugging sessions where you always want to choose

Choosing which kernel boots by default

GRUB2 can have multiple kernels listed in its menu. Think about it — when you install a new kernel,
the old one does not disappear. Both are available. The GRUB_DEFAULT setting in
/etc/default/grub decides which one boots automatically when the timeout runs out.

Method 1 — Boot by position (simplest)

By default, GRUB_DEFAULT=0 means “boot the first entry in the menu”, which is always
the most recently installed kernel. This is usually what you want for development — install your
new kernel and it automatically becomes the first entry.

# Boot the first (newest) kernel — this is the default behaviour
GRUB_DEFAULT=0

Method 2 — Boot by exact name (precise control)

If you want to lock in a specific kernel regardless of what else gets installed, you can use its
full name. First, check what kernels are available on your system:

# List all kernel entries that GRUB knows about
grep -E "^menuentry|submenu" /boot/grub/grub.cfg | cut -d "'" -f2

You will see output similar to this (the exact kernel versions will differ on your machine):

Ubuntu
Advanced options for Ubuntu
Ubuntu, with Linux 6.8.0-60-generic
Ubuntu, with Linux 6.8.0-60-generic (recovery mode)
Ubuntu, with Linux 6.8.0-mykernel
Ubuntu, with Linux 6.8.0-mykernel (recovery mode)

If the kernel you want is inside the “Advanced options” submenu (which is common in modern Ubuntu),
you must include the submenu name using a > separator:

GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-mykernel"
⚠️ Important: When you use an exact kernel name in GRUB_DEFAULT,
the setting does not update automatically when a new kernel is installed.
You have to come back and change it manually, then run sudo update-grub again.
For day-to-day kernel development, using GRUB_DEFAULT=0 (always boot newest) or
the “saved” method below is usually more practical.

Method 3 — Remember the last boot choice (most flexible)

There is a handy option that makes GRUB2 remember whatever you booted last time and use it again
next time. This is great during development — you can pick your custom kernel once and it keeps
booting it:

GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true

With this setup, whatever you select from the GRUB menu on one boot becomes the automatic choice
for all future boots — until you change it again from the menu.

Three ways to set the default kernel — comparison
Method Setting Pros Cons
By position GRUB_DEFAULT=0 Simple, no maintenance Always picks newest — may not be what you want
By name GRUB_DEFAULT="submenu>entry" Very precise control Must update manually after every kernel change
By last choice GRUB_DEFAULT=saved Remembers your pick automatically Requires GRUB_SAVEDEFAULT=true too

Applying your GRUB changes

Every time you edit /etc/default/grub, you must run this command to regenerate the
actual GRUB configuration:

sudo update-grub

On Fedora and RHEL-based systems, the equivalent command is:

# Fedora / RHEL / Rocky Linux
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

After running update-grub, you are ready to reboot:

sudo reboot

What the GRUB menu looks like at boot time

When your machine restarts, if the GRUB menu is configured to show, you will see a simple text menu.
Here is how to understand what you are seeing:

Typical GRUB2 Menu Structure (modern Ubuntu / Debian)
GNU GRUB version 2.12
▶ Ubuntu (latest distro kernel — visible on main menu)
  Recovery mode for Ubuntu
  Advanced options for Ubuntu (submenu — press Enter to expand)
    ↳ Ubuntu, with Linux 6.8.0-mykernel
    ↳ Ubuntu, with Linux 6.8.0-mykernel (recovery mode)
    ↳ Ubuntu, with Linux 6.8.0-60-generic
    ↳ Ubuntu, with Linux 6.8.0-60-generic (recovery mode)

A few things to notice here:

  • Modern Ubuntu (20.04 and later) shows the latest kernel directly on the main menu. Older kernels are inside the “Advanced options” submenu.
  • Every kernel gets a matching recovery mode entry. This boots the kernel with a minimal set of services and gives you a root shell — useful when a new kernel breaks something.
  • The default entry (the one GRUB will auto-boot) is marked with an asterisk * or highlighted.
💡 How to navigate the GRUB menu at boot:
Use the ↑ ↓ arrow keys to move between entries.
Press Enter to boot the highlighted entry.
Press e to temporarily edit the boot command (useful for debugging).
Press c to get a GRUB command-line.
Press any key (except Enter) to stop the countdown timer.

Safety strategy — never delete your original kernel

When you are doing kernel development, you will compile and install multiple kernels.
A very important rule: never delete your original distribution kernel.

Think about what happens if your custom kernel has a bug and fails to boot — perhaps a driver
crashes early, or the filesystem support is not compiled in. You need a working kernel to fall
back to so you can fix the issue and try again. The distro kernel is your safety net.

Kernel Development — Recommended Boot Strategy
✅ Recommended approach
  1. Keep original distro kernel installed
  2. Install your custom kernel alongside it
  3. Set GRUB_TIMEOUT to 5+ seconds
  4. Try booting your custom kernel
  5. If it fails — select distro kernel from GRUB menu
  6. Fix the issue and reinstall
❌ Dangerous approach
  1. Delete old distro kernel to save space
  2. Install custom kernel
  3. Custom kernel fails to boot
  4. No fallback — system is unbootable
  5. Need USB rescue drive to recover
⚠️ Worst-case scenario: If all your kernels somehow fail to boot and you have
no recovery option, you can boot a live Linux system from a USB drive. From there you can mount
your root filesystem, chroot into it, and reinstall or fix a kernel. This is advanced recovery
but knowing it exists reduces the fear of experimentation.

A complete working /etc/default/grub for kernel development

Here is a clean example of what a good /etc/default/grub looks like when you are
actively doing kernel development on Ubuntu 22.04 / 24.04:

# /etc/default/grub — Kernel development setup

# Boot the most recently installed kernel by default
GRUB_DEFAULT=0

# Always show the GRUB menu (do not hide it)
GRUB_TIMEOUT_STYLE=menu

# Wait 5 seconds for user input before auto-booting
GRUB_TIMEOUT=5

# Distro name for GRUB display
GRUB_DISTRIBUTOR=`lsb_release -i -s 2>/dev/null || echo Debian`

# Kernel boot parameters (remove 'quiet splash' to see boot messages)
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""

After saving this file, always run:

sudo update-grub
💡 Tip for kernel debugging: During development, change GRUB_CMDLINE_LINUX_DEFAULT
from "quiet splash" to just "" (empty string). This removes the splash
screen and shows all kernel boot messages on the console, making it much easier to spot where
the boot process fails if something goes wrong.

Interview Questions — GRUB2 and Kernel Boot

Q1. What is GRUB2 and what role does it play in the Linux boot process?
GRUB2 (GNU GRand Unified Bootloader version 2) is the bootloader used by most modern Linux
distributions. After the system firmware (BIOS or UEFI) completes its hardware checks, it
hands control to GRUB2. GRUB2 then reads its configuration, presents a menu of available
kernels, loads the selected kernel image and its initramfs into memory, and passes control
to the kernel. GRUB2 itself is no longer involved once the kernel starts running.
Q2. Why should you never directly edit /boot/grub/grub.cfg?
/boot/grub/grub.cfg is an auto-generated file. Running sudo update-grub
completely overwrites it. Any manual changes you make will be lost the next time update-grub
runs — for example when you install a new kernel. The correct approach is to edit
/etc/default/grub for user-level settings, then let update-grub
regenerate grub.cfg from that and from the scripts in /etc/grub.d/.
Q3. What happens when GRUB_TIMEOUT is set to 0? When would you use -1?
When GRUB_TIMEOUT=0, GRUB boots the default kernel immediately without showing
any menu. This is typical for production servers where you never want user interaction at boot.
GRUB_TIMEOUT=-1 makes GRUB wait indefinitely — the system will never auto-boot
and will sit at the GRUB menu until someone presses Enter. This is useful in debugging scenarios
where you always want to manually confirm which kernel to boot.
Q4. How do you tell GRUB2 to boot a kernel that is inside a submenu?
In modern Ubuntu/Debian systems, only the newest kernel appears on the main GRUB menu. Older
kernels are inside the “Advanced options for Ubuntu” submenu. To set one of those as the default,
you use the submenu name and the entry name separated by a > character in
GRUB_DEFAULT. For example:GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-mykernel"After editing, run sudo update-grub for the change to take effect.

Q5. What is the difference between GRUB_DEFAULT=saved and GRUB_SAVEDEFAULT=true?
These two work together. GRUB_DEFAULT=saved tells GRUB to look up a previously
saved entry and boot that, rather than using a hardcoded position or name.
GRUB_SAVEDEFAULT=true tells GRUB to automatically save whatever the user picks
from the menu as the new default for next time. You need both set together for the
“remember last choice” behaviour to work correctly.
Q6. Why is it important to keep the original distro kernel when installing a custom compiled kernel?
A freshly compiled kernel can fail to boot due to missing drivers, wrong configuration options,
or any number of bugs introduced during development. If you deleted the original distro kernel
and your custom kernel fails, you are left with an unbootable system. Keeping the original
kernel gives you a reliable fallback — you can select it from the GRUB menu, boot into a working
system, diagnose what went wrong, fix the issue, and try again. It is a basic safety practice
for kernel development.
Q7. What command regenerates the GRUB configuration and when must you run it?
The command is sudo update-grub on Ubuntu/Debian systems (equivalent to
sudo grub-mkconfig -o /boot/grub/grub.cfg). You must run it any time you change
/etc/default/grub, install a new kernel, or modify anything in /etc/grub.d/.
Without running it, your changes have no effect because /boot/grub/grub.cfg — the
file GRUB actually reads at boot — has not been updated yet.
Q8. What does the ‘e’ key do in the GRUB menu and why is it useful for kernel developers?
Pressing e in the GRUB menu opens a temporary editor that lets you modify the
kernel boot parameters for that single boot. Changes made this way are not saved permanently —
they only apply to the current boot. This is extremely useful for kernel developers because
you can add debugging parameters (like debug, earlyprintk,
ignore_loglevel), change the root device, or disable specific subsystems to
narrow down a boot failure — all without permanently modifying your GRUB configuration.

Continue Learning — Free Linux Kernel Development Course

EmbeddedPathashala is a completely free educational platform covering Linux kernel programming,
embedded systems, Bluetooth/BLE development, and Linux device drivers. All content is written
by working embedded engineers for students and professionals.

Previous Lecture                                                                                                                                                                                                  Next Lecture

Leave a Reply

Your email address will not be published. Required fields are marked *