[libvirt PATCH 2/2] qemu: support use of stateless EFI firmware

Daniel P. Berrangé berrange at redhat.com
Fri Jul 22 16:23:17 UTC 2022


When the <loader stateless='yes'/> attribute is set, the QEMU driver
needs to do three things

 - Avoid looking for an NVRAM template
 - Avoid auto-populating an <nvram/> path
 - Find firmware descriptors with mode=stateless instead of mode=split

Note, the first thing happens automatically when we solve the second
thing.

Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
---
 src/qemu/qemu_domain.c                        |  3 +-
 src/qemu/qemu_firmware.c                      | 48 +++++++++++--------
 ...ware-auto-efi-stateless.x86_64-latest.args | 33 +++++++++++++
 .../firmware-auto-efi-stateless.xml           | 18 +++++++
 ...re-manual-efi-stateless.x86_64-latest.args | 33 +++++++++++++
 .../firmware-manual-efi-stateless.xml         | 18 +++++++
 tests/qemuxml2argvtest.c                      |  2 +
 7 files changed, 135 insertions(+), 20 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/firmware-auto-efi-stateless.x86_64-latest.args
 create mode 100644 tests/qemuxml2argvdata/firmware-auto-efi-stateless.xml
 create mode 100644 tests/qemuxml2argvdata/firmware-manual-efi-stateless.x86_64-latest.args
 create mode 100644 tests/qemuxml2argvdata/firmware-manual-efi-stateless.xml

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 7df8041adf..b02ffc9a2e 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -4683,7 +4683,8 @@ qemuDomainDefPostParse(virDomainDef *def,
     }
 
     if (virDomainDefHasOldStyleROUEFI(def) &&
-        !def->os.loader->nvram) {
+        !def->os.loader->nvram &&
+        def->os.loader->stateless != VIR_TRISTATE_BOOL_YES) {
         def->os.loader->nvram = virStorageSourceNew();
         def->os.loader->nvram->type = VIR_STORAGE_TYPE_FILE;
         def->os.loader->nvram->format = VIR_STORAGE_FILE_RAW;
diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c
index c477b45d62..eb7abb0b32 100644
--- a/src/qemu/qemu_firmware.c
+++ b/src/qemu/qemu_firmware.c
@@ -1110,10 +1110,18 @@ qemuFirmwareMatchDomain(const virDomainDef *def,
         return false;
     }
 
-    if (fw->mapping.device == QEMU_FIRMWARE_DEVICE_FLASH &&
-        fw->mapping.data.flash.mode != QEMU_FIRMWARE_FLASH_MODE_SPLIT) {
-        VIR_DEBUG("Discarding loader without split flash");
-        return false;
+    if (fw->mapping.device == QEMU_FIRMWARE_DEVICE_FLASH) {
+        if (def->os.loader && def->os.loader->stateless == VIR_TRISTATE_BOOL_YES) {
+            if (fw->mapping.data.flash.mode != QEMU_FIRMWARE_FLASH_MODE_STATELESS) {
+                VIR_DEBUG("Discarding loader without stateless flash");
+                return false;
+            }
+        } else {
+            if (fw->mapping.data.flash.mode != QEMU_FIRMWARE_FLASH_MODE_SPLIT) {
+                VIR_DEBUG("Discarding loader without split flash");
+                return false;
+            }
+        }
     }
 
     if (def->sec) {
@@ -1175,27 +1183,29 @@ qemuFirmwareEnableFeatures(virQEMUDriver *driver,
         VIR_FREE(def->os.loader->path);
         def->os.loader->path = g_strdup(flash->executable.filename);
 
-        if (STRNEQ(flash->nvram_template.format, "raw")) {
-            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
-                           _("unsupported nvram template format '%s'"),
-                           flash->nvram_template.format);
-            return -1;
-        }
+        if (flash->mode == QEMU_FIRMWARE_FLASH_MODE_SPLIT) {
+            if (STRNEQ(flash->nvram_template.format, "raw")) {
+                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                               _("unsupported nvram template format '%s'"),
+                               flash->nvram_template.format);
+                return -1;
+            }
 
-        VIR_FREE(def->os.loader->nvramTemplate);
-        def->os.loader->nvramTemplate = g_strdup(flash->nvram_template.filename);
+            VIR_FREE(def->os.loader->nvramTemplate);
+            def->os.loader->nvramTemplate = g_strdup(flash->nvram_template.filename);
 
-        if (!def->os.loader->nvram) {
-            def->os.loader->nvram = virStorageSourceNew();
-            def->os.loader->nvram->type = VIR_STORAGE_TYPE_FILE;
-            def->os.loader->nvram->format = VIR_STORAGE_FILE_RAW;
-            qemuDomainNVRAMPathFormat(cfg, def, &def->os.loader->nvram->path);
+            if (!def->os.loader->nvram) {
+                def->os.loader->nvram = virStorageSourceNew();
+                def->os.loader->nvram->type = VIR_STORAGE_TYPE_FILE;
+                def->os.loader->nvram->format = VIR_STORAGE_FILE_RAW;
+                qemuDomainNVRAMPathFormat(cfg, def, &def->os.loader->nvram->path);
+            }
         }
 
         VIR_DEBUG("decided on firmware '%s' template '%s' NVRAM '%s'",
                   def->os.loader->path,
-                  def->os.loader->nvramTemplate,
-                  def->os.loader->nvram->path);
+                  NULLSTR(def->os.loader->nvramTemplate),
+                  NULLSTR(def->os.loader->nvram ? def->os.loader->nvram->path : NULL));
         break;
 
     case QEMU_FIRMWARE_DEVICE_KERNEL:
diff --git a/tests/qemuxml2argvdata/firmware-auto-efi-stateless.x86_64-latest.args b/tests/qemuxml2argvdata/firmware-auto-efi-stateless.x86_64-latest.args
new file mode 100644
index 0000000000..89f733761e
--- /dev/null
+++ b/tests/qemuxml2argvdata/firmware-auto-efi-stateless.x86_64-latest.args
@@ -0,0 +1,33 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-fedora \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-fedora/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-fedora/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-fedora/.config \
+/usr/bin/qemu-system-x86_64 \
+-name guest=fedora,debug-threads=on \
+-S \
+-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tmp/lib/domain--1-fedora/master-key.aes"}' \
+-blockdev '{"driver":"file","filename":"/usr/share/OVMF/OVMF.sev.fd","node-name":"libvirt-pflash0-storage","auto-read-only":true,"discard":"unmap"}' \
+-blockdev '{"node-name":"libvirt-pflash0-format","read-only":true,"driver":"raw","file":"libvirt-pflash0-storage"}' \
+-machine pc-q35-4.0,usb=off,dump-guest-core=off,pflash0=libvirt-pflash0-format,memory-backend=pc.ram \
+-accel kvm \
+-cpu qemu64 \
+-m 8 \
+-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":8388608}' \
+-overcommit mem-lock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid 63840878-0deb-4095-97e6-fc444d9bc9fa \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/firmware-auto-efi-stateless.xml b/tests/qemuxml2argvdata/firmware-auto-efi-stateless.xml
new file mode 100644
index 0000000000..1be0f4fd96
--- /dev/null
+++ b/tests/qemuxml2argvdata/firmware-auto-efi-stateless.xml
@@ -0,0 +1,18 @@
+<domain type='kvm'>
+  <name>fedora</name>
+  <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid>
+  <memory unit='KiB'>8192</memory>
+  <vcpu placement='static'>1</vcpu>
+  <os firmware='efi'>
+    <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+    <loader stateless='yes'/>
+  </os>
+  <features>
+    <acpi/>
+  </features>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <controller type='usb' model='none'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/firmware-manual-efi-stateless.x86_64-latest.args b/tests/qemuxml2argvdata/firmware-manual-efi-stateless.x86_64-latest.args
new file mode 100644
index 0000000000..fa4a677ce9
--- /dev/null
+++ b/tests/qemuxml2argvdata/firmware-manual-efi-stateless.x86_64-latest.args
@@ -0,0 +1,33 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-test-bios \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-test-bios/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-test-bios/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-test-bios/.config \
+/usr/bin/qemu-system-x86_64 \
+-name guest=test-bios,debug-threads=on \
+-S \
+-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tmp/lib/domain--1-test-bios/master-key.aes"}' \
+-blockdev '{"driver":"file","filename":"/usr/share/OVMF/OVMF_CODE.fd","node-name":"libvirt-pflash0-storage","auto-read-only":true,"discard":"unmap"}' \
+-blockdev '{"node-name":"libvirt-pflash0-format","read-only":true,"driver":"raw","file":"libvirt-pflash0-storage"}' \
+-machine pc,usb=off,dump-guest-core=off,pflash0=libvirt-pflash0-format,memory-backend=pc.ram \
+-accel tcg \
+-cpu qemu64 \
+-m 1024 \
+-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":1073741824}' \
+-overcommit mem-lock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid 362d1fc1-df7d-193e-5c18-49a71bd1da66 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/firmware-manual-efi-stateless.xml b/tests/qemuxml2argvdata/firmware-manual-efi-stateless.xml
new file mode 100644
index 0000000000..6f2a4963b1
--- /dev/null
+++ b/tests/qemuxml2argvdata/firmware-manual-efi-stateless.xml
@@ -0,0 +1,18 @@
+<domain type='qemu'>
+  <name>test-bios</name>
+  <uuid>362d1fc1-df7d-193e-5c18-49a71bd1da66</uuid>
+  <memory unit='KiB'>1048576</memory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <loader readonly='yes' type='pflash' stateless='yes'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+  </os>
+  <features>
+    <acpi/>
+  </features>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <controller type='usb' model='none'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 57d5f3e1c1..b72d61c3bc 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1205,6 +1205,7 @@ mymain(void)
             QEMU_CAPS_DEVICE_IOH3420,
             QEMU_CAPS_ICH9_AHCI,
             QEMU_CAPS_VIRTIO_SCSI);
+    DO_TEST_CAPS_LATEST("firmware-manual-efi-stateless");
     DO_TEST_CAPS_LATEST("firmware-manual-efi-nvram-template");
     DO_TEST_CAPS_LATEST_PARSE_ERROR("firmware-manual-efi-nvram-template-stateless");
     DO_TEST_CAPS_LATEST("firmware-manual-efi-nvram-network-iscsi");
@@ -1228,6 +1229,7 @@ mymain(void)
     DO_TEST_CAPS_LATEST_PARSE_ERROR("firmware-auto-bios-not-stateless");
     DO_TEST_CAPS_LATEST_PARSE_ERROR("firmware-auto-bios-nvram");
     DO_TEST_CAPS_LATEST("firmware-auto-efi");
+    DO_TEST_CAPS_LATEST("firmware-auto-efi-stateless");
     DO_TEST_CAPS_LATEST("firmware-auto-efi-nvram");
     DO_TEST_CAPS_LATEST("firmware-auto-efi-loader-secure");
     DO_TEST_CAPS_LATEST_PARSE_ERROR("firmware-auto-efi-loader-insecure");
-- 
2.36.1



More information about the libvir-list mailing list