qemu-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-discuss] Impact of incorrectly-mapped OVMF


From: Laszlo Ersek
Subject: Re: [Qemu-discuss] Impact of incorrectly-mapped OVMF
Date: Fri, 20 Apr 2018 10:54:28 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0

On 04/19/18 18:35, Prerna wrote:
> On Thu, Apr 19, 2018 at 7:59 AM, Prerna <address@hidden> wrote:
> 
>> Hi all,
>> In playing around with OVMF a few times I accidentally specified my
>> qemu-kvm binary with this erroneous command line: "qemu-kvm ... -bios
>> /usr/share/OVMF/OVMF_CODE.fd" instead of passing this as if=pflash.
>>
>> I was expecting this to error out in qemu, but surprisingly qemu(2.6) let
>> the VM boot into EDK2 shell, and even past that into the VM's cdrom that
>> ran an installer.  Ofcourse the VM would sporadically see odd hangs/crashes
>> but that would always happen at a different time instant (sometimes not
>> happening for even days).
>>
>> My question is, what happens from a firmware initialisation perspective if
>> edk2 is passed as a bios rom instead of as pflash? Also, given that all
>> these are effectively blobs that load into memory, is there some sort of
>> pre-check that can be done by QEMU to avoid loading OVMF binary as a bios
>> ROM ?
>>
>> (Note that this is purely out of curiosity, I understand it is risky to
>> run this in production )
>> (with mismatched -bios/pflash tag)
>>
> 
> Laszlo, if you could provide any pointers for me to understand this better ?

Sure.

The OvmfPkg/README file has a section called "OVMF Flash Layout". It
explains where / how the unified (OVMF.fd) image is mapped just under
4GB in guest-phys address space.

(1) If you map the unified image with -bios, all of that becomes ROM --
read-only memory.

(2) If you map the unified image with -pflash, all of that becomes
read-write MMIO.

(3) If you use the split images (OVMF_CODE.fd and a copy of
OVMF_VARS.fd), and map then as flash chips, then the top part
(OVMF_CODE.fd, consisting of SECFV and FVMAIN_COMPACT) becomes read-only
flash (MMIO), and the bottom part (copy of OVMF_VARS.fd, consisting of
FTW Spare, FTW Work, Event log, and NV store) becomes read-write flash
(MMIO).

(4) If you use -bios with OVMF_CODE.fd only, then the top part will be
ROM, and the bottom part will be "black hole" MMIO.

Option (4) is totally invalid.

Option (3) is the best solution and it is what everybody should use (the
virt stack / libvirt already uses that).

Option (2) is acceptable, but it's suboptimal from a firmware binary
update POV -- you cannot replace your binary without losing your variables.

Option (1) is the ancient relic that once (before qemu-1.6) used to be
the only option. When you use Xen, this is the only option still today.

OVMF contains detection code that tells apart case (1) from the set {
case (2), case (3) }. (Cases (2) and (3) in the latter set look
indistinguishable to the firmware, by design.) If pflash is detected,
then you get a UEFI variable service implementation that conforms to the
UEFI spec, and everything will work fine. If, however, case (1) is
detected, then OVMF switches to a kind of variable store "emulation", where:
- variables (even non-volatile variables) primarily live in RAM only,
- a file called \NvVars on the EFI System Partition (a FAT filesystem)
  contains a serialized image of the variables,
- when booting the VM, \NvVars is de-serialized into RAM,
- until the OS is launched, variable changes (initiated from the
  firmware), are synched out to \NvVars at once,
- after the OS is launched, variable changes remain only in memory,
- if you gracefully reboot the VM into the firmware, then OS-initiated
  variable changes are synched out to \NvVars,
- if you power down the VM from within the OS, you'll lose any
  OS-initiated variable changes
- Another limitation is that some kinds of variables cannot be
  serialized and de-serialized like this; in particular variables
  related to Secure Boot.

Unfortunately this detection logic is extremely prone to mis-use (and
esp. it was never meant to deal with case (4)) and to causing confusion.
For this reason, I have had patches for a long time now that allow the
user to compile "-bios" support out of OVMF, with a build flag
(-DMEM_VARSTORE_EMU_ENABLE=FALSE). Then you will simply become unable to
boot with "-bios" -- the firmware will just hang with a black screen.
(If you capture the debug log (see OvmfPkg/README), you'll know what's
up though.) Note that this would not be the default -- the default build
wouldn't change.

Firmware built like this is much better to use on QEMU (much less room
for error, and there are some firmware features that become possible --
the UEFI memmap will be de-fragmented over time, and the foundation for
S4 support, i.e., suspend to disk, is laid).

In particular if you build OVMF with -DSMM_REQUIRE, then "-bios" support
is *already* compiled out. (If you use OVMF on Xen, then your only
choice is option (1) (because Xen does not implement flash), so OVMF
binaries built with either -DSMM_REQUIRE, or my (proposed)
-DMEM_VARSTORE_EMU_ENABLE=FALSE flag, will not run on Xen.)

My work related to -DMEM_VARSTORE_EMU_ENABLE=FALSE can be seen in
<https://bugzilla.tianocore.org/show_bug.cgi?id=386>.

You might be curious why these patches aren't upstream (despite me
having run them on my end for more than a year now). Well, both times I
posted them, they were blocked for non-technical reasons that make zero
sense to me. They boil down to, "we shouldn't enable the user to build
an OVMF binary that cannot run on Xen; instead we should implement a
fake PEI-phase r/o variable service for Xen too, *even though* that
service could *never* report valid variable contents". Thus, I'm not
allowed to improve the situation on QEMU, even conditionally, without
working a bunch more on a shim for Xen that *would not work* anyway,
functionally speaking.

So there you have it. Just be sure to use flash, or -- even better --
use libvirt to start QEMU for you. That's what I do anyway (beyond using
my patches for TianoCore BZ#386, obviously).

We could perhaps ask Gerd to incorporate my patches, for TianoCore
BZ#386, into a new firmware image at kraxel.org/repos; then users
interested in this feature -- deterministic failure to boot with -bios,
and a defragmented UEFI memmap -- could switch to that new image.

Thanks
Laszlo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]