Bounding Unicorns

How To Create Portable UEFI Boot Disk in Linux

With a BIOS (legacy) boot, once an operating system is installed on a hard drive or an SSD, the drive can be moved to another computer and it will boot there just fine into the installed operating system. With UEFI boot, at least with Linux, this is no longer happening - if Linux is installed onto a drive in UEFI mode, and this drive is moved to another computer which has never had Linux (potentially of the same base distribution, such as Debian) installed on it, the drive will not boot.

The reason for this is that, apparently to improve the multi-boot experience, UEFI moves the boot loader from the storage device into computer firmware (located on the mainboard). Thus, moving the storage device to another computer is insufficient to actually make use of it, since the new computer lacks the correct bootloader configuration in its firmware.

In BIOS mode, the first sectors of a hard drive contain the first stage of the bootloader. BIOS code executes this first stage. The first stage in turn loads the second stage, which could be the Windows bootloader that can only boot Windows or a bootloader like GRUB that can offer a menu to choose various operating systems.

In UEFI mode, the hard drive must have a special EFI partition. This partition contains second stage boot loaders for various vendors - for example Debian. However, there is no first stage on the hard drive at all; the first stage (which picks the second stage to load) exists now only in the mainboard firmware.

Thus, when GRUB is installed in UEFI mode, it does two things:

  1. It writes its second stage to the EFI system partition (ESP).
  2. It writes EFI variables to the mainboard announcing its existence.

When the computer subsequently boots, the firmware reads the EFI variables and can boot GRUB's second stage. But lacking these EFI variables, the firmware will not attempt to load GRUB's second stage at all, and the machine won't be bootable.

Thus, normally, when a drive is moved to another computer, the system needs to be brought up from rescue media, and GRUB reinstalled into the firmware of the new system.

To make a portable installation, we can use something called the "fallback bootloader". This is conceptually the same thing as the BIOS first stage bootloader - it is a bootloader that resides in a known location on the disk so that any UEFI computer will attempt to load it. For some reason Debian installer not only does not install this fallback bootloader by default, it doesn't even prompt the user to make their installation portable. Luckily, the situation can be remedied.

This page describes how to use the fallback bootloader. Specifically, on the EFI system partition, we need to copy EFI/debian/grubx64.efi to EFI/boot/bootx64.efi, EFI/boot/bootx64.efi being the universally recognized bootloader. There is no harm in doing this on any system that only has a single operating system installed (e.g. Linux).

Assuming the hard drive is /dev/sdb, and the EFI system partition is the first one (/dev/sdb1), to make this drive universally bootable we need to execute:

mount /dev/sdb1 /mnt
mkdir /mnt/EFI/boot
cp /mnt/EFI/debian/grubx64.efi /mnt/EFI/boot/bootx64.efi
umount /mnt

This will render the drive bootable but updates to the bootloader won't be copied to the fallback location just yet. To configure that, we need to execute in the running system:

echo "grub-efi-amd64 grub2/force_efi_extra_removable boolean true" | sudo debconf-set-selections