Goals and non-goals

Goals

  • devices produced by Tails Installer should boot on most UEFI-only hardware (e.g. some relevant set of Macs)
  • devices produced by Tails Installer should boot on most hardware that only supports UEFI boot for GPT devices (e.g. ThinkPad X220)
  • Legacy BIOS boot support should be left unaffected (modulo a tiny amount of really crazy firmware bugs, probably)
  • minimal support for 32-bit UEFI boot

Non-goals

  • UEFI DVD boot: BIOS boot from DVD works fine on most hardware, including Macs; adding the files needed to have UEFI DVD boot work on some systems will break what currently works for others.
  • UEFI boot from hybrid ISO cat'd on a USB device: given BIOS DVD boot works generally fine, it's OK to require users to go this way and install their UEFI-capable Tails USB stick from DVD. In case one has no DVD writer, another potentially workable option is to bootstrap in Legacy BIOS boot mode from hybrid ISO cat'd on a USB device. If the firmware supports it, this can be done on the same computer; else, from another computer.
  • UEFI Secure boot is not part of this plan. Picking technical solutions that leave room for it would be a great bonus, though.
  • UEFI boot on Mac without rEFInd would be too ambitious a goal for this iteration. Besides, we think that installing rEFInd is not that crazy a requirement, considering the additional features a device installed with Tails Installed provides (namely: persistence and incremental upgrades).

Discussion and conclusions

We have conducted an initial research and testing effort, aiming at choosing tools and procedures to add UEFI boot support to Tails. Our goals and non-goals are stated above.

The outcome of this project exceeded our expectations: we now have not only all important design decisions made, but also a prototype implementation that can already be downloaded and tested. It is built from our feature/uefi Git branch.

In this document, we first summarize our findings regarding the choice of a boot loader, and state the conclusions we have reached. Then, we discuss the implementation details that matter most. Finally, we sum up the next steps toward deploying Tails with UEFI support to the masses, and provide an overview of improvements that we may need to make in the future.

Choosing a boot loader

A large number of UEFI boot loader implementations are available. We have limited our selection to the options that meet the following conditions:

  1. available in Debian (excludes Gummiboot and rEFInd);
  2. actively maintained upstream (excludes BURG, ELILO and rEFIt);
  3. easy to integrate into the Debian Live ISO build process;
  4. no requirement to add boot entries to NVRAM;
  5. no requirement to recompile or modify the Linux kernels we install from Debian (excludes the Linux kernel EFISTUB).

So, we have considered two boot loaders, namely GRUB (not to be confused with GRUB Legacy) and syslinux (version 6). There is a lot to say about these two pieces of software, and we will focus on the criteria that seem relevant for a Debian Live system, and for Tails in particular.

GRUB

Pros:

  • GRUB has many features and is highly flexible (e.g. scripting language, many existing modules).
  • GRUB's support for UEFI has been tested in the field for a few years now, by many GNU/Linux distributions that added UEFI support back when syslinux did not support it ⇒ it supports probably more edge cases (aka. buggy firmware), especially for graphics support.
  • GRUB supports UEFI Secure boot, and is used (in various ways) by most GNU/Linux distributions that provide this feature.

Cons:

  • GRUB is complex software. Its many features and configuration options can be slightly overwhelming, and may hinder our potential to attract and welcome new contributors.
  • We would have to create a GRUB version of our menu and graphical theme configuration, and either migrate to GRUB for Legacy BIOS too (which adds quite some risks of regressions that must be evaluated and mitigated), or to maintain this configuration in addition to the existing syslinux one that would still be be used in Legacy BIOS mode.
  • GRUB is not so popular in the Live systems world ⇒ might have issues in this area that major non-Live GNU/Linux distributions did not catch.
  • We lack an evaluation of how hard it would be to backport recent enough versions of GRUB for Squeeze and Wheezy.

syslinux

Pros:

  • Tails has been using syslinux forever, and we are pretty happy with it.
  • syslinux is very popular in Live GNU/Linux distributions ⇒ picking it gives good potential for inter-distro cooperation. Notably, Debian Live systems use syslinux by default.
  • Debian Live's UEFI support will be based on syslinux 6.
  • We were able to trivially backport syslinux 6 for Squeeze.

Cons:

  • syslinux' support for UEFI is quite young; this is slightly mitigated by the fact that at least one high-profile Live system (Knoppix) already uses it, and presumably adding another one into the mix (Tails) might foster upstream development a bit, and result in rapid fixing of the most important remaining glitches.
  • syslinux has limited support for UEFI boot from DVD; this is a non-goal for us in this iteration, but still.
  • Using syslinux with Secure boot is maybe broken, but maybe not. That is, it could use some love and testing, to say the least.
  • syslinux is available in Debian experimental only, and it is hard to know when this might change.

Multiple boot loaders

Technically, it is entirely possible to install multiple UEFI boot loaders onto the Tails system partition (which is, conveniently, the EFI System Partition). This would allow users whose hardware is not supported by the default one, to boot using the other.

However:

  • some hardware is only able to boot the fallback UEFI boot loader, so we have to pick a default one anyway; then, users whose hardware only boots the fallback UEFI boot loader and is not well supported by this one would not be able to boot Tails anyway, without fiddling (in unsupported ways) with boot loader configuration;
  • the resulting user interface in the firmware boot menu would display more entries; hence, the needed documentation would be more complex to write, maintain, and, more importantly, to read and follow.

Conclusions

First, we believe the user experience that would result from installing multiple boot loaders would be much less smooth overall, so we are rejecting this option for now. Still, if broader testing and user feedback showed that none of the other available options is good enough by itself, we might have to reconsider.

Second, in our early testing, GRUB and syslinux appeared to be perfectly on par with each other, as far as hardware support is concerned. To be fair, it must be noted that GRUB was tested in the simpler, and likely more robust text-only mode, while we have taken benefit of our existing configuration and graphical theme to test syslinux a bit more extensively. So, with the data we have at hand, quality of hardware support cannot be used as a criterion in this decision.

We must say that GRUB's flexibility and mature UEFI support is seriously appealing to us. Also, even if Secure boot is not part of this first iteration, it is very tempting to bet on a boot loader that is already in wide use in this area. Still, we feel that continuing to use syslinux both for Legacy BIOS and UEFI boot will make Tails blend better with the surrounding Live operating system environment, particularly Debian Live, which has many advantages both for Tails users and developers. Added to that, the lesser risk of regressions for existing Tails users, and the lesser impact on our project's resources, were decisive.

Our final take on this is to use syslinux 6 as our boot loader of choice, for the initial UEFI boot support in Tails.

To end with, it has to be said that switching boot loaders in the future appears to be pretty easy from a technical standpoint. Of course, the quality assurance effort that would go with it in order to assert the risk for regressions, shall not be overlooked: it is generally bad for user experience to break support for hardware that was previously known-working, even if the very change that causes this breakage allows to support many more systems in total. Regardless, we do not consider the current decision as set in stone. We think it would be perfectly workable to switch to GRUB or another boot loader later on, if it proves to be needed for future developments of Tails, or to adjust our position to match changes in the ecosystem thereabout.

Implementation

Even if it is slightly out-of-scope, as far as the project that called for this document is concerned, we discuss here a few important implementation details we have had the opportunity to think of, experiment with, and reach conclusions about, while we were conducting this research and testing project.

Boot device partitioning

UEFI theoretically supports the standard PC disk partition scheme (MBR), but in practice it is most often used to boot off devices with a GUID Partition Table (GPT). Add to this that GPT supports labelling partitions (as opposed to filesystem labels, that are useless for detecting an encrypted Debian Live persistent volume). This is why we have decided, back when we were implementing persistence support and a graphical USB installer in 2012, to initialize Tails boot devices with a GPT. Since then, we have made great use of this feature in Tails Persistent Volume Assistant, Incremental Upgrader and Greeter.

Despite a few painful consequences we discovered along the way, all caused by buggy firmware implementations, we think that picking GPT at that point was the right choice to make. We now have the opportunity to take advantage of it even more, and to surpass the aforementioned firmware limitations, by adding UEFI support to Tails.

Boot loader installation path

During our early testing, we have discovered that some hardware does not support running a UEFI boot loader, without entries added to the NVRAM, unless it is installed in the path meant for the device's fallback UEFI boot loader (EFI/BOOT/BOOTX64.EFI). At this point, let us make three observations:

  1. It is clearly not an option for most Tails users to fiddle with efibootmgr each time they encounter such a system. This is not only impractical and tedious, but requires technical expertise that exceeds what our design goals expect from our users.
  2. Developers and researchers in the GNU/Linux distributions field have discovered many issues with how NVRAM and boot entries are managed by UEFI firmware, often resulting in non-bootable systems, and sometimes in fully bricked hardware, unless special tricks are used. We do not feel comfortable assuming that every such problem has been detected and workaround'ed to this date, and our current team lacks the expertise to tackle this problem with great confidence.
  3. Tails is designed to avoid leaving traces on the hardware being used to run it. Without further consideration, our position is to assume that adding boot entries in the computer's NVRAM directly conflicts with this design goal.

Therefore, we will not add boot entries for Tails in the NVRAM, and our only practically available choice is to install our boot loader of choice as the fallback UEFI boot loader on Tails devices.

Available Linux kernels

We are aiming to support UEFI boot in Tails for 64-bit hardware only. Then, the included UEFI boot loader has to be a 64-bit one. Running a 32-bit kernel from a 64-bit UEFI boot loader does not work. Therefore, we have to ship a 64-bit kernel, in addition to (at least) one 32-bit kernel, the latter being needed to provide continued support for 32-bit hardware.

The set of Linux kernels shipped in Tails has to be modified to add a 64-bit kernel, in replacement of the 686-pae flavour. This causes only a few minor problems that, in our opinion, are worth neither blocking the addition of UEFI support, nor keeping the 686-pae kernel and bloating the ISO with a third kernel.

Boot loader configuration

The syslinux configuration that is already used for Legacy BIOS boot is copied as-is into the UEFI boot loader configuration directory.

Build-time implementation

Two build-time hooks take care of the UEFI boot loader setup:

  • config/chroot_local-hooks/60-copy-syslinux-modules
  • config/binary_local-hooks/99-syslinux_uefi

Tails Installer

Tails Installer creates the Tails system partition as an EFI System Partition (ESP), with the corresponding GUID. Additionally, it was adapted to support paths used by the syslinux 6 Debian packages, and in the EFI/BOOT directory.

syslinux backport

A backport of syslinux 6.x is installed from our APT repository.

32-bit UEFI

Chosen path

A 32-bit UEFI GRUB2 bootloader is installed in the fallback location. It is configured to load our existing syslinux configuration, and to convert it on the fly to GRUB's format:

Support for {vesa,}menu.c32 was added in GRUB upstream, but didn't make it into Debian yet as of 2.02~beta2-22, so we have backported these patches and are shipping a custom GRUB2 package.

Discarded implementation ideas

syslinux

It's currently impossible with upstream syslinux to have both 32-bit and 64-bit UEFI boot loaders installed in the fallback path, without forcing the user to manually choose between them, which would degrade UX substantially for users who have 64-bit UEFI working fine already.

Once the proposed patches have been merged upstream, we may want to replace our current implementation with a syslinux-based one, for greater UX consistency.

32-bit GRUB2 EFI chainloading 32-bit syslinux EFI

  • syslinux 32-bit EFI installed in EFI/TAILS32
  • GRUB 32-bit EFI installed in EFI/BOOT/BOOTIA32.EFI

=> did not manage to chainload 32-bit syslinux EFI from GRUB. On Tails/Jessie (GRUB 2.02~beta2-22), I get error: unknown error. after typing boot. This likely comes from grub-core/loader/efi/chainloader.c.

32-bit GRUB2 EFI with native configuration

This requires to write/generate and maintain a GRUB2 configuration, either semi-automatically (e.g. with grub-syslinux2cfg) or by hand.

Future work

See the corresponding blueprint.