From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id F1A2A1A1E43 for ; Tue, 4 Oct 2016 10:22:36 -0700 (PDT) Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 59AE531B311; Tue, 4 Oct 2016 17:22:36 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-70.phx2.redhat.com [10.3.116.70]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u94HMYNV009377; Tue, 4 Oct 2016 13:22:35 -0400 To: spam collector References: <1825038664.87486514.1475464584880.JavaMail.zimbra@cableone.net> <9f2b0b8c-9bfb-dd73-f7cb-cd6df775c237@redhat.com> <812341546.91963700.1475549145141.JavaMail.zimbra@cableone.net> <5c54ce38-9f0c-ac8d-c926-570ebc3dd720@redhat.com> <1747186652.93714260.1475599157436.JavaMail.zimbra@cableone.net> Cc: edk2-devel@ml01.01.org From: Laszlo Ersek Message-ID: <94a76bd7-732c-c8f6-b8be-8175dd061b86@redhat.com> Date: Tue, 4 Oct 2016 19:22:34 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 In-Reply-To: <1747186652.93714260.1475599157436.JavaMail.zimbra@cableone.net> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 04 Oct 2016 17:22:36 +0000 (UTC) Subject: Re: OVMF.fd and placement of EfiBootServicesData X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Oct 2016 17:22:37 -0000 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit On 10/04/16 18:39, spam collector wrote: > [...] I was surprised to see that QEMU and/or > OVMF requires the NvVars file to exist on the partition, else OVMF > does not even show the shell, even on a perfectly valid partitioned > image. I don't know if this is QEMU's fault or OVMF's fault. If > the NvVars file does not exist, is it the desired option to fail > the loading of the shell? If the file does not exist, can OVMF use > default values and still load the shell? OVMF does not require the NvVars file to exist. The NvVars file is only used / relied on when the QEMU command line is incorrect, that is, when it does not configure the pflash chip(s) for storing the firmware binary and/or the variable store. * The command line that you are likely used to goes like this: qemu-system-x86_64 -bios OVMF.fd ... This is broken. Don't use it. The OVMF.fd file in the above usage is a unified file (1MB or 2MB in size), containing both the firmware binary and an empty (pre-formatted) variable store. The entire file is mapped into guest memory as ROM. The variable store area is not writeable, hence OVMF falls back to the NvVars based emulation. That emulation is not entirely compatible with the UEFI spec. Don't use the above command line. * The first stage improvement is the following command line: qemu-system-x86_64 -pflash OVMF.fd The OVMF.fd file has the same characteristics as above, but the same stuff is mapped as a programmable pflash chip into guest memory. It means that the guest memory area in question *normally* reads and executes like normal RAM, but if you write to it (that is, if OVMF's flash driver writes to it), it is flipped into "programming mode", where you can read and write the device using various "commands". One of those commands flips the device back to "normal" mode. In this mode, the NvVars-based emulation is not used, and the variable store / variable services will work as defined by the UEFI spec. The problem with this approach is that the OVMF.fd file contains both a firmware binary and a live variable store. You cannot upgrade the firmware binary without losing the VM's long-term, non-volatile variables. * The second stage improvement is the following command line: # create the virtual machine's private variable store from the # pristine variable store template, if the former doesn't exist yet, # or has been lost for some reason if ! [ -e GUEST_1_VARS.fd ]; then cp OVMF_VARS.fd GUEST_1_VARS.fd fi qemu-system-x86_64 \ -drive if=pflash,format=raw,unit=0,readonly,file=OVMF_CODE.fd \ -drive if=pflash,format=raw,unit=1,file=GUEST_1_VARS.fd \ ... In this case, the OVMF_CODE.fd and OVMF_VARS.fd are used separately. (You can find both files under the Build directory; plus Gerd Hoffmann's RPM files also package them.) The OVMF_CODE.fd file is the read-only firmware binary (1920KB in size), whereas the OVMF_VARS.fd file is an empty, preformatted variable store *template* (128KB in size). The VM never uses OVMF_VARS.fd directly, you (or the management layer, see below) uses that file only to instantiate VM-specific varstores. This pattern allows you to upgrade your firmware binary without messing up each VM's own variable store. The issue with this method is that a malicious guest OS can still poke at the pflash chip (with unit=1) directly. If you have Secure Boot enabled, you don't want the guest OS to tamper with the authenticated UEFI variables in the varstore that contain certificates and such. * The third stage improvement is SMM. For that, build OVMF like this (I'm simplifying a lot, but this email should come to an end sometime): build -a IA32 -a X64 -p OvmfPkg/OvmfPkgIa32X64.dsc \ -D SMM_REQUIRE -D SECURE_BOOT_ENABLE \ ... and run OVMF like this: # create the virtual machine's private variable store from the # pristine variable store template, if the former doesn't exist yet, # or has been lost for some reason if ! [ -e GUEST_1_VARS.fd ]; then cp OVMF_VARS.fd GUEST_1_VARS.fd fi qemu-system-x86_64 \ -machine q35,smm=on \ -global driver=cfi.pflash01,property=secure,value=on \ -drive if=pflash,format=raw,unit=0,readonly,file=OVMF_CODE.fd \ -drive if=pflash,format=raw,unit=1,file=GUEST_1_VARS.fd \ In this case, the guest OS won't be able to write to the variable store directly. It will have to invoke the runtime UEFI variable services, which will raise an SMI / enter SMM. The SMI handler (part of the firmware) will validate / authenticate the request parameters, and perform the modifications if they are valid. * The fourth stage improvement is to use libvirt, which will handle all of the above for you, assuming you give it the right domain XML. (Virt-manager / virt-install can create domain XMLs that need no or minimal further customizations.) * In some builds / distributions of OVMF, the UEFI shell is excluded from the firmware image, and it is provided on a small ISO image. This is justified by two things: (a) first, this way you can use QEMU's -device virtio-scsi-pci,id=scsi0 \ -drive if=none,format=raw,readonly,file=UefiShell.iso \ -device scsi-hd,bus=scsi0.0,bootindex=N \ options to boot the UEFI shell directly -- bootindex is not usable for modules built into the firmware binary; QEMU's "bootorder" fw_cfg doesn't have enough expressive power for that --, (b) second, we've been advised that the UEFI shell can be used to circumvent Secure Boot. By moving the shell binary out of the firmware image, to a CD-ROM, as an external *unsigned* EFI application, it cannot be launched when Secure Boot is enabled. * Should your installed guest (such as a UEFI GNU/Linux distro, or a UEFI Windows edition) lose the variable store (for example because you unwittingly delete GUEST_1_VARS.fd), the UEFI spec defines a method for the (guest) OS to recreate a sane set of boot options / boot order, after you (or libvirt) recreate GUEST_1_VARS.fd from OVMF_VARS.fd again. For Linux at least, the keyword here is "fallback.efi"; you can read about it at . > > I ask because I spent a little while thinking that my GPT partitioned > image was in error since I could not get a shell to load. Once I > added the NvVars file to the root directory, the shell loaded as > expected. If NvVars is not compatible with UEFI, which I don't > believe it is, (which you are correct about,) > should OVMF still require it to boot to the shell? No, and it doesn't. Use one of the above pflash-based methods please. Since we're into boot option land anyway, I should mention the following section of the OVMF whitepaper: Select features | Platform-specific boot policy If you never use the "bootindex=N" QEMU device property (or libvirt's equivalent element), then OVMF will not touch your UEFI boot options (Boot####, BootOrder), beyond regenerating options for all possible bootable devices at the end of your current BootOrder. However, if you want to influence the UEFI boot order from the QEMU command line (or the libvirt domain XML), you can. There are a few caveats; please read the above whitepaper section for understanding them. > Maybe if I study more on the pflash option and use it, OVMF will > not require the NvVars file. Exactly. > > I ask with the intent of better understanding the reason it > requires the NvVars file, as opposed to being sarcastic as it may > sound. :-) It doesn't sound sarcastic, don't worry. ;) NvVars dates back to a time when QEMU didn't have pflash yet, and (consequently) OVMF didn't have a driver for QEMU's pflash. Now that pflash can be used, it (and only it) should be used too. OVMF also runs on Xen. Xen doesn't provide pflash emulation, so the NvVars fallback is still in active use on Xen. Thanks Laszlo