인터페이스는 현지화되어 있으며, Skill 소개와 설명 문서는 선택한 언어로 AI가 자동 번역합니다. 코드·명령어·경로·전문 용어는 원문을 유지하며 원작자 문서가 우선합니다.
Skills 둘러보기
생산성 및 협업 · SKILL.md

grub-uefi-bootloader

grub-uefi-bootloader

Configures GRUB2 bootloader for UEFI firmware boot processes including ESP management, Secure Boot signing, multi-boot setups, kernel parameters, and bootloader recovery procedures.

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill 문서

GitHub

name: grub-uefi-bootloader description: Configures GRUB2 bootloader for UEFI firmware boot processes including ESP management, Secure Boot signing, multi-boot setups, kernel parameters, and bootloader recovery procedures. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: linux role: implementation scope: implementation output-format: code content-types:

  • code
  • guidance
  • config
  • do-dont triggers: grub2, UEFI boot, Secure Boot, EFI System Partition, bootloader recovery, how do i repair bootloader, efibootmgr, GRUB configuration how do i repair bootloader archetypes:
  • tactical anti_triggers:
  • brainstorming
  • vague ideation response_profile: verbosity: low directive_strength: high abstraction_level: operational related-skills: linux-services, linux-security, kernel-tuning, shell-process-management, cloud-linux-engineering maturity: stable completeness: 95 exampleCount: 5

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/efi with FAT32 filesystem and 512 MiB minimum size
  • Confirm UEFI firmware mode with efibootmgr --verbose before any bootloader changes
  • Set kernel parameters in /etc/default/grub, never edit grub.cfg directly
  • Generate new GRUB config with grub-mkconfig -o /boot/grub2/grub.cfg (RHEL) or update-grub (Debian)
  • For Secure Boot: sign kernel and initramfs with sbsign using Shim/MOK key pair
  • Validate boot entries with efibootmgr after 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-install with 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/grub for kernel parameter changes — never modify grub.cfg directly as it is auto-generated
  • MUST use grub-mkconfig -o /boot/grub2/grub.cfg (RHEL/Fedora) or update-grub (Debian/Ubuntu) after any /etc/default/grub changes
  • MUST verify ESP is FAT32 and mounted at /boot/efi before installing GRUB to UEFI target
  • MUST use --target=x86_64-efi when running grub-install on UEFI systems — never omit this parameter
  • MUST verify NVRAM boot entries with efibootmgr -v after 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-mkconfig regeneration before relying on them in production

MUST NOT DO

  • MUST NOT edit /boot/grub/grub.cfg directly — any changes will be overwritten by the next update-grub or grub-mkconfig run
  • 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-install on 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.EFI fallback 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 via efibootmgr
  • 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

SkillPurpose
linux-securityFull Secure Boot key management including TPM integration, MOK enrollment, and firmware policy configuration
kernel-tuningDeeper kernel parameter optimization beyond what GRUB passes at boot time (sysctl, cgroup tuning)
shell-process-managementManaging shell environments, process groups, and scripting patterns for bootloader automation scripts
linux-servicesSystemd integration with boot ordering, emergency targets, and initramfs service configuration
cloud-linux-engineeringCloud-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.

저장한 Skills