Using UEFI in QEMU/KVM (AArch64 + AArch32)

This page provides instructions for building and running the port of Tianocore/EDK2 to a QEMU/KVM based 'virt' platform in both ARM and AArch64 mode.


  • Supports the QEMU/arm 'mach-virt' machine type both in AArch64 and AArch32 execution modes
  • Peripherals are discovered dynamically using a flattened device tree image passed by QEMU at the base of RAM (0x4000_0000). This includes the serial UART, RTC, interrupt controller etc
  • Supports reset and poweroff through PSCI
  • Supports virtio block, network and SCSI devices
  • Supports non-volatile variable storage through emulated NOR flash
  • Supports reset, poweroff and RTC access through UEFI Runtime Services
  • Supports UEFI Secure Boot


To run this UEFI firmware, you will need QEMU version 2.2 or later built for aarch64-softmmu (or arm-softmmu).

To run it in accelerated mode, i.e., under an arm64 or ARM Linux kernel with KVM, you will need a fairly recent host kernel (v3.19 or later).

Note that if your [emulated] hardware has a GICv3, it is essential that your host device tree correctly identifies the GIC as a v3, or KVM will kick it into a mode that is incompatible with the GICv3 handling in UEFI running inside the guest.

Building the firmware

Source can be found on the Tianocore EDK2 GitHub

Prebuilt binaries can be found here.

Before building from the cloned repository the first time, it is necessary to do a

make -C BaseTools

Prepare the environment:

export GCC49_AARCH64_PREFIX=aarch64-linux-gnu-
export GCC49_ARM_PREFIX=arm-linux-gnueabihf-

Then, the code can be built using

build -a <architecture> -t GCC49 -p ArmVirtPkg/ArmVirtQemu.dsc

where <architecture> is either ARM or AARCH64

After the build completes successfully, the firmware image can be found in the file


Running the firmware

To run the firmware in non-accelerated mode (e.g., on a x86 box), invoke QEMU in the following way:

qemu-system-aarch64 \
    -m 1024 \
    -cpu cortex-a57 \
    -M virt \
    -bios Build/ArmVirtQemu-<arch>/DEBUG_GCC49/FV/QEMU_EFI.fd \
    -serial stdio

(replace cortex-a57 with cortex-a15 for 32-bit ARM)

This should result in the UEFI shell being launched, unless you hit any key to enter the menu.

Booting Linux

It is possible to boot directly into Linux from UEFI, without an intermediate bootloader. For instance, using this image, which contains a separate FAT /boot partition containing the kernel, we can boot Linux by following these steps:

  • decompress the image:
    •   zcat vexpress64-openembedded_minimal-armv8-gcc-4.9_20140823-686.img.gz > vexpress64-oe.img
  • invoke qemu as above, but add the following command line arguments:

    •   -drive if=none,file=vexpress64-oe.img,id=hd0 
        -device virtio-blk-device,drive=hd0

The disk image is preconfigured to boot a file called 'Image' from the first partition of the first virtio block device (by means of a startup.nsh UEFI shell script), so it should boot the kernel after the countdown expires. To boot manually, enter the shell while hitting Escape (to prevent startup.nsh from being executed) and enter the following command:

Image root=/dev/vda2 console=ttyAMA0,38400n8 earlycon=pl011,0x9000000

Using persistent UEFI variables

It is possible to make UEFI remember the environment variables that are set by the boot configuration menus or by efibootmgr under Linux. To do so, we need to pass two NOR images instead of one, which requires the use of -pflash rather than -bios. However, -pflash requires the NOR images to be exactly 64 MB in size, so we need to prepare those images first.

  • Create flash0.img containing the UEFI image:

    •   cat QEMU_EFI.fd /dev/zero | dd iflag=fullblock bs=1M count=64 of=flash0.img
  • Create a blank flash1.img:

    •   dd if=/dev/zero of=flash1.img bs=1M count=64
  • Invoke QEMU as above, but replace -bios .../QEMU_EFI.fd with:

    •   -pflash flash0.img -pflash flash1.img

Now, any changes made in the BDS boot menu will persist and be stored in flash1.img

Running under KVM

When running the above on a KVM-enabled AArch64 or ARM system using a KVM-enabled QEMU, replace -cpu cortex-aXX with:

  • -cpu host -enable-kvm

UEFI Secure Boot

This firmware can be built with support for UEFI Secure Boot.

First, follow the instructions in CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt regarding how to download and prepare the OpenSSL sources, since these are not included in the Tianocore tree.

Then, build the firmware image as outlined above, while adding the SECURE_BOOT_ENABLE option:

build -a <arch> -t GCC49 -p ArmVirtPkg/ArmVirtQemu.dsc \

The resulting firmware can be invoked as described in the preceding sections. Using persistent UEFI variables is recommended, since enrolled certificates are stored as variables internally.

How to configure UEFI Secure Boot and sign boot images is beyond the scope of this guide, but works the same way as it does on other virtual platforms like OVMF.

LEG/UEFIforQEMU (last modified 2017-02-02 15:58:15)