Customizing the UEFI boot process

Smart Startup

Article from Issue 206/2018
Author(s): , Author(s):

The traditional BIOS dates back decades and has not been able to keep up with the rapid development of PCs and laptops. Its powerful successor UEFI takes over its tasks and provides more features, more convenience, and better security.

Since 1981, PCs have booted with the help of the Basic Input/Output System (BIOS). Over the years, different manufacturers have continued to expand the BIOS firmware system, but even after all this time, the BIOS system is difficult to adjust and still does not support 64-bit operation.

Back in the late 1992, Intel launched a new initiative to replace the venerable BIOS system with a 64-bit alternative. This Extensible Firmware Interface (EFI) initiative became the Unified EFI (UEFI) Forum in 2005. In addition to Intel, AMD, Microsoft, HP, and other prominent vendors contributed to the UEFI project.

UEFI describes the interface between a computer's firmware and operating system. Like BIOS, the UEFI implementation initializes the hardware components to prepare the launch of the operating system. However, UEFI natively supports 64-bit architectures, enables graphical user interfaces, and can protect against malicious software by only allowing signed operating systems (a feature that has come to be known as Secure Boot).

If you are using a Linux system that is preconfigured with support for UEFI and Secure Boot, you don't have to think about it very much unless you need to customize or troubleshoot the boot process. But if you want to dig deeper, you will find that UEFI is quite versatile and powerful. This article takes a closer look at the UEFI boot process and shows how you can use UEFI to add a custom application that runs independently of the operating system.

Boot Phases

UEFI firmware is modular and extensible. When it wakes up, the firmware runs through various stages in a strict chronological order (shown in Figure 1). The first phase is known as the Security (SEC) phase. However, the name is unfortunate because very few security-relevant actions occur in this first phase – for instance, the UEFI firmware does not use this phase to check signatures. Essentially, the SEC phase initializes the CPU with hardware-specific code. The CPU loads the code directly from flash memory. RAM is not yet available at this time. Instead, the UEFI firmware uses the temporary memory of the CPU cache as RAM. The SEC phase transfers phase size and location of this temporary storage, as well as optional information about the CPU, to the Pre-EFI Initialization (PEI) phase.

Figure 1: The UEFI boot process runs through a series of phases.

The PEI phase initializes the main memory, as well as hardware components that are required for the next phases. PEI Modules (PEIMs) provide APIs (PEIM-to-PEIM interface, PPI). The PEIM dispatcher is responsible for loading and running the PEIMs. It investigates the PEIMs' dependencies, loads them into the now available main memory, and runs them in a specific order.

In addition to initializing basic hardware components, the UEFI firmware also reads a structured collection of codes and data, known as the firmware volume location. This data is typically stored in flash memory and includes device drivers for the next phase. After the dispatcher has run most of the necessary PEIMs, it finally looks for the Driver Execution Environment (DXE) initial program load (IPL) PEIM. This last PEIM then transfers the execution to the following DXE phase.

In the DXE phase, most of the necessary system initialization then follows. Like the PEI phase, the DXE phase also has a dispatcher, which loads DXE drivers from the firmware volume location and runs them in the desired order. The DXE drivers initialize all required hardware components and register or use protocols.

Protocols provide the text output to the console or access to the PCI devices. If a protocol is only available before the operating system launches, it is known as a boot service. A protocol that you can access them while the operating system is running is called a run-time service.

After the dispatcher has loaded all drivers, it continues with the Boot Device Selection (BDS) phase. The BDS phase runs the UEFI Boot Manager. NVRAM variables tell the Boot Manager which UEFI applications must be launched. The operating system can influence these variables through a run-time service and determine the UEFI applications that must run. The hardware manufacturers frequently provide some UEFI applications, such as diagnostics or recovery applications. You can add additional applications yourself and integrate them in the boot process.

The OS bootloader is a special application. The system typically loads it and launches it from the EFI system partition (/boot/efi). By launching the OS bootloader, the boot process transitions to the Transient System Load (TSL) phase. If the system uses Secure Boot, its signature would be tested in this phase. Unsigned code will not run. The TSL phase ends on calling the ExitBootServices() function. This call thoroughly cleans up the memory and only leaves the specially marked interfaces in the memory that need to be available at operating system run time.

After calling ExitBootServices(), the system is in the Run Time (RT) phase; the operating system is running and can in turn access the UEFI run-time services. After the RT phase, the system enters the After Life (AL) phase with the termination of the operating system. This is intended for an orderly shutdown. However, it is hardly used.

UEFI Run-Time Services and Variables

UEFI run-time services are UEFI functions that can be used at operating system run time. For this purpose, a UEFI driver registers as a run-time service and creates an entry in the run-time services table. During the boot process, the operating system is given this table. The table gives the operating system access to the real-time clock; the OS can trigger a platform reset, access variables in the NVRAM, or initiate a firmware update.

While most run-time services are only accessible to kernel drives on a Linux system, access to the NVRAM variables and the firmware update function are exported to userspace by the Linux kernel. The Linux kernel makes UEFI variables accessible in userspace via the UEFI variable filesystem (efivarfs). Linux distributions launched by UEFI integrate the filesystem under /sys/firmware/efi/efivars.

You can list all available variables via:

ls /sys/firmware/efi/efivars

You can read UEFI variables like normal files. The following command outputs the contents of a variable:

cat /sys/firmware/efi/efivars/variable_name

on the console. However, the stored information is available in a machine-readable format; the output of the cat command is often fairly cryptic.

You can write or delete these variables as you would a normal file. But deleting a variable can be fraught with danger. Previously, a rm-rf / would result in not just all the files on the hard drive being deleted but all UEFI variables too. However, some buggy UEFI implementations expected certain variables. If these variables were deleted, the computer no longer launched and you had to send the motherboard to be repaired.

Current Linux kernels therefore protect most of the variables with the immutable flag:

lsattr PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8c
----i-------------- PKDefault-8be4df61-93ca-11d2-aa0d-00e098032b8

Thus, accidental deletion or modification is ruled out. In practice, you cannot directly access the variable via commands such as cat. Instead, you need to use special programs such as efibootmgr that let you edit the group of boot variables.

The BDS phase is controlled by the boot variables. A variable starting with Boot000 represents an entry in the UEFI Boot Manager. The value of the variable specifies the location of a UEFI application that is bootable during the BDS phase. The BootOrder-GUID variable determines the order in which the applications must be launched. The efibootmgr program manages these variables at the command line. The command in Listing 1 displays the current configuration of the BDS phase.

Listing 1

BDS Phase Configuration


Listing 1 shows two entries. The entry known as debian is right at the front in the boot order and is therefore run first. The entry points to the EFI system partition (/boot/efi), on which GRUB is stored. The system first runs the UEFI implementation of GRUB in the BDS phase. GRUB, in turn, launches the Linux kernel. You can add new boot variables or change the boot order with the efibootmgr command.

While the boot variables are freely adjustable, write access to other variables is restricted. They include, among others, the PK, KEK, DB, and DBX variables. These variables store the public keys for signature verification within the scope of Secure Boot.

If an attacker can change these variables, they can also bypass or switch off Secure Boot. Therefore, only signed data can be stored in these variables. The UEFI implementation verifies the signature of the transferred public key and only allows the write operation if the signature is trustworthy.

Update Capsule

Another interesting UEFI run-time service bears the name Update Capsule. The operating system can use this service to transfer data blocks to the UEFI firmware. The operating system stores the data in memory and shares the location with firmware via the Update Capsule service. A system reset is then triggered. The computer restarts. UEFI now accesses the provisioned data block.

The service is used primarily to run updates of the UEFI firmware. The advantage of this procedure is that the firmware can handle the actual update process. You don't need any proprietary tools, which are usually only available on Windows.

The standardized UEFI interface makes firmware updates independent of the operating system. For example, Microsoft uses this process to provision surface tablets with new firmware via Windows Update. Apple also uses this process for certain MacBooks. At present, Linux users can only use the update function in conjunction with a few systems. In addition to Microsoft and Apple, Dell is the only big manufacturer that offers firmware updates in the Update Capsule format.

Like the UEFI variables, the Linux kernel exports the update interface to the filesystem. The /sys/firmware/efi/esrt directory contains the EFI System Resource Table (ESRT). The kernel generates an input for each device that can be updated via the Update Capsule interface. The fwupdate tool lists these devices. The tool is installed using:

sudo apt-get install fwupdate

The command generates a list of all Update Capsule-capable devices in the system:

fwupdate --list

If there is an Update Capsule-compatible firmware for the devices listed, it can be installed as follows:

fwupdate --apply=guid-of-hardware firmware.cap

Unfortunately, as previously mentioned, only a few manufacturers support this functionality to date. However, it shows what advantages the standardized UEFI interface has over proprietary BIOS implementations.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Linux Boot Process

    If you want to troubleshoot startup issues, you need a clear understanding of how Linux boots.

  • The State of Secure Boot

    Opinions differ on the UEFI boot security system, but one thing is certain: Secure Boot is here to stay. We thought it was time to ask, "How hard is it to boot a popular Linux distribution in a UEFI Secure Boot environment?"

  • UEFI Developments

    Windows secure boot controversy gets uglier.

  • UEFI Boot Fix

    A new universal workaround will keep Linux booting on the next generation of UEFI-enabled personal computers.

  • UEFI and Secure Boot

    The coming Windows 8 implementation of UEFI with Secure Boot adds an extra layer of complexity for some Linux users. We look at the problem and two solutions from Fedora and Canonical.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More