[libvirt-users] [Fwd: UEFI NVRAM variables]

Laszlo Ersek lersek at redhat.com
Thu Jul 13 11:26:46 UTC 2017


Hi,

thank you, Andrea, for the forward.

On 07/13/17 10:19, Andrea Bolognani wrote:
> -------- Forwarded Message --------
> From: Thomas Meyer <thomas at m3y3r.de>
> To: libvirt-users at redhat.com
> Subject: [libvirt-users] UEFI NVRAM variables
> Date: Wed, 12 Jul 2017 07:49:43 +0200
> 
>> Hi,
>>
>> how do I set the BootOrder variable in an NVRAM file for UEFI boot?

This is one of the most frequently asked questions about OVMF.

Short version:
- alternative 1: use neither <boot dev="..."/> nor <boot index="..."/>
in your domain XML, and manage the BootOrder and Boot#### variables
entirely within the guest (using the OVMF Setup TUI and/or the
efibootmgr utility).
- alternative 2: use <boot index="..."/> in your domain XML, and it will
mostly do what you want.

Mid-size version:

* Never use "-boot order=x,y,z" with OVMF, on the QEMU command line,
because the guest-visible effects of this QEMU option are fully useless
to UEFI guest firmware. For more details, please refer to
<https://bugzilla.redhat.com/show_bug.cgi?id=1323085#c10>.

Translating the above to libvirt, never use <boot dev='...'/> elements
in your domain XML with UEFI guest firmware. (They are also discouraged
by the libvirt documentation, for their non-unique meaning.)

* The "-device xxx,bootindex=N" properties on the QEMU command line are
usable and useful to UEFI guest firmware. (This is what libvirt's <boot
order='N'/> per-device elements map to, which are also what the libvirt
docs recommend.)

However, the expressive power of these properties is still lesser than
the expressive power of the UEFI boot options, therefore the best that
OVMF can do here is a kind of auto-generation of all possible boot
options, and filtering and reordering them based on translation and
prefix-matching.

For that, the long version: please refer to the OVMF whitepaper from a
few years back, where I described this algorithm in excruciating detail:

http://www.linux-kvm.org/downloads/lersek/ovmf-whitepaper-c770f8c.txt

Search it for "Platform-specific boot policy".

>> Is there a way to configure a domain with the bios qemu option instead of pflash?

If you want to boot a guest with OVMF as firmware, but map the firmware
as ROM, not as pflash, you can do it. For that, you have to use the
unified OVMF image (called "OVMF.fd" most commonly), not the split image
(called "OVMF_CODE.fd" and other variants). The <loader> element should
look like:

  <loader>/usr/share/OVMF/OVMF.fd</loader>

and the <nvram> element should not be present.

This will map to "-bios OVMF.fd" on the QEMU command line.

Be *strongly* warned though that by this, you are throwing away
persistent non-volatile variables, and that the fake variable support
that OVMF falls back to does not -- cannot -- conform to the UEFI spec.
You will encounter obscure mis-behavior with variables. (One of the
obvious glitches will be that Secure Boot settings will not survive a
reboot.)

>>
>> Are there a tool available to manipulate the UEFI variables from the outside?

No, there isn't, and as far as it's up to me, there won't be. (This is
another of the most frequently asked questions.)

The reason for this is that the representation of the variable store on
the host filesystem (in /var/lib/libvirt/qemu/nvram/<guest>_VARS.fd) is
the functional composition of three layers in the edk2 driver stack:

- platform-specific pflash driver / layout
- generic fault tolerant write driver (implementing a kind of journaled
  system, where you can "lose power" in the middle of a write operation,
  and your varstore won't be corrupted)
- generic variable driver

None of these are standardized in UEFI, and even restricting ourselves
to edk2 (the reference implementation of PI/UEFI), only the last two
layers are documented in Intel whitepapers. Regarding examples for the
first layer, OVMF itself can be built with two distinct (and
incompatible) variable store layouts, and the ArmVirtQemu varstore
layout is again different.

In other words, a host-side utility to parse and modify these files
would have to reimplement the functionality of the above three layers,
deal with, and clean up, interrupted writes (see the fault tolerant
writer level), and generally keep chasing any pertinent changes in the
edk2 codebase. (Upstream edk2 does not guarantee backwards compatibility
with existent variable stores, and it does not provide conversion tools
either.) If someone feels up to writing and continuously maintaining
such a host-side utility, I won't try to prevent them. But, I won't be
that person.

Another approach would be to replace the above-mentioned variable driver
stack in OVMF, with a custom "paravirt" variable driver implementation.
This would be a large project, and even if I were sympathetic to it
(which I'm not), I'm pretty sure it wouldn't be welcome to upstream edk2
(because competing, parallel implementations for the same thing are a
big maintenance burden). I vaguely suspect that a giga-company whose
name starts with G and refers to a very large number has done this,
targeting their own (unreleased / proprietary) VMM, but to my knowledge
their variable driver implementation is similarly unreleased / proprietary.

Either way, massaging guest-produced data from the host side, be the
data "UEFI variable content" or "disk image content", is also a security
question. So the only one really feasible approach here would be a
libguestfs-like tool that
- booted a guest on top of the variable store,
- implemented a kind of "firmware guest agent" that manipulated the
variables "from the inside",
- and used custom commands over virtio-serial, between host and guest.

As I said, a large project.

Thanks,
Laszlo




More information about the libvirt-users mailing list