# UEFI - Unified EFI - [Overview](#overview) - [Identification](#identification) - [Partition Layout](#partition-layout) - [Partition Table](#partition-table) - [Filesystem Mounts](#filesystem-mounts) - [GRUB Layout](#grub-layout) - [RHEL / CentOS](#rhel-centos) - [Debian / Ubuntu](#debian-ubuntu) - [GRUB Installation](#grub-installation) - [RHEL / CentOS](#rhel-centos-1) - [Debian / Ubuntu](#debian-ubuntu-1) - [EFI Boot to GRUB](#efi-boot-to-grub) - [Boot Process](#boot-process) - [RHEL / CentOS](#rhel-centos-2) - [Debian / Ubuntu](#debian-ubuntu-2) - [Rescue Mode](#rescue-mode) - [UEFI Shell](#uefi-shell) - [EFI Applications](#efi-applications) - [RHEL / CentOS](#rhel-centos-3) - [Ubuntu / Debian](#ubuntu-debian) - [Troubleshooting](#troubleshooting) - [Setting EFI Boot Order](#setting-efi-boot-order) - [Add EFI Boot Option](#add-efi-boot-option) - [References](#references) ## Overview [From Intel](https://www.intel.com/content/www/us/en/architecture-and-technology/unified-extensible-firmware-interface/efi-homepage-general-technology.html) on the origins and how the acronym UEFI and EFI are related, as they tend to be used interchangeably on many websites and in a lot of documentation (only a select portion of this web page reproduced here): > The Unified EFI (UEFI) Specification (previously known as the EFI Specification) defines an interface between an operating system and platform firmware. Intel's original version of this specification was publicly named EFI, ending with the EFI 1.10 version. > > In 2005, The Unified EFI Forum was formed as an industry-wide organization to promote adoption and continue the development of the EFI Specification. Using the EFI 1.10 Specification as the starting point, this industry group released the following specifications, renamed Unified EFI. For the Linux tech, this boils down to three major items on a server: - The GPT partition table is used, MBR is not allowed - Because GPT is used, > 2T boot disks can be supported - A special [vfat](https://en.wikipedia.org/wiki/File_Allocation_Table#VFAT) partition `/boot/efi` exists on the system for GRUB, the kernel and others to use This article will cover the operational aspects of working with UEFI Linux systems. ## Identification The One True Way to know if the Linux system is booted into EFI mode is the presence of this virtual directory, only when booted to EFI mode: ``` /sys/firmware/efi/ ``` This is a defined standard in the Linux kernel and can be used reliably to determine if the server is currently booted to EFI mode or traditional BIOS. Within this directory will be a handful of interfaces which can manipulate the EFI infrastructure itself. When booted in traditional BIOS mode, this directory will be completely missing. ## Partition Layout In general, the design is such that the first partition is the special EFI code, the second is the traditional boot, and the third the rest of the system. Remember, as this is a native GPT partition table there is no special primary/extended problem as there is with MBR, it's just flat partitions all the way. Visually it may feel odd, as the first partition is mounted underneath the second one (so, it appears backwards in mounting from how it appears in the partition table). ### Partition Table ``` # parted /dev/sda unit s print ... Partition Table: gpt Disk Flags: Number Start End Size File system Name Flags 1 2048s 520192s 518145s fat32 EFI boot 2 522240s 1546240s 1024001s ext4 boot boot 3 1548288s 936640478s 935092191s pv0 lvm ``` ### Filesystem Mounts ``` # df -h | grep -v tmpfs Filesystem Size Used Avail Use% Mounted on /dev/mapper/vglocal20171117-root00 439G 3.5G 435G 1% / /dev/sda2 477M 219M 254M 47% /boot /dev/sda1 252M 9.7M 242M 4% /boot/efi /dev/mapper/vglocal20171117-tmp00 2.0G 3.2M 2.0G 1% /tmp ``` ## GRUB Layout The majority of changes about dealing with EFI happen at the GRUB layer; most of the work is performed at install time however upon occasion it's required to repair or manually manipulate the GRUB configuration. The implementation differs from vendor to vendor, and even within RHEL and CentOS there are minor differences. > The GRUB configuration maker (`grub2-mkconfig` / `grub-mkconfig`) does not support writing both an EFI and BIOS version of the grub.cfg file. When the script is run, it looks for the `/sys/firmware/efi` directory, and if found it will create all GRUB menu entries in EFI mode. There is currently no way to override this other than hacking the script to change this behaviour. Once you build GRUB in EFI mode, do not attempt to change the server to BIOS mode and boot it unless you have manually created a non-EFI config file. ### RHEL / CentOS At it's core, three additional packages are added to the OS on top of all the other traditional (non-EFI) GRUB packages: ``` grub2-efi-x64 efibootmgr shim ``` The installation of these three packages changes the system to implement a few fundamental designs which must be taken into account: 1. The GRUB environment boot block – which stores the named kernel (version) to boot - is moved and symlinked upon package install. Before: ``` # ls -lG /boot/grub2/grubenv -rw-r--r--. 1 root 1024 Sep 26 11:23 /boot/grub2/grubenv ``` After: ``` # ls -lG /boot/grub2/grubenv lrwxrwxrwx. 1 root 28 Nov 17 10:12 /boot/grub2/grubenv -> /boot/efi/EFI/redhat/grubenv ``` The installation of `grub2-efi-x64` moves the boot block to an EFI only area, and it does not work if you boot the server in non-EFI mode with the grub EFI package installed! When booting non-EFI, GRUB will simply not find any boot block (the symlink doesn't work to GRUB) and boot the first kernel found. (Editor's note: Fedora changed this to be relative not absolute, a Red Hat case was opened asking them to backport this to RHEL7 so that the grub2-efi-x64 managed symlink will work in if it's installed on a non-EFI booting system. https://access.redhat.com/support/cases/#/case/01907436 ) 2. There are two GRUB config files - one for EFI, one for non-EFI. Red Hat handles this externally via symlinks, like so: ``` # ls -lG /etc/grub*.cfg lrwxrwxrwx. 1 root 22 Nov 17 10:12 /etc/grub2.cfg -> ../boot/grub2/grub.cfg lrwxrwxrwx. 1 root 31 Nov 17 10:12 /etc/grub2-efi.cfg -> ../boot/efi/EFI/redhat/grub.cfg ``` When manually updating grub.cfg (using `grub2-mkconfig`, `vim`, etc.) be sure to edit the correct EFI config file! The kernel RPM upgrades call the shell script `/sbin/new-kernel-pkg` which updates both config files for us, making it seem transparent. The 'redhat' subdirectory will be 'centos' on a CentOS system (most likely to avoid the trademark issues), see below. 3. GRUB sees it's boot area differently - when making changes to grub.cfg, make the backup file in the same directory as the original – in `/boot/grub2` for non-EFI, in `/boot/efi/EFI/{redhat,centos}/` for the EFI version. This way if you need to boot grub manually with the backup it's within view at the GRUB console as expected. ### Debian / Ubuntu At it's core, three additional packages are added to the OS on top of all the other traditional (non-EFI) GRUB packages: ``` grub-efi-amd64 efibootmgr shim ``` Unlike the Red Hat design, Ubuntu integrates the EFI work into the existing GRUB configuration using an 'include' style architecture. 1. The GRUB environment block - grubenv - is unchanged and lives in `/boot/grub/` 2. The GRUB config file - grub.cfg - is unchanged and lives in `/boot/grub/` 3. The EFI GRUB `/boot/efi/EFI/ubuntu/grub.cfg` is a small include file that generally looks like this: If `/boot` is on it's own unique partition (/dev/sda2, e.g.): ``` search.fs_uuid root hd0,gpt2 set prefix=($root)'/grub' configfile $prefix/grub.cfg ``` If `/boot` is just a subdirectory of the root / partition (one filesystem): ``` search.fs_uuid root set prefix=($root)'/boot/grub' configfile $prefix/grub.cfg ``` The value of `$prefix` is carried into the `/boot/grub/grub.cfg` file, which is how it finds it's grubenv file in the same way: ``` if [ -s $prefix/grubenv]; then set have_grubenv=true ... ``` Using this design, the EFI files simply include the main configuration files in their traditional location. This would imply compatibility with all existing tooling and the need to generate only one config file when making changes. ## GRUB Installation The process to prepare a system for EFI use with the GRUB packages differs; besides running a similar boot block install command, a secondary command must be run to update the EFI Bootmanager data to know how to boot the system. **Note**: in most (if not all) cases after setting up GRUB the commands must be set for the Boot Order, see the section further down with instructions on this process - boot order is for EFI, not GRUB in this case. (GRUB only handles the actual kernels to boot after EFI has booted into it) ### RHEL / CentOS The process is almost identical, except for the name change to avoid trademark infringement by CentOS (standard design change). ``` ## Required packages done during install, mock install for reference here: yum install grub2-efi efibootmgr shim ## Install the boot block and tell it where EFI data is grub2-install --target=x86_64-efi \ --efi-directory=/boot/efi \ --bootloader-id=grub \ --debug ## RHEL system - notice the directory name and label efibootmgr --create --gpt \ --disk /dev/sda --part 1 --write-signature \ --label "Red Hat Enterprise Linux" \ --loader /EFI/redhat/shim.efi ## CentOS system - notice the directory name and label efibootmgr --create --gpt \ --disk /dev/sda --part 1 --write-signature \ --label "CentOS Linux" \ --loader /EFI/centos/shim.efi # Build the config from /etc/default/grub into the EFI area grub2-mkconfig > /boot/efi/EFI/redhat/grub.cfg ``` As mentioned above, there is a non-EFI grub config (not being updated here) and the EFI grub config file as shown above. They are not symlinked together – when GRUB boots in non-EFI vs. EFI mode it sees the partitions differently. ### Debian / Ubuntu The process is generally the same, this platform provides a nicer way to update GRUB2 but is otherwise the same work: ``` ## Required packages done during install, mock install for reference here: apt-get update && apt-get install grub-efi-amd64 grub-efi-amd64-bin \ grub-efi-amd64-signed efibootmgr shim shim-signed ## Install the boot block and tell it where EFI data is grub2-install --target=x86_64-efi \ --efi-directory=/boot/efi \ --bootloader-id=grub \ --debug ## Create the EFI bootloader entry efibootmgr --create --gpt \ --disk /dev/sda --part 1 --write-signature \ --label "Ubuntu Linux" \ --loader /EFI/ubuntu/shimx64.efi ## Update GRUB update-grub ``` ### EFI Boot to GRUB This is normally handled automatically by the `efibootmgr` command when adding the new entry; if needed, see the Troubleshooting section below Setting EFI Boot Order to have EFI hand off the boot to GRUB appropriately. ## Boot Process Based on the above layout, the boot process can now be examined - the EFI firmware has an understanding of partition types and tables for many platforms and expects there to be EFI applications on the vfat (fat32, "sda1") partition at the start of the disk as well as custom settings such as the EFI Bootloader menu. See the EFI Applications section for a full rundown of the contents of this disk area. ### RHEL / CentOS This is [documented very succinctly by Red Hat](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/installation_guide/s2-grub-whatis-booting-uefi), reproduced here: 1. The UEFI-based platform reads the partition table on the system storage and mounts the EFI System Partition (ESP), a VFAT partition labeled with a particular globally unique identifier (GUID). The ESP contains EFI applications such as bootloaders and utility software, stored in directories specific to software vendors. Viewed from within the Red Hat Enterprise Linux 6.9 file system, the ESP is /boot/efi/, and EFI software provided by Red Hat is stored in `/boot/efi/EFI/redhat/`. 2. The `/boot/efi/EFI/redhat/` directory contains `grub.efi`, a version of GRUB compiled for the EFI firmware architecture as an EFI application. In the simplest case, the EFI boot manager selects grub.efi as the default bootloader and reads it into memory. If the ESP contains other EFI applications, the EFI boot manager might prompt you to select an application to run, rather than load grub.efi automatically. 3. GRUB determines which operating system or kernel to start, loads it into memory, and transfers control of the machine to that operating system. The last step is what reads `grub.cfg` and the environment boot block (grubenv) to know which kernel to boot with the desired options. The above is not 100% true in RHEL7, as the system launches shim.efi which then launches grub.efi - shim.efi is signed, grub.efi is not so if a system is set to SecureBoot it needs to launch a shim. ### Debian / Ubuntu The same as the above just with minor details changed unique to the vendor. Upstream: https://help.ubuntu.com/community/UEFI ## Rescue Mode ### UEFI Shell When the UEFI firmware fails to boot GRUB (due to any random reason - if you're here something has definitely gone wrong), it will drop you into the UEFI Shell. It's a daunting looking interface, and depends on the exact vendor to determine what it looks like. In general, remember these tips: 1. It acts like Windows - the paths have `\` chars, 'ls' shows Windows-like directory lists, etc. 2. `FS0:` is the magic EFI-ESP boot area, simply typing `FS0: ` like on Windows C:\ or D:\ 3. Once in `FS0:\\`, find the `shimx64.efi` file and run it like a Windows command - it will load GRUB for you The shim file should transparently boot you into the GRUB binary; however, it's possible to just boot the `grubx64.efi` file directly as well. Each EFI file is a binary which can be run (mmx64.efi is MOK Manager, generally useless in daily life - shimx64.efi and grubx64.efi are what you're after to run). Generally speaking, if you're been dumped into the UEFI Shell it indicates that one of two things has gone wrong: 1. The GRUB boot block has not been installed properly to /dev/sda, `grub-install` is needed to repair 2. The EFI bootloader does not have a config to launch GRUB, `efibootmgr` is needed to repair Running the `grub-install` process may run the `efibootmgr` process automatically as one of it's finishing steps, confirmed on at least Ubuntu 16 that it does. A broken Ubuntu 16 install was repaired in one shot using this command as an example - this is only an example: ``` # grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader=grub --debug ``` Results will vary - by definition what is broken depends on the exact situation at hand, not all things break in the same way. The above example fixes the most basic problem - the GRUB boot block and/or EFI entry was not properly installed and needed a quick repair. ## EFI Applications What are all these files in `/boot/efi`? The EFI design is such that it can run any applications written with the EFI SDK - basically, 32bit Windows (PE-executable) files. While the normal usage doesn't require touching any of these, it's handy to understand what they are for. ### RHEL / CentOS Replace the vendor name (redhat -> centos) below, otherwise the same. | Filename | Purpose | | ----------------------------------------- | ------- | | `/boot/efi/EFI/BOOT/BOOTX64.EFI` | The standard, unsigned, GNU EFI Bootloader application - used by bootable USB drives for example | | `/boot/efi/EFI/BOOT/fbx64.efi` | The fallback EFI application if the GNU EFI Bootloader fails to find any options or bootloader order (scans on the fly) | | `/boot/efi/EFI/redhat/mmx64.efi` | MOK Manager app - the EFI application to sign apps with keys | | `/boot/efi/EFI/redhat/shim.efi` | The signed - by Microsoft - EFI Bootloader (aka SecureBoot) | | `/boot/efi/EFI/redhat/shimx64.efi` | A copy of shim.efi for compatibility, exact same file as the above | | `/boot/efi/EFI/redhat/shimx64-redhat.efi` | The Red Hat key signed version of the GNU EFI Bootloader application | | `/boot/efi/EFI/redhat/grubx64.efi` | The unsigned GRUB binary application, it is transparently launched by the signed shim.efi / shimx86.efi | | `/boot/efi/EFI/Dell/BootOptionCache/BootOptionCache.dat` | Dell firmware settings for EFI boot options | | `/boot/efi/EFI/redhat/grubenv` | GRUB environment boot block, kernel name to boot stored here | | `/boot/efi/EFI/redhat/grub.cfg` | GRUB EFI configuration file | | `/boot/efi/EFI/redhat/fonts/unicode.pf2` | Fonts for use with GRUB / other EFI apps | | `/boot/efi/EFI/redhat/BOOT.CSV / BOOTX64.CSV` | The EFI Bootloader application options managed by efibootmgr (loads shim.efi, basically) | ### Ubuntu / Debian The Ubuntu system keeps an identical copy of files in `/boot/efi/EFI/grub` and `/boot/efi/EFI/ubuntu` - the contents are copied in from outside dynamically, unlike the RHEL/CentOS packages which install the files directly into the `/boot/efi` area. | Filename | Purpose | | ----------------------------------------- | ------- | | `/boot/efi/EFI/{grub,ubuntu}/grub.cfg` | GRUB include file which sources /boot/grub/grub.cfg on the fly using the UUID of the disk | | `/boot/efi/EFI/{grub,ubuntu}/grubx64.efi` | The unsigned GRUB binary application, it is transparently launched by the signed shimx86.efi | | `/boot/efi/EFI/{grub,ubuntu}/mmx64.efi` | MOK Manager app - the EFI application to sign apps with keys | | `/boot/efi/EFI/{grub,ubuntu}/shimx64.efi` | The signed - by Microsoft - EFI Bootloader (aka SecureBoot) | These are sourced from the other packages: | Package | Filename | Purpose | | ----------------------- | -------------------------------- | ------- | | `shim` | `/usr/lib/shim/fbx64.efi.signed` | The fallback EFI application if the GNU EFI Bootloader fails to find any options or bootloader order | | `shim` | `/usr/lib/shim/mmx64.efi.signed` | The signed MOK Manager EFI application copied to `/boot/efi/EFI/{grub,ubuntu}/mmx64.efi` | | `shim` | `/usr/lib/shim/shimx64.efi` | The signed - by Microsoft - EFI Bootloader (aka SecureBoot) copied to `/boot/efi/EFI/{grub,ubuntu}/shimx64.efi` | | `grub-efi-amd64-signed` | `/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed` | The grubx64.efi EFI application copied to `/boot/efi/EFI/{grub,ubuntu}/grubx64.efi` | ## Troubleshooting ### Setting EFI Boot Order The `efibootmgr` command can be used to display and set the boot order based on what's configured as possible boot options. Every option is given a numerical designation, setting the boot order is just indicating their logical order to try. First, display the current boot order by passing no options to the command: ``` # efibootmgr BootCurrent: 0002 BootOrder: 0003,0000,0001,0002 Boot0000* EFI DVD/CDROM Boot0001* EFI Hard Drive Boot0002* EFI Internal Shell Boot0003* Ubuntu ``` Notice in the above example, the boot order is set to the EFI internal shell and that was what we booted into (notice BootCurrent); our desire is to reset this boot order to try the OS (Ubuntu) first, then the generic hard drive, then the DVD, then finally the shell last. We specify those options to the command in order desired, and it will display the result automatically: ``` # efibootmgr --bootorder 0003,0001,0000,0002 BootCurrent: 0002 BootOrder: 0003,0001,0000,0002 Boot0000* EFI DVD/CDROM Boot0001* EFI Hard Drive Boot0002* EFI Internal Shell Boot0003* Ubuntu ``` After rebooting the device it should have gone straight to option 0003 (Ubuntu), and BootCurrent should reflect that choice: ``` # efibootmgr BootCurrent: 0003 BootOrder: 0003,0001,0000,0002 Boot0000* EFI DVD/CDROM Boot0001* EFI Hard Drive Boot0002* EFI Internal Shell Boot0003* Ubuntu ``` See `man efibootmgr` for additional options such as activating and deactivating choices. ### Add EFI Boot Option If the device seems to boot to the EFI shell or disk incorrectly, it's possible the OS is missing an entry in the EFI variables to boot from to the OS. In shit case, first examine the bootable options to observe that there's no entry for the OS (GRUB, mainly) present: ``` # efibootmgr BootCurrent: 0002 BootOrder: 0001,0000,0002 Boot0000* EFI DVD/CDROM Boot0001* EFI Hard Drive Boot0002* EFI Internal Shell ``` There should be an additional entry "Ubuntu" or "Red Hat" or "CentOS" (etc.) pointing directly at the shim EFI. To add / correct the server, add the entry using `efibootmgr` – the method is almost identical for all the distros, just varies by the vendor's name in the path. ``` ## RHEL efibootmgr --create --gpt \ --disk /dev/sda --part 1 --write-signature \ --label "Red Hat Enterprise Linux" \ --loader /EFI/redhat/shim.efi ## CentOS efibootmgr --create --gpt \ --disk /dev/sda --part 1 --write-signature \ --label "CentOS Linux" \ --loader /EFI/centos/shim.efi ## Ubuntu efibootmgr --create --gpt \ --disk /dev/sda --part 1 --write-signature \ --label "Ubuntu Linux" \ --loader /EFI/ubuntu/shimx64.efi ``` After adding the new entry, you must set the boot order for the new entry to boot first. Follow the Setting EFI Boot Order section above to now choose your OS as the default first choice to boot. ## References - https://www.intel.com/content/www/us/en/architecture-and-technology/unified-extensible-firmware-interface/efi-homepage-general-technology.html - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/installation_guide/s2-grub-whatis-booting-uefi - https://access.redhat.com/support/cases/#/case/01907436 - https://help.ubuntu.com/community/UEFI