Deep Dive: GRUB vs EFISTUB Bootloaders
The bootloader is the first thing that runs when you power on your machine. Get it wrong, and you’re reaching for a live USB. Get it right, and you have a recovery console that can save you from almost any disaster.
This post documents my two-week experiment with EFISTUB (no bootloader), and why I ultimately returned to GRUB.
What is EFISTUB?
Modern Linux kernels can be EFI executables. Your motherboard’s UEFI firmware can boot them directly—no GRUB, no bootloader at all. The kernel itself is the boot target.
Pros:
- Blazing fast boot (no menu, no timeout)
- Zero dependencies (no bootloader package to maintain)
- Simpler attack surface
- Secure Boot friendly (if you sign the kernel)
Cons:
- Kernel arguments are stored in NVRAM (risky to modify frequently)
- No boot menu (can’t select between kernels)
- No snapshot recovery menu
The EFISTUB Experiment
I ran EFISTUB for about two weeks. Setup was simple:
# Create EFI boot entry directly to kernel
efibootmgr --create \
--disk /dev/nvme0n1 \
--part 1 \
--label "Gentoo" \
--loader '\vmlinuz-6.12.47-gentoo' \
--unicode 'root=/dev/nvme0n1p3 rootflags=subvol=/@ ro quiet splash' \
--verbose
It worked beautifully. Boot time dropped. The system felt snappier knowing there was one less layer between power button and desktop.
Updating the Kernel
The challenge with EFISTUB: kernel updates require updating the EFI entry.
# After kernel compilation
cp /usr/src/linux/arch/x86/boot/bzImage /boot/efi/vmlinuz-6.12.48-gentoo
# Update EFI entry
efibootmgr --create \
--disk /dev/nvme0n1 \
--part 1 \
--label "Gentoo-New" \
--loader '\vmlinuz-6.12.48-gentoo' \
--unicode 'root=/dev/nvme0n1p3 rootflags=subvol=/@ ro quiet'
# Delete old entry
efibootmgr -b 0003 -B # where 0003 is the old entry number
Manageable, but tedious. And if the new kernel panics? No fallback without a live USB.
The Reversion to GRUB
Week two, I broke something. I don’t remember what—maybe a kernel config issue, maybe a driver mismatch. The system panicked on boot.
With EFISTUB, my recovery options were:
- Boot a live USB
- Mount the Btrfs partition
- Either fix the problem from chroot, or manually change the EFI entry to point at a snapshot subvolume
- Hope I got the rootflags right
This process took 20 minutes and violated my “2-minute recovery” rule.
The realization: GRUB isn’t just a bootloader. With grub-btrfs, it’s a recovery console.
GRUB + grub-btrfs: The Recovery Console
Installation
# Install GRUB with EFI support
emerge sys-boot/grub sys-boot/grub-btrfs
# Install to EFI partition
grub-install --efi-directory=/boot/efi --bootloader-id=Gentoo
# Generate configuration
grub-mkconfig -o /boot/grub/grub.cfg
What grub-btrfs Does
grub-btrfs scans your /.snapshots directory and generates boot entries for each snapshot. Your GRUB menu becomes:
Gentoo Linux
Advanced options for Gentoo Linux --->
Gentoo Linux, with Linux 6.12.47
Gentoo Linux (snapshot 47) - Before emerge Firefox
Gentoo Linux (snapshot 48) - After emerge Firefox
Gentoo Linux (snapshot 49) - Timeline 2025-11-30 11:00
Gentoo Linux (snapshot 50) - Before system update
If my system panics, I:
- Reboot
- Select a snapshot from the menu
- System boots into known-good state
- Investigate what broke
Total time: under 2 minutes. No live USB needed.
GRUB Configuration
File: /etc/default/grub
# Timeout before auto-boot
GRUB_TIMEOUT=5
# Default boot entry (0 = first entry)
GRUB_DEFAULT=0
# Show GRUB menu (not hidden)
GRUB_TIMEOUT_STYLE=menu
# Kernel command line (quiet boot with splash)
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
# Enable os-prober for dual-boot systems
GRUB_DISABLE_OS_PROBER=false
# Limit snapshot menu entries
GRUB_BTRFS_LIMIT="10"
After editing, regenerate:
grub-mkconfig -o /boot/grub/grub.cfg
Automating GRUB Updates
Kernel Post-Install Hook
Every kernel update should regenerate the GRUB config. Create a hook:
File: /etc/kernel/postinst.d/zz-grub
#!/bin/bash
# Regenerate GRUB config after kernel installation
grub-mkconfig -o /boot/grub/grub.cfg
chmod +x /etc/kernel/postinst.d/zz-grub
Snapshot Change Hook
Optionally, regenerate GRUB when snapshots are created (so new snapshots appear in the menu immediately):
# Add to cron.hourly
cat > /etc/cron.hourly/grub-btrfs-update << 'EOF'
#!/bin/bash
/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg 2>/dev/null
EOF
chmod +x /etc/cron.hourly/grub-btrfs-update
Recovery Procedures
Scenario 1: System Won’t Boot After Update
- At GRUB menu, select Advanced options
- Choose a snapshot from before the update
- System boots into snapshot (read-only)
- If it works, make the rollback permanent:
snapper rollback reboot
Scenario 2: Kernel Panic
- At GRUB menu, select a previous kernel version
- Remove or fix the problematic kernel
- Rebuild with corrected configuration
Scenario 3: Black Screen (GPU Driver Issue)
- At GRUB menu, press
eto edit boot entry - Add
nomodesetto the kernel command line - Press Ctrl+X to boot
- Fix GPU drivers from a working (text mode) system
Scenario 4: Can’t Get to GRUB Menu
If the system hangs before GRUB:
- Boot from live USB
- Mount EFI partition:
mount /dev/nvme0n1p1 /mnt - Check if GRUB files exist:
ls /mnt/EFI/Gentoo/ - Chroot and reinstall GRUB if needed
EFISTUB: When It Makes Sense
EFISTUB isn’t wrong—it’s just a different trade-off:
Use EFISTUB when:
- You have a separate, stable recovery partition
- You’re not using Btrfs snapshots for rollback
- You want minimal boot time and attack surface
- You’re comfortable with live USB recovery
Use GRUB when:
- You’re using Btrfs snapshots and want boot-time rollback
- You dual-boot or need kernel selection
- You value recovery speed over boot speed
- You want “just works” kernel updates
The Verdict
I went back to GRUB. The 1-2 second boot time penalty is worth the recovery capability. When something breaks at 2 AM, I don’t want to hunt for a USB drive.
GRUB + grub-btrfs turns every snapshot into a bootable recovery point. That’s not overhead—that’s insurance.
Both approaches are valid. Know what you’re trading off, and choose accordingly.