Skip to content

efibootmgr

Linux Tux Logo

Gentoo EFI Booting Without a Bootloader

Direct-to-Firmware Linux Engineering for Minimalist Power Users


A surgically clean Gentoo setup where GRUB has been thrown overboard and replaced by a custom-compiled kernel with a built-in command line, initramfs, LUKS, and LVM - All injected directly into UEFI.

Minimalism on steroids. No middlemen. No magic. Just pure control, raw performance, and a system that boots as if it were hard-coded into the machine itself.


Before you getting started be sure you have disable protection and varaible protection in bios so we can write to nvram


Misc

To add Shell.efi to the booloader we must add it as

mkdir -vp /boot/efi/shell/
cp /usr/share/edk2/OvmfX64/Shell.efi /boot/efi/shell/
efibootmgr -c -d /dev/nvme0n1 -p 2 -L "UEFI Interactive Shell" -l '\efi\shell\Shell.efi'

Now UEFI Interactive Shell should showup in your startup bootmanager

Add memtest86plus to efistub

Be sure you have moved memtest86plus directory into efi directory

efibootmgr -c -d /dev/nvme0n1 -p 2 -L "Memtest86+" -l '\efi\memtest86plus\memtest.x86_64'

Install sys-apps/memtest86-bin and add it to efibootmgr

Be sure you have moved memtest86-bin directory into efi directory

mkdir -vp /boot/efi
mkdir /boot/efi/memtest86-bin
mv /boot/memtest86-bin.efi /boot/efi/memtest86-bin
efibootmgr -c -d /dev/nvme0n1 -p 2 -L "Memtest86-gui" -l '\efi\memtest86-bin\memtest86-bin'

It's crucial to set the boot drive correct and also its partition number, you can find it with findmnt

findmnt /boot | awk 'NR > 1 {print $2}'

Now we must Register the kernel and initramfs and boot partitions number in UEFI

  • Notice: You will see the output from the efibootmgr command once you create it and you can either add it to the cmdline or to CONFIG_CMDLINE.
  • Notice2: Keep your bootx file in /boot/efi/gentoo/grubx64.efi
efibootmgr --create \
  --disk /dev/nvme0n1 \
  --part 2 \
  --label "Gentoo 7.0.4-Performance" \
  --loader '\vmlinuz-7.0.4-gentoo-x86_64' \
  --unicode 'initrd=\intel-uc.img initrd=\initramfs-7.0.4-gentoo-x86_64.img crypt_root=UUID=<crypt_root_uuid> dolvm rd.lvm.vg=rootfs root=/dev/mapper/vgname-rootfs ro rootfstype=ext4 rootwait loglevel=7 pcie_aspm=off usbcore.autosuspend=-1 cpufreq.default_governor=performance energy_perf_bias=performance i915.enable_psr=0 i915.enable_fbc=0 usbcore.usbfs_memory_mb=256'

We Verify that the record was created correctly

efibootmgr -v | grep -A2 "Gentoo 6.19.6"

Output from the verify command should be similar to

Boot0003* Gentoo 6.19.6 HD(2,GPT,525cbfeb-c4bb-43c9-9070-75931eb00100,0x1000,0x1dc000)/\vmlinuz-6.19.6-gentoo-x86_6469006e0069007400720064003d005c0069006e0069007400720061006d00660073002d0036002e00310039002e0036002d00670065006e0074006f006f002d007800380036005f00360034002e0069006d006700
  dp: 04 01 2a 00 02 00 00 00 00 10 00 00 00 00 00 00 00 c0 1d 00 00 00 00 00 eb bf 5c 52 bb c4 c9 43 90 70 75 93 1e b0 01 00 02 02 / 04 04 40 00 5c 00 76 00 6d 00 6c 00 69 00 6e 00 75 00 7a 00 2d 00 36 00 2e 00 31 00 39 00 2e 00 36 00 2d 00 67 00 65 00 6e 00 74 00 6f 00 6f 00 2d 00 78 00 38 00 36 00 5f 00 36 00 34 00 00 00 / 7f ff 04 00
data: 69 00 6e 00 69 00 74 00 72 00 64 00 3d 00 5c 00 69 00 6e 00 69 00 74 00 72 00 61 00 6d 00 66 00 73 00 2d 00 36 00 2e 00 31 00 39 00 2e 00 36 00 2d 00 67 00 65 00 6e 00 74 00 6f 00 6f 00 2d 00 78 00 38 00 36 00 5f 00 36 00 34 00 2e 00 69 00 6d 00 67 00

Check the boot order with efibootmgr

  • Note: The output is BootOrder: 0003,0004,0000 so our new Gentoo 6.19.6 (Boot0003) will boot first.
  • Note: You can verify the BootXXXX numbers with the efibootmgr command.
BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0003,0004,0000
Boot0000  USB 3.0 Device USB 3.0 Device 000000004BA8    PciRoot(0x0)/Pci(0x14,0x0)/USB(17,0)4eac0881119f594d850ee21a522c59b21180000049535048
Boot0001  USB 3.0 Device USB 3.0 Device 000000004BA8    PciRoot(0x0)/Pci(0x14,0x0)/USB(17,0)4eac0881119f594d850ee21a522c59b21180000049535048
Boot0002* \EFI\BOOT\grub.efi    PciRoot(0x0)/Pci(0x14,0x0)/USB(18,0)/HD(2,MBR,0xd2447f09,0xe58d88,0x10000)/\EFI\BOOT\grub.efi0000000049535048
Boot0003* Gentoo 6.19.6 HD(2,GPT,525cbfeb-c4bb-43c9-9070-75931eb00100,0x1000,0x1dc000)/\vmlinuz-6.19.6-gentoo-x86_6469006e0069007400720064003d005c0069006e0069007400720061006d00660073002d0036002e00310039002e0036002d00670065006e0074006f006f002d007800380036005f00360034002e0069006d006700
Boot0004* Seagate Expansion Desk NAABL96K       PciRoot(0x0)/Pci(0x14,0x0)/USB(16,0)4eac0881119f594d850ee21a522c59b21180000049535048

Command Examples

Put new entry first in boot order (replace 0003 with your new boot number)

efibootmgr --bootorder 0003,0002,0001

Safety net — don't remove GRUB yet

  • On reboot — select new UEFI entry manually via F9/F10/F12 on your hardware.
  • Verify that it boots correctly with LUKS prompt.
  • Check afterwards:
cat /proc/cmdline

Rename or update label of an entry

efibootmgr -b 0000 -L 'Gentoo Linux'

Delete all old entries that are bothering you

efibootmgr -b 0000 -B
efibootmgr -b 0001 -B
efibootmgr -b 0002 -B

Build EFI Support in Kernel

The combination that completely eliminates GRUB which must be enabled directly in the kernel

CONFIG_EFI_STUB=y
CONFIG_CMDLINE_BOOL=y
  • Note that when CONFIG_CMDLINE_BOOL is activated [Y] in kernel the command line options appear below. This is where you enter the parameters we are going to extract.

Enter arguments here that should be compiled into the kernel image and used at boot time

  • 1) If the boot loader provides a command line at boot time, it is appended to this string to form the full kernel command line when the system boots.
  • 2) However, you can use the CONFIG_CMDLINE_OVERRIDE option to override this behavior and hardcode the options directly without issues.
  • 3) Add the kernel commandline from GRUB_CMDLINE_LINUX_DEFAULT if you used sys-boot/grub:2 earlier.

Optional: If you use sys-boot/grub:2 as you did before moving over to efibootmgr, you can extract the parameters from GRUB_CMDLINE_LINUX_DEFAULT

awk -F'"' '/^GRUB_CMDLINE_LINUX_DEFAULT=/ {print $2}' /etc/default/grub
  • Output should be something similar to:
initrd=\amd-uc.img initrd=\initramfs-7.1.2-gentoo-r1-x86_64.img crypt_root=UUID=<crypt_root_uuid> dolvm rd.lvm.vg=rootfs root=/dev/mapper/elitedesk-rootfs rootfstype=ext4 quiet

Compile Kernel so we are up to date

export NUMCPUS=$(nproc)
export NUMCPUSPLUSONE=$((NUMCPUS + 1))

cd /usr/src/linux
make -j${NUMCPUSPLUSONE} -l${NUMCPUSPLUSONE}
make modules_install
cp arch/x86/boot/bzImage /boot/vmlinuz-6.19.6-gentoo-x86_64

Without installkernel

Create initramfs - use genkernel over dracut here for simplicity

genkernel --luks --lvm --install initramfs

Now create /boot/EFI/gentoo folder

mkdir -vp /boot/EFI/gentoo

Now copy our kernel image and initramfs image to the EFI partition we just created

cp /boot/vmlinuz-6.19.6-gentoo-x86_64 /boot/efi/EFI/gentoo/vmlinuz.efi
cp /boot/initramfs-6.19.6-gentoo-x86_64.img /boot/efi/EFI/gentoo/initramfs.img

Function for create EFISTUB

#!/usr/bin/env bash

# - iNFO --------------------------------------
#
#   Author: wuseman
# FileName: kernel.sh
#  Created: 2024-03-26 (19:24:10)
# Modified:
#  License: WTFPL (https://www.wtfpl.net)
#
# ---------------------------------------------

##################################################################
# Create kernel and initramfs for efibootmgr
##################################################################
kernelboot() {
    local boot_dir="/boot"
    local disk="/dev/nvme0n1"
    local part="2"
    local label_prefix="Gentoo"

    ### Minimal - HP Workstation
    #local cmdline="crypt_root=UUID=<crypt_root_uuid> dolvm rd.lvm.vg=rootfs root=/dev/mapper/elitedesk-rootfs rootfstype=ext4 quiet"
    ### Large - Asus Workstation
    local cmdline="crypt_root=UUID=<crypt_root_uuid> dolvm rd.lvm.vg=rootfs root=/dev/mapper/elitedesk-rootfs ro rootfstype=ext4 rootdelay=15 loglevel=7 cpufreq.default_governor=performance amd_pstate=active amd_iommu=on iommu=pt acpi_enforce_resources=lax mitigations=off nowatchdog nvme_core.default_ps_max_latency_us=0 tsc=reliable ro quiet"
    local latest_vmlinuz
    latest_vmlinuz=$(find "${boot_dir}" -maxdepth 1 -type f -name "vmlinuz-7.*" ! -name "*.old" ! -name "*.bak" | sort -V | tail -n 1)

    if [[ -z ${latest_vmlinuz} ]]; then
        echo "[-] Error: Found no fresh kernels in ${boot_dir}" >&2
    fi

    local k_file="${latest_vmlinuz##*/}"
    local k_ver="${k_file#vmlinuz-}"

    local initrd_file="initramfs-${k_ver}.img"
    if [[ ! -f "${boot_dir}/${initrd_file}" ]]; then
        echo "[-] Error: Found no matching initramfs (${initrd_file}) for ${k_file}" >&2
        return 1
    fi

    echo -e "[\e[1;32m+\e[0m] Found latest kernel: ${k_file}"
    echo -e "[\e[1;32m+\e[0m] Matching initramfs: ${initrd_file}"

    local old_bootnum
    old_bootnum=$(efibootmgr | sed -n "s/^Boot\([0-9A-Fa-f]\{4\}\).*${label_prefix}.*/\1/p")

    if [[ -n ${old_bootnum} ]]; then
        echo "${old_bootnum}" | while read -r boot_id; do
            echo -e "[\e[1;32m+\e[0m] Purging old boot entry: Boot${boot_id}"
            efibootmgr -q -B -b "${boot_id}"
        done
    fi

    local full_cmdline="initrd=\\amd-uc.img initrd=\\${initrd_file} ${cmdline}"

    echo -e "[\e[1;32m+\e[0m] Executing efibootmgr for ${k_ver}..."
    if efibootmgr --create \
        --disk "${disk}" \
        --part "${part}" \
        --label "${label_prefix} ${k_ver}-Performance" \
        --loader "\\${k_file}" \
        --unicode "${full_cmdline}" >/dev/null; then
        echo -e "[\e[1;32m+\e[0m] Successfully created EFI boot entry for ${k_ver}!"
        echo "------------------------------------------------"
        efibootmgr | grep "${label_prefix}"
    else
        echo "[-] Error: Failed to write to NVRAM via efibootmgr" >&2
        return 1
    fi
}

Clear old kernels not needed anymore

#!/usr/bin/env bash
 
# - iNFO --------------------------------------
#
#   Author: wuseman
# FileName: kernel.sh
#  Created: 2023-01-05 (15:21:20)
# Modified:
#  License: WTFPL (https://www.wtfpl.net)
#
# ---------------------------------------------

clearkernel() {
    local boot_dir="/boot"
    local latest_ver
    local file

    # Ensure running as root
    if [[ ${EUID} -ne 0 ]]; then
        echo "[-] Error: clearkernel must be run as root." >&2
        return 1
    fi

    # Find the most recent vmlinuz kernel version (excluding .old files)
    latest_ver=$(find "${boot_dir}" -maxdepth 1 -type f -name "vmlinuz-*" ! -name "*.old" -printf "%T@ %p\n" |
        sort -n | tail -n 1 | awk '{print $2}' | sed -r 's|.*/vmlinuz-||')

    if [[ -z "${latest_ver}" ]]; then
        echo "[-] Error: Could not determine the latest kernel version." >&2
        return 1
    fi

    echo "[+] Keeping kernel version: ${latest_ver}"
    echo "[+] Scanning for obsolete kernel components..."

    # Iterate through target patterns
    for file in "${boot_dir}"/{vmlinuz,initramfs,config,System.map}-*; do
        # Guard against empty glob expansion
        [[ -e "${file}" ]] || continue

        # Do not delete the latest kernel files
        if [[ "${file}" == *"${latest_ver}"* ]]; then
            continue
        fi

        # Strict deletion log and execution
        echo "[-] Removing: ${file}"
        rm -f "${file}"
    done

    echo "[+] Kernel cleanup complete. Remember to update your EFIBOOTMGR entries if needed!"
}    

Compile Kernel and Open Menu Config

#!/usr/bin/env bash
 
# - iNFO --------------------------------------
#
#   Author: wuseman
# FileName: kernel.sh
#  Created: 2021-07-15 (06:30:26)
# Modified:
#  License: WTFPL (https://www.wtfpl.net)
#
# ---------------------------------------------

kernel() {
    export MENUCONFIG_COLOR=blackbg

    if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
        echo "ERROR: run 'kernel' as root (no sudo is used in this function)." >&2
        return 1
    fi

    local kdir="/usr/src/linux"
    if [[ ! -d "$kdir" ]]; then
        echo "ERROR: $kdir does not exist." >&2
        return 1
    fi

    cd "$kdir"

    if [[ ! -f .config ]]; then
        if [[ -r /proc/config.gz ]]; then
            echo "[*] .config missing; importing running kernel config from /proc/config.gz"
        #	zcat /proc/config.gz >.config
        #	make olddefconfig
        else
            echo "ERROR: .config missing and /proc/config.gz not readable/enabled." >&2
            echo "Hint: enable IKCONFIG_PROC in the currently running kernel, or provide a config manually." >&2
            return 1
        fi
    else
        echo "[*] Using existing .config"
    fi

    echo "[*] menuconfig (interactive)"
    make menuconfig

    local jobs
    jobs="$(nproc --all 2>/dev/null || getconf _NPROCESSORS_ONLN || echo 1)"

    echo "[*] Building kernel (jobs=$jobs)"
    make -j"$jobs"

    echo "[*] Installing modules"
    make modules_install

    echo "[*] Installing kernel"
    make install

    echo "[*] Building/Installing initramfs with genkernel (luks+lvm)"
    genkernel --luks --lvm --install initramfs

    echo "[*] Regenerating BOOT config"
    kernelboot
    echo
    read -r -p "Kernel build complete. Reboot now? [y/N] " ans
    case "${ans,,}" in
    y | yes)
        echo "[*] Rebooting..."
        reboot
        ;;
    *)
        echo "[*] Not rebooting."
        ;;
    esac
}    

Long Options

Set bootnum active.

efibootmgr --bootnum XXXX --active

Set bootnum inactive.

efibootmgr --bootnum XXXX --inactive

Modify BootXXXX (hex).

efibootmgr --bootnum XXXX

Delete bootnum.

efibootmgr --bootnum XXXX --delete-bootnum

Create new variable bootnum and add to bootorder at index (-I).

efibootmgr --create

Create new variable bootnum and do not add to bootorder.

efibootmgr --create-only

Disk containing boot loader (defaults to /dev/sda).

efibootmgr --disk /dev/sda

Remove duplicate values from BootOrder.

efibootmgr --remove-dups

Force boot entries to be created using EDD 1.0 or 3.0 info.

efibootmgr --edd 3

EDD 1.0 device number (defaults to 0x80).

efibootmgr --device 0x80

Use a full device path.

efibootmgr --full-dev-path

Use an abbreviated File() device path.

efibootmgr --file-dev-path

Re-connect devices after driver is loaded.

efibootmgr --reconnect

Do not re-connect devices after driver is loaded.

efibootmgr --no-reconnect

Force disk with invalid PMBR to be treated as GPT.

efibootmgr --gpt

Create a netboot entry for the named interface.

efibootmgr --iface eth0

When creating an entry, insert it in bootorder at specified position (default: 0).

efibootmgr --index 0

Defaults to \"\EFI\Gentoo\grub.efi\"

efibootmgr --loader '\EFI\Gentoo\grub.efi'

Boot manager display label (defaults to \"Linux\").

efibootmgr --label "Gentoo"

Mirror memory below 4GB.

efibootmgr --mirror-below-4G t

X Percentage memory to mirror above 4GB.

efibootmgr --mirror-above-4G 50

Set BootNext to XXXX (hex).

efibootmgr --bootnext XXXX

Delete BootNext.

efibootmgr --delete-bootnext

Explicitly set BootOrder (hex).

efibootmgr --bootorder XXXX,YYYY,ZZZZ

Delete BootOrder.

efibootmgr --delete-bootorder

Partition containing loader (defaults to 1 on partitioned devices).

efibootmgr --part 1

Be quiet.

efibootmgr --quiet

Operate on Driver variables, not Boot Variables.

efibootmgr --driver

Set boot manager timeout waiting for user input.

efibootmgr --timeout 5

Delete Timeout.

efibootmgr --delete-timeout

Handle extra args as UCS-2 (default is ASCII).

efibootmgr --unicode

Print additional information.

efibootmgr --verbose

Return version and exit.

efibootmgr --version

Write unique sig to MBR if needed.

efibootmgr --write-signature

Operate on SysPrep variables, not Boot Variables.

efibootmgr --sysprep

Append extra args from file (use \"-\" for stdin).

efibootmgr --append-binary-args args.bin

Show help/usage.

efibootmgr --help

Short Options

Set bootnum active.

efibootmgr -b XXXX -a

Set bootnum inactive.

efibootmgr -b XXXX -A

Modify BootXXXX (hex).

efibootmgr -b XXXX

Delete bootnum.

efibootmgr -b XXXX -B

Create new variable bootnum and add to bootorder at index (-I).

efibootmgr -c

Create new variable bootnum and do not add to bootorder.

efibootmgr -C

Disk containing boot loader (defaults to /dev/sda).

efibootmgr -d /dev/sda

Remove duplicate values from BootOrder.

efibootmgr -D

Force boot entries to be created using EDD 1.0 or 3.0 info.

efibootmgr -e 3

EDD 1.0 device number (defaults to 0x80).

efibootmgr -E 0x80

Use a full device path.

efibootmgr --full-dev-path

Use an abbreviated File() device path.

efibootmgr --file-dev-path

Re-connect devices after driver is loaded.

efibootmgr -f

Do not re-connect devices after driver is loaded.

efibootmgr -F

Force disk with invalid PMBR to be treated as GPT.

efibootmgr -g

Create a netboot entry for the named interface.

efibootmgr -i eth0

When creating an entry, insert it in bootorder at specified position (default: 0).

efibootmgr -I 0

Defaults to \"\EFI\Gentoo\grub.efi\"

efibootmgr -l '\EFI\Gentoo\grub.efi'

Boot manager display label (defaults to \"Linux\").

efibootmgr -L "Gentoo"

Mirror memory below 4GB.

efibootmgr -m t

X Percentage memory to mirror above 4GB.

efibootmgr -M 50

Set BootNext to XXXX (hex).

efibootmgr -n XXXX

Delete BootNext.

efibootmgr -N

Explicitly set BootOrder (hex).

efibootmgr -o XXXX,YYYY,ZZZZ

Delete BootOrder.

efibootmgr -O

Partition containing loader (defaults to 1 on partitioned devices).

efibootmgr -p 1

Be quiet.

efibootmgr -q

Operate on Driver variables, not Boot Variables.

efibootmgr -r

Set boot manager timeout waiting for user input.

efibootmgr -t 5

Delete Timeout.

efibootmgr -T

Handle extra args as UCS-2 (default is ASCII).

efibootmgr -u

Print additional information.

efibootmgr -v

Return version and exit.

efibootmgr -V

Write unique sig to MBR if needed.

efibootmgr -w

Operate on SysPrep variables, not Boot Variables.

efibootmgr -y

Append extra args from file (use \"-\" for stdin).

efibootmgr -@ args.bin

Show help/usage.

efibootmgr -h