Skip to content

Instantly share code, notes, and snippets.

@gokuldas
Last active February 6, 2022 21:07
Show Gist options
  • Save gokuldas/828eb87e433cc649c7dba0cf9e93cf64 to your computer and use it in GitHub Desktop.
Save gokuldas/828eb87e433cc649c7dba0cf9e93cf64 to your computer and use it in GitHub Desktop.
Multi-boot with UEFI

Multi-boot with UEFI

TLDR:

Procedure Summary: Details

  1. Make ESP
  2. Disable SecureBoot
  3. Install rEFInd
  4. Confirm boot into rEFInd
  5. Confirming boot on EFI
  6. Disable legacy boot
  7. Mount ESP to /boot or bind mount
  8. Install Bootloader
  9. Customize rEFInd menu and kernel parameters
  10. Make rEFInd update hook

Background

FSUG-TVM recently conducted a GNU/Linux install-fest. The feeling was unanimous. Everyone has gripes about UEFI firmware (including me). You were most likely to complete a BIOS/legacy OS install than a UEFI based install. There were several reasons for these:

  • Buggy UEFI implementation
  • Intentionally locked down UEFI boot sequence
  • Secure boot 'feature'
  • Incorrect or incomplete installation of bootloaders

Most of the problems would have been due to the last reason. UEFI would seem extremely complicated to someone who is used to only BIOS based installs. BIOS is indeed simpler compared to UEFI. It took a long time for me to figure out how to do a UEFI based install on my desktop. UEFI boot didn't work for me because I hadn't completed the procedure. I tried forcing UEFI only boot by disabling legacy boot. This however blew up on my face and the PC simply refused to boot - not even the firmware setup screen was available to make a recovery. I had to use jumpers on the motherboard to reset all firmware options. It was later determined that this was a bug in firmware. The problem was solved by a firmware update. But I remained stuck with legacy boot for a while.

I recently managed to complete UEFI multi-boot install for 2 OS - Arch Linux and TrueOS (FreeBSD). UEFI when done properly can give the system administrator a lot of flexibility, ease of operation, easy troubleshooting, safety and a lot of power when compared to BIOS. UEFI should be the preferred option to install OS when given a choice. This gist explains some basic concepts related to UEFI and the proper procedure to complete a UEFI based multi-boot install.

Technical Info

Firmware, BIOS, UEFI, Legacy and SecureBoot

Firmware: When PC is started up, the processor has absolutely no idea on how to load the OS and give control to the user. The job of loading OS is that of a small program called bootloader. However, the bootloader itself is on the harddisk. There are a lot of procedures to configure the harddisk and some other essential peripherals before anything on the harddisk is even accessible. The job of doing that configuration is carried out by a small software that resides in an NVRAM (Non-Volatile Memory). The PC hardware is hardwired to load the firmware into memory and execute it as soon as the PC is powered up. In a gist, the following is the sequence of booting:

  1. PC power is switched ON
  2. Hardware loads firmware from NVRAM into RAM and starts executing it
  3. Firmware configures some essential peripherals like HDD and memory controller
  4. Firmware loads a boot manager/loader into RAM and initiates its execution
  5. Boot loader loads bare minimum OS (kernel, RAMFS, RAMdisk)
  6. Kernel starts a userland application called init at PID-1
  7. Init starts loading all other application in a chain (display server, desktop manager, Desktop Environment)

The firmware has two major functions:

  • Configure hardware and initiate bootloader
  • Provide an interface (API) for certain software to access hardware

BIOS: From 1980s to until about 2011, the most common firmware was an implementation of the BIOS standard (Basic IO System). BIOS implementations were easy to manage and generally bug-free due to decades of development. However, the age of the standard shows a lot. Bootloading and APIs are anything but easy. BIOS could only load one OS's bootloader from harddisk. If other OSs were present, their bootloader had to be chain-loaded by the blessed bootloader. Detailed comparison of boot sequence by BIOS an UEFI is explained below.
The APIs of BIOS standard are 16 bit word length. These APIs were used a lot when processors were 16bit. As processors became 32bit ones and evetually 64bit ones, using these APIs accumulated a lot of overhead for mode switching. BIOS APIs are rarely used these days.

UEFI: The modern firmare that is used on all new PCs, laptops and some mobile devices since 2011 is an implementation of UEFI standard (Unified Extensible Firmware Interface). UEFI was created primarily by Intel and Microsoft. UEFI has a several advantages over BIOS:

  • UEFI can mount a complete harddisk partition that has a FAT32 file system (ESP)
  • BIOS uses a sort of hack to access bootloader from harddisk. UEFI can load one of any number of boot loaders/managers on ESP
  • Booting with UEFI is much simpler and less hacky than with BIOS
  • UEFI could even load other usefull UEFI applications (like a shell)
  • UEFI APIs can have same word length as processor (64 bit)
  • UEFI has a shell, shell commands and can be scripted like OS shells
  • UEFI can setup a full GUI (unlike TUIs for BIOS) for programs like bootmanager
  • UEFI gives access to IO devices like mouse or touchscreen even in a boot environment
  • UEFI can secure the low level software from malware and rootkits if you use SecureBoot
  • UEFI gives a comprehensive environment that can be used for troubleshooting if OS booting fails

UEFI is like a simple but extremely capable OS that loads directly from NVRAM. NVRAMs of earlier era used to be too small in capacity for firmwares the size of UEFI. However, large capacity NVRAMs are so cheap these days that there is no point in sticking with limited firmwares like BIOS.

Legacy Boot: The world is in a process of switching over to UEFI from BIOS. However, many UEFI implementations are buggy and havent yet stabilized. And many OS makers are still in the process of supporting UEFI. Most motherboard manufacturers therefore support booting to OS in a BIOS compatible way in addition to UEFI. This method is called Legacy Boot. I recommend disabling Legacy Boot unless your UEFI is buggy or locked down.

SecureBoot: There are malwares and rootkits that can affect even bootloaders. SecureBoot is an extension to EFI that secures the Computer from malware even at boot environment. In this method, a cryptographic public key is loaded in the firmware called 'Platform key' or PK. All boot loaders/managers have to be digitally signed with corresponding private key. While SecureBoot is enabled, UEFI will load the boot loader/manager only if the loader is not tampered with and thus verified with the signature.
Users can load their own PK and sign their own bootloaders and kernels with it. However, this is a technically involved process and difficult for most users. Instead, Microsoft persuaded most OEMs to include their PKs with UEFI firmware. This enables Windows OS released by Microsoft to be easily installed and securely booted in most desktops. However, this created a controversy alleging that this allows Microsoft to stifle competing OSs by making it hard to install those OSs. Microsoft responded by offering free signing service for other OSs using their key. Many distro developers like Redhat make use of this service. For regular users, I recommend disabling SecureBoot from firmware setup screen, until you learn to load PK and sign software.

UEFI Applications

UEFI allows applications to run directly with just UEFI even before OS is loaded. These are called UEFI applications. UEFI applications can have a rich user interface including full graphical interface and input from devices like mouse and touchscreen.
Everything loaded by UEFI is a UEFI application. This includes boot loaders, boot managers, command shell and other tools. These are easy to develop and deploy. They must just confirm to the following requirements:

  • Must be of EFI executable format
  • Must have a .efi filename extension
  • Must use only UEFI APIs
  • Must be on a partition that UEFI can read (ESP)

Partitioning Scheme: GPT vs MBR

Partitioning scheme: One name often heard with UEFI is GPT. GPT is a partitioning scheme for Harddisk and SSDs. Partitioning schemes allow the HDDs and SDDs to be divided up into smaller partitions or volumes (like C:, D:, E:, etc on Windows). This partitioning information is stored on a directly accessible area of the storage medium. Two of the common partitioning schemes are explained below:

Master Boot Record (MBR): This is an older scheme where the partitioning information is stored in the first sector of the storage device - called MBR. MBR also contain 446 bytes reserved for bootloader which can be easily discovered by BIOS. Each partition also has a reserved first sector called Volume Boot Record (VBR). VBR is where many OSs store their bootloaders. The bootloader in MBR loads boot loader from VBR.
MBRs have several inadequacies. 446 bytes is hardly adequate for any boot loader and makes it necessary to make boot loader in several stages. Also, MBR has limitations in size of storage device and the number of primary partitions it can support. MBR supports only 4 primary partitions. If you need more partitions, you have to convert one primary partition into an extended partition and then divide the extended partition into many logical partitions. However, many OSs can't boot from a logical partition and needs a primary partition.

GUID Partition Table (GPT): GPT is a newer scheme in which partitions are identified uniquely by an identifier named GUID. The partition table can hold information about a large number of partitions. Therefore, GPTs don't have logical partitions. All partitions are primary, and any OS can boot from any partition. GPTs also have a limited backwards compatibility with MBR, so that many BIOS systems are able to boot from GPT disks.

Choice of a Partitioning Scheme: Even though GPT is often mentioned along with UEFI, these two are not tied together. Both firmwares (BIOS and UEFI) are able to boot from disks of either partitioning scheme (MBR and GPT). However, GPT standard is managed by UEFI foundation and they recommend it. GPT is simply more powerful, flexible and simpler than MBR. GPT should be the preferred choice for a partitioning scheme with either UEFI or BIOS. The exception is in case of really old BIOS implementations that wont support GPT for some weird reason.

EFI System Partition (ESP)

ESP is the partition where UEFI applications - primarily Boot manager and Boot loader - are stored. It is a common practice to give ESP a special GUID and a 'boot' flag (not 'legacy-boot' flag). However, as this blog post mentions, this GUID and flag are not necessary for the firmware to treat a partition as ESP. UEFI will treat any partition containing UEFI applications it can read as ESP.

Technically, ESP should have a FAT32 filesystem format, as UEFI firmwares are commonly designed to read only FAT32 partitions. The partition should also have a minimum size of 100MB. The highest recommended size of ESP is 512MB. Since 512MB is only a small percentage of HDD memory these days, I recommend 512MB too for ESP.

Boot Loader

Boot loaders are programs that load the OS from HDD to RAM. These are often specific to each operating system. Boot loaders often dont have a user interface. They simply load the OS when they are executed.

EFISTUB: Linux kernels with version greater than 3.3 can act as their own UEFI bootloader. This eliminates the need for another traditional bootloader like GRUB or Syslinux under UEFI.

BSD Loader: BSDs use their own special boot loader outside of its kernels. The advantage of this boot loader is that it supports encryption features like GELI and PersonaCrypt.

Boot Manager

A boot manager is a user interface program that allows the user to choose the OS to boot into. Once the user makes the choice, the boot manager then loads the appropriate boot loader to continue with OS loading. Users are often confused by the distiction of the terms 'boot loader' and 'boot manager', since many of the legacy boot loaders had a UI and were infact combined boot manager + boot loader. This combination used to make sense in BIOS systems, where only one boot loader could be loaded by firmware. That boot loader had to give users a choice to chain load other OSs. Newer UEFI systems allow any number of bootloaders for each OS to reside on the ESP. Now the OS selection UI can be split away into a dedicated boot manager.

rEFInd: rEFInd is a modern OS-independant UEFI boot manager. rEFInd has the ability to search the disk for boot loaders, even outside ESP and present them to user on every boot. rEFInd is also easy to install. It often conveniently registers itself as the first boot program - making it easy for the user to avoid problems like boot breakage or boot coup. rEFInd also addresses many quirks and bugs in several UEFI implementations.

GRUB: Grand Unified BootLoader (GRUB) is a venerable bootloader for unices in the BIOS era. It has a UI for selecting OSs - making it a combined boot manager + boot loader. It also has the ability to chain load boot loaders of incompatible OSs like Windows. GRUB2 can work as bootloader under UEFI and BIOS. However, with Linux kernel gaining ability to bootload itself (EFISTUB), and with emergence of dedicated boot managers like rEFInd, GRUB is totally unnecessary in UEFI systems.

Boot sequence: BIOS vs UEFI

An understanding of boot sequences under BIOS and UEFI can help users install boot loaders properly under BIOS and UEFI.

BIOS boot sequence: BIOS boot sequence progresses in several stages due to limitations of stoarge space allotted to boot loaders.

  • Power ON: Firmware is read into memory
  • Firmware does hardware checks (POST) and hardware initialization
  • Firmware loads first stage OS independant boot loader from MBR called Secondary Program Loader (SPL)
  • SPL reads the MBR partition table and identifies a bootable partition
  • SPL loads an OS-specific boot loader from VBR of the bootable partition
  • This VBR boot loader may present options to user to select another OS
    • In case user selects another OS, its bootloader is chain loaded from that OS's partition's VBR
  • VBR boot code the proceeds to load OS kernel and all other OS services in a chain

UEFI boot sequence: UEFI's boot sequnce is simpler and more versatile than in BIOS. It is explained in more detail in this article.

  • Power ON: Firmware is read into memory
  • Firmware does hardware checks and does some hardware initialization
  • Firmware loads some variables from flash memory: BootOrder, Boot0001, Boot0002, ...
    • Boot0001, Boot0002 etc are DevicePaths to boot loader/managers
    • Eg: Boot0001 = ACPI(a0341d0,0)PCI(1f,2)SATA(0,0,0)HD(1,800,64000,12029cda-8961-470d-82ba-aeb17dba91a5)File(\EFI\fedora\shim.efi)
    • BootOrder is the priority list of DevicePaths. If BootOrder is 0002, 0001, 0003, the firmware will first try to load bootloader pointed to by DevicePath Boot0002. Failing that, from Boot0001, and so on
  • Firmware will initialize all devices in the DevicePath to access the boot loader
  • Even if the boot loader is not found in any of these paths, firmware will still try to initialize other hardware in search of a bootloader.
  • Once the bootloader is loaded, it will load the kernel and other services in a chain

Registering Boot Loader/Manager

As it should be evident by now, the key to ensuring a successful boot is to register the bootloaders/managers in the Boot#### variables, and set their priority correctly in BootOrder variable. Failure to do this is often the reason why we get unexpected results during bootup - like boot failure or the wrong OS booting up.

Boot Configuration registering can be done manually using the following tools:

  • efibootmgr: A linux command line utility
  • bcfg: A UEFI shell command line utility

It's worth noting that the first boot program needn't necessarily be a boot manager. You could register a boot loader if you want to boot into just one OS. It could also be other UEFI tools like UEFI shell. It is possible to load a boot loader even from the shell - possibly using scripts. This is useful for testing boot configurations and troubleshooting.

Boot Coup: Sometimes, some OSs during update will register its own bootloader as first boot program. This is called boot coup. However, such problems are easy to solve. Use one of the following methods:

  • Easiest: Reinstall rEFInd. rEFInd registers itself as priority if it can. Details here
  • If you are on Linux, use command line utility efibootmgr
  • Boot into a UEFI shell and manage boot entires using command bcfg

Detailed Procedure

Make ESP

You could skip this step if your PC is configured for UEFI bootup for atleast one OS. You can ensure that the disk is partitioned using GPT by running the following command from Linux:

sudo fdisk -l

The partition scheme can be identified from the 'Disklabel type' key in the output. In case your a partitioning a fresh HDD, it is highly recommended to use GPT.

The ESP should preferably have a size of 512MB and should be formatted with a FAT32 filesystem. It can optionally have the 'boot' flag enabled. All these can be done from Linux and BSD using fdisk or GParted, or Disk Management Tool on Windows.

Disable SecureBoot

SecureBoot is often an optional feature of UEFI. Even though it is possible for user to load his own keys in the firmware and sign the bootloaders, this is often cumbersome and it is easier to disable SecureBoot. Unsigned bootloader won't be loaded by the firmware if SecureBoot is enabled. Disabling SecureBoot can be done from the firmware setup screen, accessible by a special key (like F2) just after power on.

Install rEFInd

rEFInd is a boot manager that allows you to choose the OS to boot into. It does two useful things. It registers itself as the default boot program upon install. And it scans as many partitions as possible on every boot to find bootloaders and present them to the user (it can read many file systems, not just FAT32). Therefore, installing rEFInd first ensures that boot doesn't break and that every installed OS is always available - especially when installing new OS.

Procedures for installing rEFInd are available here. It details various scenarios like automated script based installs, manual installation and registering, etc. I will describe the easiset method - using Linux. Install refind package from your distro repository. On Arch, this is done using the following command:

sudo pacman -S refind-efi

Next step is to install refind in ESP and registering it. It can be done with single command:

sudo refind-install

This step is simple and usually just works. In case it doesn't, check for solutions here. And in case some other boot loader takes over the boot priority in a boot coup, you can recover following the instructions here

Confirm boot into rEFInd

After installing rEFInd to ESP, reboot to confirm that rEFInd is indeed the boot program that is loaded. In case it is not, do a recovery using efibootmgr or by reinstalling rEFInd.

Confirming boot on EFI

If you need to confirm at any stage that you booted Linux through UEFI, you can run the following command:

dmesg | grep efi

If the logs contain lines related to EFI, it is a confirmation that UEFI boot is working.

Disable legacy boot

At this stage, successful UEFI boot is confirmed and rEFInd is avaliable to prevent a boot failure. It's better to disable legacy boot in firmware to ensure that we don't end up with legacy boot by accident. This again can be done from firmware setup screen, that is accessible just after power ON using a special key like F2.

I faced a major problem when I tried this on my PC. The PC just refused to boot - even the firmware setup screen was not available. This was due to a firmware bug. If this happens, don't panic. Refer the manuals for the motherboard. Firmware reset can be done by changing a jumper setting on the motherboard. This will get the PC back in working order. Then download the latest firmware for the motherboard and flash it to the NVRAM. That should solve the problem.

Mount ESP to /boot or bind mount

Now you can proceed with installation of any OSs. The following procedure is specific to Linux and to some extend to BSDs. The aim of the following procedure is to ensure that boot loaders and kernel are accessible to boot manager, while being accessible to the distro's package manager for updates.

Most distros prefer to mount ESP at /boot/efi/. This method though, doesn't make the kernel and initrds accessible from ESP. Linux standards and Arch Linux recommend mounting ESP at /boot/ itself. More details are available here.

Arch Linux suggests a more involved, but elegant method of using a bind mount. Essentially this involes mounting the ESP to a special directory /esp/. Then the directory /esp/EFI/arch is bind mounted to /boot/. In this method, the ESP is not littered by distro specific files. Instead, the distro files are contained within a sub directory of ESP. Testing this method can be done by the following commands:

# ESP is assumed to be /dev/sda1. Modify accordingly
su
cd /
umount /dev/sda1 # In case ESP is already mounted
mkdir esp
mount /dev/sda1 /esp
mkdir -p /esp/EFI/arch
mv /boot/* /esp/EFI/arch/
mount --bind /esp/EFI/arch /boot

Once tested, this can be made permanent by adding following lines to /etc/fstab

UUID=xxxx-xxxx /esp vfat rw,defaults 0 2
# Replace xxxx-xxxx with UUID of your ESP
/esp/EFI/arch /boot none defaults,bind 0 0

Warning: Don't reboot yet. Boot will fail in this condition. The kernel doesn't know the partition where your root filesystem resides. You have to pass 'root' kernel parameter to the kernel for that. This can be done through rEFInd by creating a refind_linux.conf file in /esp/EFI/{os_name}. An example is given below:

"Default"    "root=UUID=xxxx-xxxx rw quiet splash add_efi_memmap initrd=/EFI/arch/initramfs-linux.img"
"Emergency"  "root=UUID=xxxx-xxxx rw add_efi_memmap initrd=/EFI/arch/initramfs-linux-fallback.img"
"Console"    "root=UUID=xxxx-xxxx rw add_efi_memmap systemd.unit=multi-user.target initrd=/EFI/arch/initramfs-linux.img"

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

More details of that is available here and here.

Install Bootloader

The bootloader for the OS should be loaded into ESP or in a partition that rEFInd can access - which fortunately include most types of linux partitions.

If you are going to use EFISTUB bootloader of linux kernel, your work is mostly over. The rEFInd bootmanager is already in place. The bootloading kernel itself is in the /boot folder - which is accessible to rEFInd. In case you decided to follow last step (mounting ESP to /boot or bind mounting), your kernel is already inside ESP and very well accessible to any boot manager.

GRUB2 bootloader is really unnecessary under UEFI. But, in case you need it for some reason, instructions are available here.

Customize rEFInd menu and kernel parameters

At this stage, your UEFI boot setup is ready and you can confirm by test booting. But you may want to customize further. You can customize rEFInd boot menu by following instructions here. You could also modify kernel parameters - for example, enabling splash screen or KMS - by following instructions here.

Make rEFInd update hook

An important point to note is that installing or updating the rEFInd distro package alone won't install the boot manager into ESP. You have to run refind-install during installation and each time refind is updated by distro package manager. You could create a distro specific post-install hook to automatically update rEFInd in ESP each time the distro updates the package. If you are using arch linux, the pacman post-update hook is file /etc/pacman.d/hooks/refind.hook. Its contents are as follows:

[Trigger]
Operation=Upgrade
Type=Package
Target=refind-efi

[Action]
Description = Updating rEFInd on ESP
When=PostTransaction
Exec=/usr/bin/refind-install

Be careful to do the installation and updation of rEFInd in ESP from only one OS, lest it may cause a contention. Detailed instruction are available here.

Conclusion

By now, you should have a completely customized and fully functional UEFI multi-boot setup. Most update tasks are automated and file system is designed to be clean. UEFI may seem daunting at first. But I expect it to become the tool in the hands of even intermediate PC users to confidently troubleshoot problems like boot failures. For advanced users, UEFI presents a great opportunity to grok the lower level hardware easily. By learning some basic concepts and procedures, PC maintainance and troubleshooting should be orders of magnitude easier.

Author: Gokul Das B
Date: 17 July 2017

@karuvally
Copy link

Thankyou for writing a comprehensive tutorial 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment