Customizing the UEFI boot process
Custom Code
The EFI Developer Kit II (EDK II) is used for developing UEFI applications. It is the current reference implementation of the UEFI specification and is used by many manufacturers as the basis for their own firmware. To avoid developers having to constantly reboot their computers to test their own applications, it makes sense to work in Qemu. EDK II includes everything you need to generate complete UEFI firmware and relaunch under Qemu.
First, you need to install some dependencies. On Ubuntu 4.16, use the following command:
sudo apt-get install build-essential uuid-dev iasl git gcc-5 nasm
The easiest way to pick up the last stable release of EDK II is via GitHub:
mkdir ~/src cd ~/src git clone https://github.com/tianocore/edk2.git vUDK2017
After downloading, first compile the base tools:
cd ~/src/vUDK2017 make -C BaseTools
If everything worked, the EDK is ready for use. The source code is organized in packages. The MdeModulePkg
and MdePkg
packages are important because they implement the actual UEFI Specification. The code is largely architecture independent. To generate firmware capable of running on a specific platform, the firmware requires platform-specific code. The EDK provides this code for Qemu. The Ovmf package internally builds on the Mde packages and adds the Qemu specific parts.
In order for the Ovmf package to create an EDK, you need to edit the ~/src/vUDK2017/Conf/target.txt
file. Specify the Ovmf package as the ACTIVE_PLATFORM
:
ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
In addition, you need to adapt the architecture and the compiler tool chain you will be using. On an x64 Ubuntu 04.16 system, use the following values:
TARGET_ARCH= X64 TOOL_CHAIN_TAG= GCC5
Once the target platform is set, launch the first build process:
source edksetup.sh build
The build takes a few minutes and stores the complete firmware in the ~/src/vUDK2017/Build/OvmfX64/DEBUG_GCC5/FV
directory.
To test the UEFI firmware using Qemu, copy the required firmware files into a new directory (Listing 2). Using the following command, you can launch a virtual machine and run the firmware:
Qemu-system-x86_64 -drive if=pflash,format=raw,file=OVMF_CODE.fd -drive if=pflash,format=raw,file=OVMF_VARS.fd
Listing 2
Copying Firmware Files
If Qemu displays a logo with the words TianoCore
for a short time and then launches the UEFI shell (Figure 2), the whole process was successful.
For the first attempts with your own UEFI applications, you can use the Hello World application from the MdeModule
as a template. The correct file can be found in MdeModulePkg/Application/HelloWorld/HelloWorld.c
. This file, which is shown in Listing 3, was expanded and now implements a simple variant of the Hangman game. The user has to guess the word penguin
and thus quit the application.
Listing 3
Hello World!
The entry point of the application is the UefiMain
function (Line 8). UefiMain
has two transfer arguments. ImageHandle
is a handle for the process itself and not interesting for the Hello World application. However, the second argument SystemTable
is a central data structure of the UEFI environment. SystemTable
now provides the application with access to protocols that have been previously registered in the DXE phase.
In Line 21, the program uses the Simple Text Output Protocol via SystemTable
. The protocol has a function known as ClearScreeen
. As the name suggests, this call clears the output console. This is followed by some output implemented by the print function. Under the hood, the print function also uses the Simple Text Output protocol. Line 32 relies on the WaitForEvent
service. With its help, the program waits for the occurrence of certain events, in this case for a key press (WaitForKey
). After the event occurs, the ReadKeyStroke
function returns the pressed key.
The following for
loop checks whether the character matches one of the expected characters. The entire process is repeated by the do-while
loop until the user has guessed all the letters correctly. The program then outputs the word you are looking for and then waits for a subsequent key press before it quits.
You have to extend the Ovmf package in order for the Hangman program to be included in the next build. In the ~/src/vUDK2017/OvmfPkg/OvmfPkgX64.dsc
file, add the [Components]
section and a reference to the Hello World application:
[Components] MdeModulePkg/Application/HelloWorld/HelloWorld.inf
The HelloWorld.inf
file describes the application and instructs the EDK to automatically generate makefiles. In the base directory of the EDK, launch the build process for the Hello World application:
source edksetup.sh build
The build stored the generated UEFI binary HelloWorld.efi
in the ~/src/Build/OvmfX64/DEBUG_GCC5/X64
directory. To test the application, copy it to the efibin
directory and relaunch Qemu:
cd ~/efibin cp ~/src/Build/OvmfX64/DEBUG_GCC5/X64/HelloWorld.efi .
When launching, extend the command to launch the Qemu system by the hda
parameter. This parameter integrates the efibin
directory into the virtual machine as a FAT-formatted hard drive. The full command is:
Qemu-system-x86_64 -drive if=pflash,format=raw,file=OVMF_CODE.fd -drive if=pflash,format=raw,file=OVMF_VARS.fd -hda fat:~/efibin
UEFI directly supports the FAT filesystem and therefore has access to the Hello World application. After launching the UEFI Shell, enter Hello World
to launch the program (Figure 3).
After completing the application development, you can run the binary file generated in the UEFI environment of the motherboard. For this purpose, simply copy them to the EFI system partition of your computer:
sudo cp ~/efibin/HelloWorld.efi /boot/efi/
Similar to the Qemu environment, you can manually launch the application in the UEFI implementation of the motherboard using the UEFI Shell. After resetting the computer, you then have to press one of the function keys to interrupt the normal boot process and instead launch the UEFI Shell. Which key has to be pressed depends on the UEFI implementation of the motherboard. Once you are in the UEFI Shell, you can simply call the application by typing HelloWorld
.
Alternatively, you could set up an automatic launch of the application. You must configure the UEFI Boot Manager via the UEFI variables. The easiest way to do this is with the efibootmgr
program. The program generates new boot variables in the efivar
filesystem and thus an entry in the UEFI Boot Manager.
However, before this step, you should ensure that a recovery CD is ready, with which you can repair a potential misconfiguration. To generate a new entry, transfer the create
argument to the Efibootmgr. A label gives the entry an intuitive name; the loader
parameter displays the path to the UEFI application:
efibootmgr --create --label "Hangman" --loader HelloWorld.efi
If successful, the system responds with:
BootCurrent: 0000 Timeout: 2 seconds BootOrder: 0000.0001 Boot0000* debian Boot0001* Hangman
Currently, the boot sequence still defines that the entry with the debian
label will start. The efibootmgr --bootnext 0001
command changes this order for the next boot to the entry with the number 0001. If you now reboot the computer, the UEFI firmware runs the Hello World application once only.
Conclusion
This example basically shows how to develop and run UEFI programs. You are not restricted to simple text input and output. UEFI allows you to introduce a graphical user interface, access a TCP/IP network, or access a USB stick. The versatile UEFI environment lets you run even complex applications independently of the operating system.
« Previous 1 2
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
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.
News
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.
-
Gnome OS Transitioning Toward a General-Purpose Distro
If you're looking for the perfectly vanilla take on the Gnome desktop, Gnome OS might be for you.