GRUB2 and UEFI Bootloader Manager
System engineer managing the GRUB2 bootloader in UEFI environments — configuring boot entries, integrating Secure Boot via Shim signing, setting up multi-boot systems, tuning kernel parameters, performing recovery operations, and chain-loading network boot configurations.
TL;DR Checklist
- Verify ESP is mounted at
/boot/efiwith FAT32 filesystem and 512 MiB minimum size - Confirm UEFI firmware mode with
efibootmgr --verbosebefore any bootloader changes - Set kernel parameters in
/etc/default/grub, never editgrub.cfgdirectly - Generate new GRUB config with
grub-mkconfig -o /boot/grub2/grub.cfg(RHEL) orupdate-grub(Debian) - For Secure Boot: sign kernel and initramfs with
sbsignusing Shim/MOK key pair - Validate boot entries with
efibootmgrafter every GRUB reinstall - Test bootloader recovery procedure on non-production systems before relying on it
When to Use
Use this skill when:
- Installing or reinstalling GRUB2 on a UEFI system, including ESP layout and bootloader file placement
- Repairing a broken bootloader after a Windows update, disk change, or failed OS upgrade (chroot recovery)
- Configuring dual-boot systems with Linux alongside Windows or other operating systems
- Integrating Secure Boot by signing kernels, initramfs, and GRUB itself with MOK/Shim keys
- Managing UEFI boot entries — adding, deleting, reordering, or fixing broken NVRAM boot entries
- Tuning kernel command line parameters for console output, crash dumps, quiet splash, or network debugging
- Setting up chain-loading for iPXE, PXE network boot, or other bootloaders from within GRUB menu
- Diagnosing boot failures — missing ESP, incorrect UUID references in GRUB config, or firmware NVRAM corruption
When NOT to Use
Avoid this skill for:
- BIOS/legacy (MBR) boot systems — use
grub-installwith a disk device target instead of EFI target; UEFI and BIOS are fundamentally different boot paths - Replacing GRUB entirely — if you want systemd-boot, rEFInd, or another bootloader, that is a separate decision outside GRUB scope
- Firmware-level issues — if the system won't POST, has firmware bugs, or Secure Boot key enrollment is failing at UEFI level, diagnose in firmware first
- Application-level boot problems — services failing after boot, user session issues, or systemd unit failures are not bootloader concerns
Use linux-security for full Secure Boot key management including TPM integration and MOK enrollment workflows. Use kernel-tuning for deeper kernel parameter optimization beyond what GRUB passes at boot time.
Core Workflow
1. Verify UEFI Mode and ESP Layout
Before any bootloader work, confirm the system is in UEFI mode and the EFI System Partition exists with correct properties.
# Check if booted in UEFI mode (file exists only on UEFI systems)
[[ -d /sys/firmware/efi ]] && echo "UEFI mode" || echo "Legacy BIOS mode"
# List all partitions and their types (look for EFI System type: EF00)
lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL | grep -E 'efi|ESP'
# Check ESP mount point — should be FAT32 mounted at /boot/efi
mount | grep efivarfs # UEFI variables filesystem
findmnt -T /boot/efi # Verify what is mounted on ESP
# Typical ESP layout:
# /dev/nvme0n1p1 vfat 512M /boot/efi EFI
# Inspect ESP contents — should have GRUB and possibly other bootloaders
ls -la /boot/efi/EFI/
# Expected output:
# /boot/efi/EFI/BOOT/ — fallback boot directory
# /boot/efi/EFI/ubuntu/ — or distro-specific bootloader files
# /boot/efi/EFI/Microsoft/ — Windows bootloader (if dual-boot)
# Check current UEFI boot entries in NVRAM
sudo efibootmgr -v
Checkpoint: System is confirmed UEFI, ESP is FAT32 and mounted at /boot/efi, and lsblk shows at least one EFI System partition (type EF00). Proceed only if these conditions are met.
2. Configure GRUB Defaults
Edit /etc/default/grub to set kernel parameters, menu behavior, and visual options. Never edit grub.cfg directly — it is auto-generated and will be overwritten.
# Edit GRUB default configuration (Debian/Ubuntu)
sudoedit /etc/default/grub
# Key parameters to configure:
# ---------------------------------
GRUB_DEFAULT=0 # Default menu entry (0-indexed) or "saved" with GRUB_SAVEDEFAULT
GRUB_TIMEOUT=5 # Seconds before auto-booting default entry
GRUB_TIMEOUT_STYLE=menu # "menu" shows countdown; "hidden" hides it entirely
GRUB_DISTRIBUTOR="$(lsb_release -i -s 2> /dev/null || echo Debian)"
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=3"
GRUB_CMDLINE_LINUX="" # Parameters for both default and recovery entries
# Common kernel parameters:
# console=tty0,console=ttyS0,115200n8 — Console output (local + serial)
# crashkernel=auto — Reserve memory for kdump crash dump capture
# rd.auto=1 — Automatically discover and mount root devices
# nomodeset — Skip kernel mode setting (fallback for GPU issues)
# reboot=warm — Warm reboot instead of cold reset
# nosmp — Disable SMP (single-core, debugging)
# For systemd-boot detection, disable GRUB's OS-prober scanning Windows
# GRUB_DISABLE_OS_PROBER=true — Only if you manage boot entries manually via efibootmgr
# Save and regenerate GRUB configuration
sudo grub-mkconfig -o /boot/grub2/grub.cfg # RHEL / Fedora / Arch
# OR
sudo update-grub # Debian / Ubuntu
Checkpoint: /etc/default/grub contains desired parameters, grub.cfg is regenerated successfully with no errors, and the new configuration includes expected kernel command line options. Verify by inspecting the generated file: grep GRUB_CMDLINE_LINUX_DEFAULT /boot/grub2/grub.cfg.
3. Install/Reinstall GRUB to ESP
Install GRUB EFI binary to the correct location on the ESP.
# Identify the ESP partition device
ESP_DEV=$(findmnt -n -o SOURCE /boot/efi)
echo "ESP device: $ESP_DEV"
# Install GRUB to UEFI target (this places grubx64.efi and related files on ESP)
sudo grub-install \
--target=x86_64-efi \
--efi-directory=/boot/efi \
--bootloader-id=ubuntu \
--recheck \
--no-nvram
# Parameters explained:
# --target=x86_64-efi — EFI x86_64 target (required for UEFI)
# --efi-directory — Mount point of the ESP
# --bootloader-id — Name of the directory under /boot/efi/EFI/ (becomes the NVRAM label)
# --recheck — Re-check partition table even if cached
# --no-nvram — Do not modify NVRAM boot entries (safe for manual entry management)
# Expected files installed:
# /boot/efi/EFI/ubuntu/grubx64.efi — GRUB EFI binary (signed or unsigned)
# /boot/efi/EFI/ubuntu/shimx64.efi — Shim bootloader (for Secure Boot chain)
# /boot/efi/EFI/ubuntu/grub.cfg — Standalone copy of grub.cfg
# Verify installation
ls -la /boot/efi/EFI/ubuntu/
Checkpoint: grubx64.efi exists under /boot/efi/EFI/<bootloader-id>/, grub.cfg is present in the same directory, and no errors were reported by grub-install. If Secure Boot is enabled, verify signing (see Section 5).
4. Manage UEFI Boot Entries with efibootmgr
Add, remove, or reorder boot entries stored in firmware NVRAM.
# List all current boot entries with verbose file paths
sudo efibootmgr -v
# Expected output format:
# BootCurrent: 0001
# Timeout: 5 seconds
# BootOrder: 0001,0002,0000
# Boot0000* Windows Boot Manager — HD(1,GPT,...)/File(\EFI\MICROSOFT\BOOT\BOOTMGFW.EFI)
# Boot0001* ubuntu — HD(1,GPT,...)/File(\EFI\UBUNTU\GRUBX64.EFI)
# Boot0002* rEFInd — HD(1,GPT,...)/File(\EFI\REFIND\REFIND_X64.EFI)
# Add a new boot entry for GRUB (replace values from efibootmgr -v output)
sudo efibootmgr \
--create \
--disk /dev/nvme0n1 \
--part 1 \
--label "Ubuntu GRUB" \
--loader '\EFI\ubuntu\grubx64.efi'
# Set boot order (first entry boots automatically)
sudo efibootmgr --bootorder 0001,0002,0000
# Delete a boot entry by number
sudo efibootmgr --deleteboot 0002
# Set timeout directly from NVRAM
sudo efibootmgr --timeout 10
# Enable/disable a boot entry (toggle the '*' asterisk)
sudo efibootmgr --bootnum 0003 --write-signature
# Reset boot order to default (distribution-specific)
sudo efibootmgr --bootorder "$(efibootmgr | grep BootOrder | cut -d',' -f1 | sed 's/BootOrder=//')"
Checkpoint: efibootmgr -v shows the desired boot entries with correct loader paths, and the boot order places preferred systems first. Verify the system boots into the intended default OS after a reboot.
5. Secure Boot Integration: Signing Kernels with Shim/MOK
When Secure Boot is enabled in firmware, all bootloader components must be signed with a trusted key enrolled in MOK (Machine Owner Key) or the Microsoft PK.
# --- Method 1: Using sbsign (manual signing workflow) ---
# Generate your own signing keys (one-time setup)
openssl req -new -x509 -newkey rsa:4096 -keyout MOK.priv \
-outform DER -out MOK.der -nodes -days 36500 \
-subj "/CN=Custom MOK Key/"
# Convert DER to PEM for use with mokutil
openssl x509 -in MOK.der -inform DER -out MOK.pem
# Sign the kernel
sudo sbsign --key MOK.priv --cert MOK.pem --output /boot/vmlinuz-$(uname -r) /boot/vmlinuz-$(uname -r)
# Sign the initramfs
sudo sbsign --key MOK.priv --cert MOK.pem --output /boot/initrd.img-$(uname -r) /boot/initrd.img-$(uname -r)
# Sign GRUB EFI binary
sudo sbsign --key MOK.priv --cert MOK.pem \
--output /boot/efi/EFI/ubuntu/grubx64.efi \
/usr/lib/grub/x86_64-efi-signed/grub-signed-x64.efi
# Enroll the MOK key via mokutil (triggers MOK Manager at next boot)
sudo mokutil --import MOK.der
# --- Method 2: Using sbctl (modern automated workflow — recommended) ---
# Install sbctl (Debian/Ubuntu: from source or AUR equivalent)
git clone https://github.com/antiwave/sbctl.git
cd sbctl
make && sudo make install
# Generate or import keys
sudo sbctl setup-keys
# Enroll the Microsoft PK to enable full Secure Boot (requires reboot)
sudo sbctl enroll-microsoft-keys
# Sign all relevant boot files automatically
sudo sbctl sign-all
# Verify signatures on boot files
sbctl verify /boot/vmlinuz-$(uname -r)
sbctl verify /usr/lib/grub/x86_64-efi-signed/grub-signed-x64.efi
# Expected output:
# ✓ /boot/vmlinuz-6.1.0-generic signed with key db.key
# ✓ /usr/lib/grub/x86_64-efi-signed/grub-signed-x64.efi signed with key db.key
Checkpoint: All boot components (vmlinuz, initrd.img, grubx64.efi) are signed and verify correctly. The MOK key is enrolled (visible via mokutil --list-enrolled). After reboot, Secure Boot should be active without requiring manual MOK Manager intervention.
6. Multi-Boot Configuration: Dual Boot with Windows
Configure GRUB to detect and chain-load Windows alongside Linux.
# Enable OS Prober to detect Windows installations
sudoedit /etc/default/grub
# Set (or uncomment):
GRUB_DISABLE_OS_PROBER=false
# Install os-prober if not already installed
sudo apt install os-prober ntfs-3g # Debian/Ubuntu
sudo dnf install os-prober ntfs-utils # RHEL/Fedora
# Manually detect additional OS installations
sudo os-prober
# Expected output:
# /dev/nvme0n1p3@/EFI/Microsoft/Boot/bootmgfw.efi:Windows Boot Manager:Windows:efi
# Regenerate GRUB configuration (now includes Windows entry)
sudo update-grub # Debian/Ubuntu
# OR
sudo grub-mkconfig -o /boot/grub2/grub.cfg # RHEL/Fedora
# Verify the generated config contains the Windows menuentry
grep -A5 "Windows Boot Manager" /boot/grub/grub.cfg
Checkpoint: os-prober detects the Windows installation, grub.cfg includes a valid menu entry for Windows Boot Manager with correct EFI path. The system boots into GRUB menu showing both Linux and Windows options.
7. Bootloader Recovery via Chroot
Repair a broken bootloader when the system cannot boot into either OS. Use a live USB environment.
# --- Step 1: Boot from live USB and identify partitions ---
lsblk
# Expected layout:
# nvme0n1
# ├─nvme0n1p1 vfat 512M /boot/efi ← ESP
# ├─nvme0n1p2 ext4 50G / ← Linux root
# └─nvme0n1p3 ntfs 200G C: ← Windows
# --- Step 2: Mount the Linux root partition ---
sudo mount /dev/nvme0n1p2 /mnt
# --- Step 3: Bind-mount virtual filesystems for chroot ---
for dir in /dev /dev/pts /proc /sys /run; do
sudo mount --bind "$dir" "/mnt$dir"
done
# --- Step 4: Mount the ESP (EFI System Partition) ---
sudo mount /dev/nvme0n1p1 /mnt/boot/efi
# --- Step 5: Enter the chroot environment ---
sudo chroot /mnt
# --- Step 6: Inside chroot — reinstall GRUB to ESP ---
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck
# --- Step 7: Regenerate GRUB config inside chroot ---
update-grub # Debian/Ubuntu
# OR
grub-mkconfig -o /boot/grub2/grub.cfg # RHEL/Fedora
# --- Step 8: Re-add NVRAM boot entry (if missing) ---
efibootmgr --create \
--disk /dev/nvme0n1 \
--part 1 \
--label "Ubuntu" \
--loader '\EFI\ubuntu\grubx64.efi'
# --- Step 9: Exit chroot and clean up ---
exit
sudo umount -R /mnt # Unmount all bindings recursively
# --- Step 10: Reboot into repaired system ---
sudo reboot
# --- Verify recovery ---
# After boot, confirm:
efibootmgr -v | grep ubuntu # Boot entry exists in NVRAM
cat /proc/cmdline # Kernel parameters loaded correctly
Checkpoint: System boots successfully into the repaired installation. efibootmgr shows a valid GRUB entry, kernel parameters from /etc/default/grub are applied (check via cat /proc/cmdline), and both Linux and Windows are detectable.
Implementation Patterns
Pattern 1: Kernel Command Line Parameter Management
Use helper scripts to manage kernel parameters safely without manual editing of /etc/default/grub.
#!/usr/bin/env bash
# kernel-params.sh — Manage GRUB kernel command line parameters
# Usage: ./kernel-params.sh [--add <param>] [--remove <param>] [--show] [--verify]
set -euo pipefail
GRUB_CONF="/etc/default/grub"
PARAMS_FILE="/tmp/kernel_params_work"
usage() {
echo "Usage: $0 [--add <key> | --remove <key> | --show | --verify]"
echo ""
echo " --add <key> Append parameter to GRUB_CMDLINE_LINUX_DEFAULT"
echo " --remove <key> Remove parameter from GRUB_CMDLINE_LINUX_DEFAULT"
echo " --show Display current kernel parameters"
echo " --verify Verify parameters were applied after grub-mkconfig"
}
extract_default_params() {
grep '^GRUB_CMDLINE_LINUX_DEFAULT=' "$GRUB_CONF" | sed 's/^GRUB_CMDLINE_LINUX_DEFAULT=//;s/^"//;s/"$//'
}
update_default_params() {
local current="$1"
local quoted="\"${current}\""
sudo sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=${quoted}|" "$GRUB_CONF"
}
add_param() {
local param="$1"
local current
current=$(extract_default_params)
# Check if parameter already exists (avoid duplicates)
if echo "$current" | grep -qw "$param"; then
echo "Parameter '$param' already present. Skipping."
return 0
fi
local new_params="${current:+$current }${param}"
update_default_params "$new_params"
echo "Added: $param → GRUB_CMDLINE_LINUX_DEFAULT=\"${new_params}\""
# Regenerate config
if command -v grub-mkconfig &>/dev/null; then
sudo grub-mkconfig -o /boot/grub2/grub.cfg
elif command -v update-grub &>/dev/null; then
sudo update-grub
fi
}
remove_param() {
local param="$1"
local current
current=$(extract_default_params)
if ! echo "$current" | grep -qw "$param"; then
echo "Parameter '$param' not found. Skipping."
return 0
fi
local new_params
new_params=$(echo "$current" | sed "s/\\b${param}\\b//g; s/ */ /g; s/^ //; s/ $//")
update_default_params "$new_params"
echo "Removed: $param → GRUB_CMDLINE_LINUX_DEFAULT=\"${new_params}\"
if command -v grub-mkconfig &>/dev/null; then
sudo grub-mkconfig -o /boot/grub2/grub.cfg
elif command -v update-grub &>/dev/null; then
sudo update-grub
fi
}
show_params() {
local current
current=$(extract_default_params)
echo "Current GRUB_CMDLINE_LINUX_DEFAULT parameters:"
echo " $current"
echo ""
echo "Currently running kernel parameters (cat /proc/cmdline):"
cat /proc/cmdline 2>/dev/null || echo " (cannot read from live system)"
}
verify_params() {
local current
current=$(extract_default_params)
local quoted="\"${current}\""
# Check generated config matches defaults
if command -v grub-mkconfig &>/dev/null; then
if grep -q "GRUB_CMDLINE_LINUX_DEFAULT=${quoted}" /boot/grub2/grub.cfg 2>/dev/null; then
echo "✓ Generated grub.cfg matches /etc/default/grub"
else
echo "⚠ WARNING: grub.cfg may not reflect current /etc/default/grub settings"
echo " Run 'sudo update-grub' or 'sudo grub-mkconfig -o /boot/grub2/grub.cfg'"
fi
elif command -v update-grub &>/dev/null; then
if grep -q "GRUB_CMDLINE_LINUX_DEFAULT=${quoted}" /boot/grub/grub.cfg 2>/dev/null; then
echo "✓ Generated grub.cfg matches /etc/default/grub"
else
echo "⚠ WARNING: grub.cfg may not reflect current settings"
fi
fi
# Show running kernel params for comparison
local running
running=$(cat /proc/cmdline 2>/dev/null || echo "")
if [[ -n "$running" ]]; then
echo ""
echo "Running kernel cmdline:"
echo " $running"
# Check if new parameters appear in running system
for p in $current; do
if echo "$running" | grep -qw "$p"; then
echo " ✓ $p present in running kernel"
fi
done
fi
}
# Argument parsing
case "${1:-}" in
--add)
[[ -z "${2:-}" ]] && { echo "Error: --add requires a parameter name" >&2; exit 1; }
add_param "$2"
;;
--remove)
[[ -z "${2:-}" ]] && { echo "Error: --remove requires a parameter name" >&2; exit 1; }
remove_param "$2"
;;
--show) show_params ;;
--verify) verify_params ;;
*) usage ;;
esac
Pattern 2: iPXE Chain-Loading from GRUB
Configure GRUB to chain-load an iPXE bootloader for network-based installation or PXE boot.
# --- Step 1: Download and prepare iPXE image ---
sudo mkdir -p /boot/efi/EFI/ipxe
sudo wget -O /boot/efi/EFI/ipxe/ipxe-x86_64.efi \
https://rom-o-matic.net/generate/ipxe-x86_64.efi?options=pni%20sse4.1%20pxe%20ndis
# Alternative: build iPXE from source with specific options
# git clone https://github.com/ipxe/ipxe.git
# cd ipxe/src
# make -j$(nproc) EMBED=netboot.ipxe bin/x86_64-efi/ipxe.efi
# --- Step 2: Create iPXE config that PXE boots from a specified server ---
cat > /boot/eth0.ipxe << 'IPXEOF'
#!ipxe
# iPXE script: boot from network via DHCP + TFTP/PXE
# Customize NEXTSERVER and image URL as needed
set next-server 192.168.1.10
imgfetch tftp://${next-server}/boot/vmlinuz /vmlinuz
imgfetch tftp://${next-server}/boot/initrd.img /initrd.img
boot || echo "Boot failed" && shell
IPXEOF
# --- Step 3: Add GRUB menu entry for iPXE chain-load ---
cat >> /etc/grub.d/40_custom << 'GRUBEOF'
menuentry "Network Boot (iPXE)" --class network {
set root=(hd0,gpt1)
linux16 /EFI/ipxe/ipxe-x86_64.efi
}
GRUBEOF
# --- Step 4: Regenerate GRUB configuration ---
sudo update-grub # Debian/Ubuntu
# OR
sudo grub-mkconfig -o /boot/grub2/grub.cfg # RHEL/Fedora
# Verify the iPXE entry appears in the menu
grep -A3 "Network Boot" /boot/grub/grub.cfg
Checkpoint: ipxe-x86_64.efi exists on ESP, /etc/grub.d/40_custom contains the chain-load entry, and grub.cfg includes a "Network Boot (iPXE)" menuentry. The iPXE script points to a valid TFTP server with bootable kernel + initramfs images.
Pattern 3: Boot Failure Diagnostics Script
Automated diagnostics for common GRUB/UEFI boot issues.
#!/usr/bin/env bash
# grub-diag.sh — Diagnose UEFI/GRUB boot configuration issues
set -euo pipefail
PASS=0
WARN=0
FAIL=0
check() {
local desc="$1" cmd="$2"
echo -n " [CHECK] $desc ... "
if eval "$cmd" &>/dev/null; then
echo "OK"
((PASS++))
else
echo "FAILED"
((FAIL++))
fi
}
warn() {
local desc="$1"
echo -n " [WARN] $desc ... "
if eval "${2:-true}" &>/dev/null; then
echo "OK"
((PASS++))
else
echo "ISSUE DETECTED"
((WARN++))
fi
}
echo "=== GRUB/UEFI Boot Diagnostics ==="
echo ""
# UEFI mode verification
echo "--- UEFI Environment ---"
if [[ -d /sys/firmware/efi ]]; then
echo " System booted in UEFI mode ✓"
else
echo " WARNING: Not booted in UEFI mode (checking BIOS compatibility) ..."
fi
# ESP presence and mount
echo ""
echo "--- EFI System Partition ---"
ESP_MOUNT=$(findmnt -n -o TARGET /boot/efi 2>/dev/null || echo "")
if [[ -n "$ESP_MOUNT" ]]; then
echo " ESP is mounted at $ESP_MOUNT ✓"
else
echo " WARNING: ESP not mounted at /boot/efi — check mount points"
fi
# Check ESP filesystem type (must be FAT32)
ESP_FS=$(findmnt -n -o FSTYPE /boot/efi 2>/dev/null || echo "")
if [[ "$ESP_FS" == "vfat" ]]; then
echo " ESP filesystem is FAT32 ✓"
elif [[ -z "$ESP_FS" ]]; then
echo " WARNING: Cannot determine ESP filesystem type (not mounted?)"
else
echo " ERROR: ESP is $ESP_FS (expected vfat/FAT32)"
fi
# ESP size check (minimum 512 MiB recommended)
if [[ -n "$ESP_MOUNT" ]]; then
ESP_SIZE_KB=$(df --output=size /boot/efi | tail -1)
ESP_SIZE_MB=$((ESP_SIZE_KB / 1024))
echo " ESP size: ${ESP_SIZE_MB} MiB"
if [[ $ESP_SIZE_MB -lt 512 ]]; then
echo " WARNING: ESP is less than 512 MiB — consider enlarging it"
fi
fi
# GRUB configuration files
echo ""
echo "--- GRUB Configuration ---"
if [[ -f /etc/default/grub ]]; then
echo " /etc/default/grub exists ✓"
else
echo " ERROR: /etc/default/grub not found"
fi
if [[ -f /boot/grub/grub.cfg ]] || [[ -f /boot/grub2/grub.cfg ]]; then
GRUB_CFG=$(ls /boot/grub/grub.cfg /boot/grub2/grub.cfg 2>/dev/null | head -1)
echo " Generated grub.cfg found at $GRUB_CFG ✓"
else
echo " ERROR: No generated grub.cfg found"
fi
# GRUB EFI binary presence
echo ""
echo "--- GRUB EFI Binary ---"
for efi_path in \
/boot/efi/EFI/ubuntu/grubx64.efi \
/boot/efi/EFI/fedora/grubx64.efi \
/boot/efi/EFI/arch/grubx64.efi \
/boot/efi/EFI/Microsoft/Boot/bootmgfw.efi \
/boot/efi/EFI/BOOT/shimx64.efi; do
if [[ -f "$efi_path" ]]; then
echo " Found: $efi_path"
fi
done
if [[ ! -f /boot/efi/EFI/ubuntu/grubx64.efi ]] && \
[[ ! -f /boot/efi/EFI/fedora/grubx64.efi ]] && \
[[ ! -f /boot/efi/EFI/arch/grubx64.efi ]]; then
echo " WARNING: No distro-specific grubx64.efi found on ESP"
fi
# UEFI boot entries
echo ""
echo "--- UEFI Boot Entries (NVRAM) ---"
if command -v efibootmgr &>/dev/null; then
sudo efibootmgr -v 2>/dev/null || echo " Cannot read NVRAM entries (requires root)"
else
echo " WARNING: efibootmgr not installed — cannot verify UEFI boot entries"
fi
# Summary
echo ""
echo "--- Diagnostics Summary ---"
echo " Passed: $PASS"
echo " Warnings: $WARN"
echo " Failed: $FAIL"
echo ""
if [[ $FAIL -gt 0 ]]; then
echo " ⚠ Boot issues detected. Review failed checks above."
else
echo " ✓ No critical issues found."
fi
Pattern 4: GRUB Rescue Mode Commands
When GRUB fails to load normally, use the built-in rescue shell to manually locate and boot the system.
# --- GRUB Rescue Shell Prompt ---
# grub rescue>
# Step 1: Find the partition containing GRUB modules
set prefix=(hd0,gpt2)/boot/grub
insmod normal
# Step 2: If step 1 fails, search for the correct root partition
ls (hd0,gpt1)/ # List files on partition — look for EFI/ or grub/ directories
ls (hd1,gpt2)/boot/grub/modules/ # Check common paths
# Step 3: Set variables manually
set root='hd0,gpt2'
set prefix='/boot/grub'
# Step 4: Load required modules
insmod ext2 # Or: insmod fat (for ESP), insmod ntfs
insmod linux # For loading kernel
insmod gzio # For compressed initramfs (.gz)
insmod all_video # For video output
insmod efi_gop # For EFI GOP video mode
# Step 5: Boot the kernel manually
linux /vmlinuz-6.1.0-generic root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ro quiet splash
initrd /initrd.img-6.1.0-generic
boot
# --- Alternative: Using ls to identify partitions ---
# grub rescue> ls
# (hd0,gpt1) (hd0,gpt2) (hd0,gpt3) (hd1) (hd1,gpt1)
# grub rescue> ls (hd0,gpt1)/
# EFI/ boot/ config.txt
# grub rescue> ls (hd0,gpt2)/
# boot/ dev/ etc/ home/ lib/ root/ var/ vmlinuz initrd.img
# So: hd0,gpt2 is the Linux root with kernel and initrd
set root='hd0,gpt2'
linux /vmlinuz-6.1.0-generic root=/dev/nvme0n1p2 ro quiet splash
initrd /initrd.img-6.1.0-generic
boot
Checkpoint: In rescue mode, manually setting root, prefix, and loading modules allows booting the system. After recovery, run the full reinstall workflow (Core Workflow Step 3 + 4) to make the configuration persistent.
Constraints
MUST DO
- MUST always edit
/etc/default/grubfor kernel parameter changes — never modifygrub.cfgdirectly as it is auto-generated - MUST use
grub-mkconfig -o /boot/grub2/grub.cfg(RHEL/Fedora) orupdate-grub(Debian/Ubuntu) after any/etc/default/grubchanges - MUST verify ESP is FAT32 and mounted at
/boot/efibefore installing GRUB to UEFI target - MUST use
--target=x86_64-efiwhen runninggrub-installon UEFI systems — never omit this parameter - MUST verify NVRAM boot entries with
efibootmgr -vafter every GRUB reinstall or bootloader modification - MUST back up the existing ESP contents (
cp -a /boot/efi /boot/efi.backup) before reformatting or replacing the ESP - MUST ensure both Linux and Windows boot entries are present in NVRAM for dual-boot systems
- MUST test kernel parameter changes with
grub-mkconfigregeneration before relying on them in production
MUST NOT DO
- MUST NOT edit
/boot/grub/grub.cfgdirectly — any changes will be overwritten by the nextupdate-gruborgrub-mkconfigrun - MUST NOT disable Secure Boot without first signing all boot components with a trusted key pair
- MUST NOT format the ESP as ext4, btrfs, or any non-FAT filesystem — UEFI firmware requires FAT32 (FAT16/FAT12) for EFI binaries
- MUST NOT run
grub-installon a BIOS/legacy system with--target=x86_64-efi— mismatch between firmware mode and target causes silent boot failure - MUST NOT remove the
EFI/BOOT/BOOTX64.EFIfallback file unless explicitly replacing it with another bootloader - MUST NOT disable OS Prober (
GRUB_DISABLE_OS_PROBER=true) without manually adding all required boot entries viaefibootmgr - MUST NOT set GRUB timeout to 0 without setting
GRUB_TIMEOUT_STYLE=hidden— zero timeout with visible menu causes immediate unexpected default boot
Related Skills
| Skill | Purpose |
|---|---|
linux-security |
Full Secure Boot key management including TPM integration, MOK enrollment, and firmware policy configuration |
kernel-tuning |
Deeper kernel parameter optimization beyond what GRUB passes at boot time (sysctl, cgroup tuning) |
shell-process-management |
Managing shell environments, process groups, and scripting patterns for bootloader automation scripts |
linux-services |
Systemd integration with boot ordering, emergency targets, and initramfs service configuration |
cloud-linux-engineering |
Cloud-init boot customization, cloud provider EFI image handling, and automated provisioning workflows |
Live References
Authoritative documentation links for GRUB2 and UEFI bootloader management. The model follows markdown links at load time to resolve external references and inline content.
- GNU GRUB Manual — Complete official GRUB reference manual covering configuration, rescue mode, and scripting
- GRUB EFI Installation Guide — Official UEFI target installation instructions
- efibootmgr Manual Page — Complete reference for UEFI NVRAM boot entry management
- systemd Boot Loader Specification — Standard for EFI boot loader interfaces on Linux
- Secure Boot and Shim Documentation — Microsoft Secure Boot chain, MOK manager, and key enrollment details
- ipxe Documentation — iPXE bootloader documentation for network boot and PXE configuration
- UEFI Specification (EDK II) — Official UEFI firmware specification defining EFI system partition layout and boot process