EFISTUB

From ArchWiki
Revision as of 18:26, 12 August 2014 by Silverhammermba (Talk | contribs) (remove strange comment about kernels not being able to boot other kernels. mention what EFISTUB is in the intro)

Jump to: navigation, search
Warning: A bug has been noticed where booting EFISTUB can fail depending on kernel version and motherboard model. See [1] and [2] for more information.

The Linux Kernel (linux>=3.3) supports EFISTUB (EFI BOOT STUB) booting. This feature allows EFI firmware to load the kernel as an EFI executable. The option 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).

An EFISTUB kernel can be booted directly by a UEFI motherboard or indirectly using a UEFI boot manager. The latter is recommended if you have multiple kernel/initramfs pairs and your motherboard's UEFI boot menu is not easy to use.

Setting up EFISTUB

After creating the EFI System Partition, you must choose how it will be mounted. The simplest option is to mount it at /boot, since this allows pacman to directly update the kernel that the EFI firmware will read. If you elect for this option, continue to #Booting EFISTUB.

Alternative ESP Mount Points

If you mount the EFI System Partition elsewhere (such as /boot/efi), you will need to copy boot files to that location (referred to hereafter as $esp).

# mkdir $esp/EFI/arch
# cp /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi
# cp /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img
# cp /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img

Furthermore, you will need to keep the files on the ESP up-to-date with later kernel updates. Failure to do so could result in an unbootable system. The following sections discuss several mechanisms for doing so.

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.

/etc/systemd/system/efistub-update.path
[Unit]
Description=Copy EFISTUB Kernel to UEFISYS Partition

[Path]
PathChanged=/boot/initramfs-linux-fallback.img

[Install]
WantedBy=multi-user.target
Note: This watches for changes to initramfs-linux-fallback.img since this is the last file built by mkinitcpio. This is to avoid a potential race condition where systemd could copy older files before they are all done being built.
/etc/systemd/system/efistub-update.service
[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

Enable these services with:

# systemctl enable efistub-update.path

Incron

incron can be used to run a script syncing the EFISTUB Kernel after kernel updates.

/usr/local/bin/efistub-update.sh
#!/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
Note: The first parameter /boot/initramfs-linux-fallback.img is the file to watch. The second parameter IN_CLOSE_WRITE is the action to watch for. The third parameter /usr/local/bin/efistub-update.sh is the script to execute.
/etc/incron.d/efistub-update.conf
/boot/initramfs-linux-fallback.img IN_CLOSE_WRITE /usr/local/bin/efistub-update.sh

In order to use this method, enable the incrond service:

# systemctl enable incrond.service

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 before copying the files.

Add efistub-update to the list of hooks in /etc/mkinitcpio.conf.

/usr/lib/initcpio/install/efistub-update
#!/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
}
/root/watch.sh
#!/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"

Bind Mount

Instead of mounting the ESP itself to /boot, you can mount a directory of the ESP to /boot using a bind mount (see mount(8)). This allows pacman to update the kernel directly while keeping the ESP organized to your liking. For example, this is useful if you have multiple distributions/boot loaders in different directories of the ESP but don't want to deal with the previous methods that depending on copying files after a kernel update.

Note: This requires a kernel and bootloader compatible with FAT32. This is not an issue for a regular Arch install, but could be problematic for other distributions (namely those that require symlinks in /boot). Forum post [here].

As before, copy all boot files to a directory on your ESP, but mount the ESP outside /boot (e.g. /esp). Then bind mount the directory:

# mount --bind /esp/EFI/arch/ /boot

If your files appear in /boot as desired, edit your Fstab to make it persistent:

/etc/fstab
/esp/EFI/arch /boot none defaults,bind 0 0
Warning: You must use the root=system_root kernel parameter in order to boot using this method.

Booting EFISTUB

Warning: Linux Kernel EFISTUB initramfs path should be relative to the EFI System Partition's root. For example, if the initramfs is located in $esp/EFI/arch/initramfs-linux.img, the corresponding UEFI formatted line should be initrd=/EFI/arch/initramfs-linux.img or initrd=\EFI\arch\initramfs-linux.img.

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 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. See rEFInd for detail.

Using UEFI Shell

It is possible to launch EFISTUB kernel from 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 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:

$ESP/archlinux.nsh
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, without boot manager

Warning: Some kernel and efibootmgr combinations might not work without manual intervention [3]. You will be able to delete but not create boot entries.
Note: Some UEFI firmwares may not support embedding command line parameters to uefi applications in the boot entries.

It is possible to directly embed the kernel parameters within the UEFI boot entry. This means that you can use your UEFI boot order/motherboard GUI to directly boot Arch Linux without a separate boot manager. Change X and Y to reflect the disk and partition where the ESP is located. Change the root= parameter to reflect your Linux root.

# efibootmgr -d /dev/sdX -p Y -c -L "Arch Linux" -l /vmlinuz-linux -u "root=/dev/sda2 rw initrd=/initramfs-linux.img"

It is a good idea to run

# efibootmgr -v

to verify that the resulting entry is correct.

To set the boot order, run:

# efibootmgr -o XXXX,XXXX

where XXXX is the number that appears in the output of `efibootmgr` command against each entry.

Tip: Save the command for creating your boot entry in a shell script somewhere, which makes it easier to modify (when changing kernel parameters, for example).

More info about efibootmgr at UEFI#efibootmgr. Forum post https://bbs.archlinux.org/viewtopic.php?pid=1090040#p1090040 .