efibootmgr
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
Install sys-apps/memtest86-bin and add it to efibootmgr
Be sure you have moved memtest86-bin directory into efi directory
It's crucial to set the boot drive correct and also its partition number, you can find it with findmnt
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'
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)
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:
Delete all old entries that are bothering you
Build EFI Support in Kernel
The combination that completely eliminates GRUB which must be enabled directly in the kernel
- 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
- Output should be something similar to:
Compile Kernel so we are up to date
Without installkernel
Create initramfs - use genkernel over dracut here for simplicity
Now copy our kernel image and initramfs image to the EFI partition we just created
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
When creating an entry, insert it in bootorder at specified position (default: 0).