Custom UEFI boot logo in QEMU/KVM on NixOS

Collin Dewey

03/20/2025

TianoCore

When launching virtual machines on my computer, I am greeted with the TianoCore logo in the middle of the black boot screen. TianoCore EDK II is a reference implementation of UEFI firmware. It’s what KVM uses for its UEFI implementation. Booting a Windows VM results in this logo staying on the screen for the duration that Windows takes to load to get to the lock screen. This logo doesn’t look very cool though.


TianoCore Logo

I wanted to change that logo to have a slightly nicer thing to look at for 10-20 seconds while Windows boots. Looking up how to change the logo with KVM’s UEFI, I am brought to an article by Gary Hawkins from 2013. Their approach involves modifying the EDK II source code for its sample OVMF firmware, replacing the logo in the source. In NixOS, patching this file is relatively easy by using an overlay included in your Nix configuration. This overlay copies a local Logo.bmp over the one located within the package in the postPatch phase, and Nix does the work of compiling it.

nixpkgs.overlays = [
  (final: prev: {
    OVMF = prev.OVMF.overrideAttrs (old: {
      postPatch = (old.postPatch or "") + ''
        cp ${./Logo.bmp} ./MdeModulePkg/Logo/Logo.bmp
      '';
    });
  })
];

To setup an image for the logo, it needs to be a BMP. Once you have a suitable image to put in the center of the screen, convert your image with ImageMagick.

magick convert Logo.png -background black -alpha remove -define bmp:format=bmp3 Logo.bmp

Put your Logo.bmp along with your Nix configuration files and rebuild.


Using custom OVMF firmware

When I make a VM with virt-manager, by default it uses the edk2-x86_64-secure-code.fd that was included along with QEMU.

<os firmware="efi">
  <type arch="x86_64" machine="pc-q35-9.2">hvm</type>
  <firmware>
    <feature enabled="no" name="enrolled-keys"/>
    <feature enabled="yes" name="secure-boot"/>
  </firmware>
  <loader readonly="yes" secure="yes" type="pflash" format="raw">/nix/store/xxxxxx-qemu-9.2.2/share/qemu/edk2-x86_64-secure-code.fd</loader>
  <nvram template="/nix/store/xxxxxx-qemu-9.2.2/share/qemu/edk2-i386-vars.fd" templateFormat="raw" format="raw">/var/lib/libvirt/qemu/nvram/virt_VARS.fd</nvram>
  <boot dev="cdrom"/>
</os>

The OS block can be replaced with a block similar to the below, replacing the /nix/store paths with /run/libvirt/nix-ovmf/OVMF_CODE.fd and /run/libvirt/nix-ovmf/OVMF_VARS.fd.

<os>
  <type arch="x86_64" machine="pc-q35-9.2">hvm</type>
  <loader readonly="yes" secure="yes" type="pflash" format="raw">/run/libvirt/nix-ovmf/OVMF_CODE.fd</loader>
  <nvram template="/run/libvirt/nix-ovmf/OVMF_VARS.fd" templateFormat="raw" format="raw">/var/lib/libvirt/qemu/nvram/virt_VARS.fd</nvram>
  <boot dev="cdrom"/>
</os>

After then, you should be able to see your custom logo in place of the TianoCore default image.