# EFISTUB

Related articles

- Arch boot process
- Boot loaders
- Unified Extensible Firmware Interface

Warning: A bug has been noticed where booting EFISTUB can fail depending on kernel version and motherboard model. See FS#33745 and [1] 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.

Note: You can keep kernel and initramfs out of ESP if you use a boot manager which has a file system driver for the partition where they reside, e.g. rEFInd.

### 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-linux
    # cp /boot/initramfs-linux.img $esp/EFI/arch/initramfs-linux.img
    # cp /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-linux-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 automating it.

#### 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-linux
    ExecStart=/usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-linux.img
    ExecStart=/usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-linux-fallback.img

Enable these services with:

    # systemctl enable efistub-update.path

You will either need to reboot or tell systemd to begin watching the path with:

    # systemctl start efistub-update.path

#### Using 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-linux
    /usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-linux.img
    /usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-linux-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

#### Using 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-linux
    /usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-linux.img
    /usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-linux-fallback.img

    echo "Synced kernel with ESP"

#### Using mkinitcpio hook (2)

Another alternative to the above solutions, that is potentially cleaner because there are less copies and does not need a system level daemon to function. The logic is reversed, the initramfs is directly stored in the EFI partition, not copied in /boot. Then the kernel and any other additional files are copied to the ESP partition, thanks to a mkinitcpio hook.

Edit the file `/etc/mkinitcpio.d/linux.preset` :

    /etc/mkinitcpio.d/linux.preset

    # mkinitcpio preset file for the 'linux' package

    # Directory to copy the kernel, the initramfs...
    ESP_DIR="/boot/efi/EFI/arch"

    ALL_config="/etc/mkinitcpio.conf"
    ALL_kver="/boot/vmlinuz-linux"

    PRESETS=('default' 'fallback')

    #default_config="/etc/mkinitcpio.conf"
    default_image="${ESP_DIR}/initramfs-linux.img"
    default_options="-A esp-update-linux"

    #fallback_config="/etc/mkinitcpio.conf"
    fallback_image="${ESP_DIR}/initramfs-linux-fallback.img"
    fallback_options="-S autodetect"

Then create the file `/usr/lib/initcpio/install/esp-update-linux` which need to be executable :

    /usr/lib/initcpio/install/esp-update-linux

    # Directory to copy the kernel, the initramfs...
    ESP_DIR="/boot/efi/EFI/arch"

    build() {
    	cp /boot/vmlinuz-linux "${ESP_DIR}/vmlinuz-linux.efi"
    	# If ucode is used uncomment this line
    	#cp /boot/intel-ucode.img "${ESP_DIR}/"
    }

    help() {
    	cat <<HELPEOF
    This hook copies the kernel to the ESP partition
    HELPEOF
    }

To test that, just run:

    rm /boot/initramfs-linux-fallback.img
    rm /boot/initramfs-linux.img
    mkinitcpio -p linux

#### Using 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. If it works for you, this method is much simpler than the other approaches which copy files.

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`. In the following examples we will assume that everything is in `$esp/`.

### Using a boot manager

There are several UEFI boot managers which can provide additional options or simplify the process of UEFI booting - especially if you have multiple kernels/operating systems. See Boot loaders for more information.

### Using UEFI Shell

It is possible to launch an 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:
    > /vmlinuz-linux root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 initrd=/initramfs-linux.img

To avoid needing to remember all of your kernel parameters every time, you can save the executable command to a shell script such as `archlinux.nsh` on your UEFI System Partition, then run it with:

    > fs0:
    > archlinux

### Using UEFI directly (efibootmgr)

UEFI is designed to remove the need for an intermediate bootloader such as GRUB. If your motherboard has a good UEFI implementation, it is possible to embed the kernel parameters within a UEFI boot entry and for the motherboard to boot Arch directly. You can use `efibootmgr` to modify your motherboard's boot entries from within Arch.

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

Where `X` and `Y` are changed to reflect the disk and partition where the ESP is located. Change the `root=` parameter to reflect your Linux root (disk UUIDs can also be used).

Or with suspend to disk active:

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

Change the `resume=` parameter to reflect your swap partition, considering the same as above for the other options.

It is a good idea to then run

    # efibootmgr -v

to verify that the resulting entry is correct.

Warning: Some kernel and `efibootmgr` version combinations might refuse to create new boot entries. This could be due to lack of free space in the NVRAM. You can try deleting any EFI dump files

    # rm /sys/firmware/efi/efivars/dump-*

Or, as a last resort, boot with the `efi_no_storage_paranoia` kernel parameter. You can also try to downgrade your efibootmgr install to version 0.11.0 if you have it available in your cache. This version works with Linux version 4.0.6. See the bug discussion FS#34641 for more information.

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 .

Category:

- Boot loaders