EFISTUB
The Linux Kernel (linux>=3.3) supports EFISTUB (EFI BOOT STUB) booting. It is enabled by default on Arch Linux kernels or can be activated by setting CONFIG_EFI_STUB=y in the Kernel configuration (see The EFI Boot Stub for more information).
A single EFISTUB kernel is not capable of launching other kernels, hence each EFISTUB Kernel + Initramfs pair requires a separate boot menu entry. Because of this, when working with multiple kernels, it is recommended to use a UEFI Boot Manager.
Contents |
Setting up EFISTUB
- Create a EFI System Partition.
- Mount the EFI System Partition either at
/boot(recommended if you are planning to use Gummiboot or no boot manager) or some other location of your choice (most other distro's and tools use/boot/efi). The mountpoint will be mentioned as$esphereafter.
Copying Kernel and Initramfs to ESP
- Create
$esp/EFI/arch/ - Copy the following files from source to destination
| Boot File Source | UEFI Destination |
|---|---|
| /boot/vmlinuz-linux | $esp/EFI/arch/vmlinuz-arch.efi |
| /boot/initramfs-linux.img | $esp/EFI/arch/initramfs-arch.img |
| /boot/initramfs-linux-fallback.img | $esp/EFI/arch/initramfs-arch-fallback.img |
Using systemd
Systemd features event triggered tasks. In this particular case, the ability to detect a change in path is used to sync the EFISTUB kernel and initramfs files when they are updated in boot.
[Unit] Description=Copy EFISTUB Kernel to UEFISYS Partition [Path] PathChanged=/boot/initramfs-linux-fallback.img [Install] WantedBy=multi-user.target
[Unit] Description=Copy EFISTUB Kernel to UEFISYS Partition [Service] Type=oneshot ExecStart=/usr/bin/cp -f /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi ExecStart=/usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img ExecStart=/usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img
Incron
incron can run a script to sync the EFISTUB Kernel after updates
#!/usr/bin/env bash /usr/bin/cp -f /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi /usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img /usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img
/boot/initramfs-linux-fallback.img IN_CLOSE_WRITE /usr/local/bin/efistub-update.sh
Mkinitcpio hook
Mkinitcpio can generate a hook that does not need a system level daemon to function. It spawns a background process which waits for the generation of vm-linuz, initramfs-linux.img, and initramfs-linux-fallback.img; then follows step 4 in Setting up EFISTUB
#!/usr/bin/env bash
build() {
/root/watch.sh &
}
help() {
cat <<HELPEOF
This hook waits for mkinitcpio to finish and copies the finished ramdisk and kernel to the ESP
HELPEOF
}
#!/usr/bin/env bash while [[ -d "/proc/$PPID" ]]; do sleep 1 done /usr/bin/cp -f /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi /usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img /usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img echo "Synced kernel with ESP"
/etc/fstab bind mount
- Method
- Whereas the general convention is to mount the EFI system partition to a
/boot/efisubfolder, the following will achieve the opposite.
- Create a
ef00type EFI system partition of FAT32 format as described elsewhere.
- Create a mount-point and mount the EFI system partition somewhere on the filesystem. For example:
-
$ mkdir /esp
$ mount -L esp /esp
- Create a folder in
/EFI/booton the EFI system partition to contain your system's/bootfiles. For example:
-
$ mkdir /esp/EFI/boot/arch64-laptop
- Move all files in
/bootto the newly created folder on your EFI system partition. For example:
-
$ mv /boot/* /esp/EFI/boot/arch64-laptop/
- Bind mount the newly populated folder on your EFI system partition to
/boot. For example:
-
$ mount --bind /esp/EFI/boot/arch64-laptop /boot
- Verify your files are available as expected with
$ ls /boot/then persist the configuration by editing/etc/fstab. For example:
-
##/etc/fstab
LABEL=arch64-laptop_rootfs / ext4 defaults 0 0
LABEL=esp /esp vfat defaults 0 0
/esp/EFI/boot/arch64-laptop /boot none defaults,bind 0 0
- Update your bootloader to apply the
root=kernel boot parameter as necessary. For example:
-
##/boot/refind_linux.conf
... root=LABEL=arch64-laptop_rootfs ...
Booting EFISTUB
EFISTUB kernel can be booted using one of the following ways :
Using gummiboot
Gummiboot is a UEFI Boot Manager which provides a nice menu for EFISTUB Kernels. It is available in [core] as gummiboot and is the recommended boot manager for EFISTUB booting. See gummiboot for more info.
Using rEFInd
rEFInd is a fork of rEFIt Boot Manager (used in Intel Macs) by Rod Smith (author of gdisk). rEFInd fixes many issues in rEFIt with respect to non-Mac UEFI booting and also has support for booting EFISTUB kernels and contains some features specific to them.
- Mount efivarfs
# mount -t efivarfs efivarfs /sys/firmware/efi/efivars # ignore if already mounted
- Install refind-efi package with
# pacman -S refind-efi
- Copy the following files from their source directory to their destination
# cp /usr/share/refind/refind_x64.efi $esp/EFI/refind/refind_x64.efi # cp /usr/share/refind/refind.conf-sample $esp/EFI/refind/refind.conf # cp /usr/share/refind/icons $esp/EFI/refind/icons # cp /usr/share/refind/drivers_x64 $esp/EFI/refind/drivers
- Edit rEFInd's config file at
$esp/EFI/refind/refind.conf. The file is well commented and self explanatory.
- Create a
refind_linux.conffile inside the directory where the kernel and initramfs files and located.
refind_linux.conf
"Boot with defaults" "root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rw rootfstype=ext4 add_efi_memmap systemd.unit=graphical.target" "Boot to Terminal" "root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rw rootfstype=ext4 add_efi_memmap systemd.unit=multi-user.target"
- Create a boot entry in the UEFI boot menu using efibootmgr
# efibootmgr -c -d /dev/sdX -p Y -l /EFI/refind/refind_x64.efi -L "rEFInd"
Systemd Automation
#!/usr/bin/env bash
## COPYRIGHT 2013 : MARK E. LEE (BLUERIDER) : mlee24@binghamton.edu; mark@markelee.com
## LOG
## 1/17/2013 : Version 2 of refind_name_patch is released
## : Supports long subdirectory location for refind
## : Updates nvram when needed
## : 10% speed boost
## 7/15/2013 : Changed arch to match 32-bit (ia32) and 64-bit (x64) naming scheme
## : Changed directory copying in update-efi-dir to copy tools and drivers directories explicitly
## : Changed efibootmgr writing code to be more concise and added (-w) to write the entry as per dusktreader's excellent guide : https://docs.google.com/document/d/1pvgm3BprpXoadsQi38FxqMOCUZhcSqFhZ26FZBkmn9I/edit
## : Function to check if NVRAM boot entry was already listed was fixed to use awk and an if then clause
## : ref_bin_escape was modified from : ref_bin_escape=${ref_bin//\//\\\\} to remove extra backslashes (error does not show up when using cmdline)
## 7/29/2013 : Changed location of tools,drivers, and binary directory to match capricious upstream move to /usr/share/refind
function main () { ## main insertion function
declare -r refind_dir="/boot/efi/EFI/refind"; ## set the refind directory
arch=$(uname -m | awk -F'_' '{if ($1 == "x86") {print "x"$2} else if ($1 == "i686") {print "ia32"}}') && ## get bit architecture
update-efi-dir; ## updates or creates the refind directory
update-efi-nvram; ## updates nvram if needed
}
function update-efi-dir () { ## setup the refind directory
if [ ! -d $refind_dir ]; then ## check if refind directory exists
echo "Couldn't find $refind_dir";
mkdir $refind_dir && ## make the refind directory if needed
echo "Made $refind_dir";
fi;
if [ "$arch" ]; then ## check if anything was stored in $arch
cp -r /usr/share/refind/{refind_$arch.efi,keys,images,icons,fonts,docs,{tools,drivers}_$arch} $refind_dir/ && ## update the bins and dirs
echo "Updated binaries and directory files for refind at $refind_dir";
else
echo "Failed to detect an x86 architecture";
exit;
fi;
}
function update-efi-nvram () { ## update the nvram with efibootmgr
declare -r ref_bin=${refind_dir/\/boot\/efi}/refind_$arch.efi; ## get path of refind binary (without /boot/efi)
declare -r ref_bin_escape=${ref_bin//\//\\}; ## insert escape characters into $ref_bin
[ "$(efibootmgr -v | awk "/${ref_bin_escape//\\/\\\\}/")" ] && ( ## check if boot entry is in nvram \
echo "Found boot entry, no need to update nvram";
) || ( ## if boot entry is not in nvram; add it
declare -r esp=$(mount -l | awk '/ESP/ {print $1}') && ## get ESP partition
efibootmgr -cgw -d ${esp:0:8} -p ${esp:8} -L "rEFInd" -l $ref_bin_escape && ## update nvram
echo "
Updated nvram with entry rEFInd to boot $ref_bin
Did not copy configuration files, please move refind.conf to $refind_dir/";
)
}
main; ## run the main insertion function
[Unit] Description=Update rEFInd bootloader files [Path] PathChanged=/usr/share/refind/refind_<arch>.efi Unit=refind_update.service [Install] WantedBy=multi-user.target
[Unit] Description=Update rEFInd directories, binaries, and nvram [Service] Type=oneshot ExecStart=/usr/bin/bash /usr/lib/systemd/scripts/refind_name_patchv2 RemainAfterExit=no
Apple Macs
In case of Apple Macs, try mactel-boot for an experimental "bless" utility for Linux. If that does not work, use "bless" form within OSX to set rEFInd as default bootloader. Assuming UEFISYS partition is mounted at /mnt/efi within OSX, do
$ sudo bless --setBoot --folder /mnt/efi/EFI/refind --file /mnt/efi/EFI/refind/refind_x64.efi
VirtualBox
In case of VirtualBox, see VirtualBox#Using_Arch_under_Virtualbox_EFI_mode.
Using UEFI Shell
It is possible to launch EFISTUB kernel form UEFI Shell as if it is a normal UEFI application. In this case the kernel parameters are passed as normal parameters to the launched EFISTUB kernel file.
> fs0: > cd \EFI\arch > vmlinuz-arch.efi root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 ro rootfstype=ext4 add_efi_memmap initrd=EFI/arch/initramfs-arch.img
You can also write a simple archlinux.nsh file with your boot parameters and put it in your UEFI System Partition, then run it with:
fs0: archlinux
Example Script:
echo -on \EFI\arch\vmlinuz-arch.efi root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rootfstype=ext4 add_efi_memmap initrd=/EFI/arch/initramfs-arch.img
This way you can specify UUID's without needing to remember the name or type out 20-30 characters.
Directly, using efibootmgr entry
It is possible to directly embed the kernel parameters within the boot entry created by efibootmgr. This means that you can use your UEFI boot order/GUI to directly boot Arch Linux without a separate bootloader like GRUB (below, the EFI System Partition is on /dev/sdX, partition Y).
# mount -t efivarfs efivarfs /sys/firmware/efi/efivars # ignore if already mounted # efibootmgr -c -d /dev/sdX -p Y -l /EFI/arch/vmlinuz-arch.efi -L "Arch Linux (EFISTUB)" -u "$(cat /proc/cmdline)"
It is a good idea to run
# efibootmgr -v
to verify that the resulting entry is correct. You should also consider reordering the boot options (efibootmgr -o) to place the Arch entry last, which could make the system easier to recover if it fails.
More info about efibootmgr at UEFI#efibootmgr. Forum post https://bbs.archlinux.org/viewtopic.php?pid=1090040#p1090040 .