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.

Figure 2: The UEFI shell is launched.

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).

Figure 3: The Hangman word-guessing game with UEFI control.

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.

Buy this article as PDF

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

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
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

News