1. Overview

UEFI (Unified Extensible Firmware Interface) has become the standard for modern computer firmware. It has many advantages over the traditional BIOS:

  • faster boot times
  • support for large storage
  • enhanced security features

Emulating UEFI on virtual machines can be helpful for development, testing, and learning purposes.

In this tutorial, we’ll see the steps to boot from UEFI in QEMU. Also, we cover the essentials, from using Open Virtual Machine Firmware (OVMF) to various ways of booting UEFI in QEMU.

Notably, we use a Ubuntu ISO file for the purposes of this tutorial.

2. Storage Image UEFI Boot Requirements

To boot a disk image in UEFI mode, we require two main components:

  • UEFI-supported image containing the operating system (OS) files and partition table formatted for UEFI systems
  • OVMF firmware files to provide the necessary UEFI firmware for booting the storage image

The path of firmware files usually varies depending on the Linux distribution. In general, we can find these files at /usr/share/OVMF/OVMF_CODE.fd and /usr/share/OVMF/OVMF_VARS.fd.

3. Open Virtual Machine Firmware (OVMF)

OVMF is used to enable UEFI firmware support in QEMU and KVM-based VMs. It’s part of the Intel EFI Development Kit II (edk2) project.

Moreover, to use OVMF, we can install it with apt:

$ sudo apt install ovmf

As a matter of fact, we can also build it from the source.

Either way, we should have support for OVMF before continuing.

4. Using QEMU CLI

QEMU VMs can be controlled via the command-line interface (CLI). In this section, we check the virt-install and qemu-system-x86_64 tools as possible solutions to UEFI booting.

4.1. Using virt-install

virt-install is a command-line tool for creating new virtual machines using the libvirt hypervisor. It provides a simple way to set up a VM with a UEFI setup.

Let’s create a UEFI-enabled virtual machine with the Ubuntu ISO file:

$ sudo virt-install  
  --name Ubuntu_Uefi \
  --memory RAM_in_MB \
  --arch x86_64 \
  --boot loader=/usr/share/OVMF/OVMF_CODE.fd \
  --cdrom /path/to/the/iso/file \
  --disk /path/to/disk.img,size=DISK_SIZE \
  --virt-type=kvm \
  --network=default,model=virtio \
  --vcpu=1 \
  --check all=off
  --virt-type qemu

We replace the placeholders with pre-defined values:

  • –name: name for the virtual machine (e.g., Ubuntu_Uefi)
  • –memory: amount of RAM for the virtual machine (e.g., –ram 4096 for 4GB)
  • –arch: CPU architecture (x86_64 for most modern systems)
  • –boot loader…: enables UEFI boot mode with custom OVMF binaries
  • –cdrom: path to our Ubuntu ISO image
  • –disk: path to the new virtual disk image file
  • size: size of the new virtual disk image (adjust in Gigabytes)
  • –virt-type: set virtualization type
  • –network…: connect to default virtual network using virtio network device model
  • —**vcpu: number of virtual CPUs for the VM
  • –check all: does some validation checks before proceeding with the installation
  • –virt-type qemu: uses QEMU as the hypervisor

In fact, we can just use –boot uefi to boot from UEFI. That means we can bypass the custom OVMF_CODE.fd file.

After that, we continue the VM installation inside the virt-viewer.

4.2. Using QEMU Emulator (qemu-system-x86_64)

The QEMU emulator (qemu-system-x86_64) directly manages virtual machines with various options.

Let’s first create a disk image file to store the VM data:

$ qemu-img create -f qcow2 disk.img 15G
Formatting 'disk.img', fmt=qcow2 ...

As a result, we can see an image file, disk.img, in the current directory. Also, this file has a size of 15 GB and is formatted as qcow2.

In the next step, we launch the VM:

$ sudo qemu-system-x86_64 \
  -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \
  -drive if=pflash,format=raw,file=/usr/share/OVMF/OVMF_VARS.fd \
  -drive file=/path/to/the/file/disk.img/,format=qcow2 \ 
  -cdrom /path/to/the/iso/file \
  -m 4098

Here, we’re using the qemu-system-x86_64 command. Basically, this is the QEMU system emulator for the x86_64 architecture.

Moreover, we’ve got three drive options here.

Let’s break down the first drive option:

  • -drive: adds a drive to the virtual machine with some options
  • if=pflash: specifies a pflash interface
  • format=raw: means that the file format is raw
  • readonly=on: makes the drive read-only since OVMF_CODE.fd file contains static UEFI code
  • file=…: path to the OVMF_CODE.fd file, which contains the UEFI firmware code

The second drive option is also the same as the last one but for the OVMF_VARS.fd file. In particular, this file contains the variable store for the UEFI firmware. Also, OVMF_VARS.fd should be read and write enabled, as it holds the UEFI settings and variables that may change.

Furthermore, we’ve got the third drive option with two sub-options:

  • file=…: sets the path to the disk image file, which in our case is disk.img
  • format=qcow2: specifies the format of the disk image as qcow2

The above values add the main storage image for the virtual machine.

Then, the -cdrom option sets the path to the installation media.

Finally, -m 2048 specifies that the virtual machine should have 2048 MB (or 2 GB) of RAM.

Thus, the above command starts a QEMU virtual machine with UEFI support using the OVMF firmware.

5. Using QEMU Frontends

QEMU frontends come with a graphical interface for managing virtual machines. There are two popular options:

Let’s go through each method one by one.

5.1. Using AQEMU

AQEMU is a graphical user interface (GUI) for QEMU. It uses the Qt5 framework.

Let’s install AQEMU using apt:

$ sudo apt install aqemu

Now, we start AQEMU from the application menu.

Further, we create a new virtual machine using the icon on the left panel:

Aqemu New VM

In the New Virtual Machine Wizard, we select the typical configuration mode:

Typical configuration mode

Next, we choose the template option and OS type as Linux 2.6:

Selecting template

Then, we use the KVM (Recommended) as the Machine Accelerator:

Selecting accelerator

Further, we give the VM a name, say AQEMU-VM:

Setting VM name

For the VM hard disk, we use a size of 20.0 GB:

Setting disk size

In this case, we use the default options for the Network type:

Configuring VM network

Finally, we complete the setup process:

Finishing VM setup

We can now see and change all VM details on the right panel of the main window.

Here, we select the VM tab and go to the Advanced option:

VM Advanced options

Now, we enter the custom QEMU command line arguments to use the UEFI firmware:

QEMU Command Line arguments

Next, we go to the M**edia tab and add a CD-ROM device under the Add Devices section:

Adding ISO file with CD-ROM

In this case, we select the Ubuntu ISO image.

Finally, we apply the changes and start the VM. Thus, we can now boot the UEFI image in AQEMU.

5.2. Using Virtual Machine Manager

Virtual Machine Manager (virt-manager) is another powerful GUI tool for managing virtual machines.

To install virt-manager, we again use apt:

$ sudo apt install virt-manager

Next, we launch virt-manager and create a new virtual machine using the Local install media option:

Creating a new VM

Then, we point to the path containing the Ubuntu ISO file:

Selecting the ISO file

Moving on, we set the Memory and CPU options for the VM:

Setting RAM size and CPU

In the next step, we enable and set the storage options as before:

Adding storage to VM

Then, we mark the option Customize configuration before installation:

VM configuration Review

In the Overview section, *we set the firmware to *U**EFI and apply the changes**:

Setting Firmware to UEFI

As a result, we can now start the OS installation.

6. Conclusion

In this article, we learned about booting from UEFI in QEMU.

Initially, we covered the purpose of Open Virtual Machine Firmware (OVMF). Then, we used the QEMU command-line tools virt-install and the QEMU emulator. Finally, we used QEMU frontends such as AQEMU and Virtual Machine Manager.