From 560429fd746adf04b57237c3c4a38ecfd906c592 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Mar 2025 15:11:53 +0100 Subject: [PATCH 1/6] hw/uefi: flush variable store to disk in post load Make live migration more robust. Commit 4c0cfc72b31a ("pflash_cfi01: write flash contents to bdrv on incoming migration") elaborates in detail on the motivation. Cc: Peter Krempa Reviewed-by: Peter Krempa Signed-off-by: Gerd Hoffmann Message-ID: <20250319141159.1461621-2-kraxel@redhat.com> --- hw/uefi/var-service-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/uefi/var-service-core.c b/hw/uefi/var-service-core.c index 8ed8378ab9..4836a0cb81 100644 --- a/hw/uefi/var-service-core.c +++ b/hw/uefi/var-service-core.c @@ -29,6 +29,7 @@ static int uefi_vars_post_load(void *opaque, int version_id) uefi_vars_state *uv = opaque; uefi_vars_update_storage(uv); + uefi_vars_json_save(uv); uv->buffer = g_malloc(uv->buf_size); return 0; } From ae24cf139ba681f8ce3dc809f3f1119b16c73043 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Mar 2025 15:11:54 +0100 Subject: [PATCH 2/6] hw/uefi: fix error handling in uefi_vars_json_save MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch lseek errors. Return on errors. Use autoptr for the GString to simplify cleanup. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Message-ID: <20250319141159.1461621-3-kraxel@redhat.com> --- hw/uefi/var-service-json.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c index 761082c11f..f1c20a6b8c 100644 --- a/hw/uefi/var-service-json.c +++ b/hw/uefi/var-service-json.c @@ -178,7 +178,7 @@ void uefi_vars_json_init(uefi_vars_state *uv, Error **errp) void uefi_vars_json_save(uefi_vars_state *uv) { - GString *gstr; + g_autoptr(GString) gstr = NULL; int rc; if (uv->jsonfd == -1) { @@ -187,18 +187,25 @@ void uefi_vars_json_save(uefi_vars_state *uv) gstr = uefi_vars_to_json(uv); - lseek(uv->jsonfd, 0, SEEK_SET); + rc = lseek(uv->jsonfd, 0, SEEK_SET); + if (rc < 0) { + warn_report("%s: lseek error", __func__); + return; + } + rc = ftruncate(uv->jsonfd, 0); if (rc != 0) { warn_report("%s: ftruncate error", __func__); + return; } + rc = write(uv->jsonfd, gstr->str, gstr->len); if (rc != gstr->len) { warn_report("%s: write error", __func__); + return; } - fsync(uv->jsonfd); - g_string_free(gstr, true); + fsync(uv->jsonfd); } void uefi_vars_json_load(uefi_vars_state *uv, Error **errp) From 761d0b5fb7e0f0a6a36c5fc449c6feda2b78af79 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Mar 2025 15:11:55 +0100 Subject: [PATCH 3/6] hw/uefi: fix error handling in uefi_vars_json_load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch lseek errors. Return on read errors. Fixes: CID 1593154 Fixes: CID 1593157 Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Message-ID: <20250319141159.1461621-4-kraxel@redhat.com> --- hw/uefi/var-service-json.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c index f1c20a6b8c..ad3462cd15 100644 --- a/hw/uefi/var-service-json.c +++ b/hw/uefi/var-service-json.c @@ -214,7 +214,7 @@ void uefi_vars_json_load(uefi_vars_state *uv, Error **errp) QObject *qobj; Visitor *v; char *str; - size_t len; + ssize_t len; int rc; if (uv->jsonfd == -1) { @@ -222,7 +222,12 @@ void uefi_vars_json_load(uefi_vars_state *uv, Error **errp) } len = lseek(uv->jsonfd, 0, SEEK_END); + if (len < 0) { + warn_report("%s: lseek error", __func__); + return; + } if (len == 0) { + /* empty file */ return; } @@ -231,6 +236,8 @@ void uefi_vars_json_load(uefi_vars_state *uv, Error **errp) rc = read(uv->jsonfd, str, len); if (rc != len) { warn_report("%s: read error", __func__); + g_free(str); + return; } str[len] = 0; From 5807508fad5344706f7d644e4232d065cb1ac2ea Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Mar 2025 15:11:56 +0100 Subject: [PATCH 4/6] hw/uefi-vars-sysbus: allow for riscv virt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the device being added to riscv virt VMs. Reviewed-by: Daniel Henrique Barboza Reviewed-by: Daniel P. Berrangé Signed-off-by: Gerd Hoffmann Message-ID: <20250319141159.1461621-5-kraxel@redhat.com> --- hw/riscv/virt.c | 2 ++ hw/uefi/Kconfig | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index dae46f4733..e517002fdf 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -57,6 +57,7 @@ #include "hw/acpi/aml-build.h" #include "qapi/qapi-visit-common.h" #include "hw/virtio/virtio-iommu.h" +#include "hw/uefi/var-service-api.h" /* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */ static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type) @@ -1935,6 +1936,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) hc->plug = virt_machine_device_plug_cb; machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS); #ifdef CONFIG_TPM machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); #endif diff --git a/hw/uefi/Kconfig b/hw/uefi/Kconfig index ca6c2bc46a..f139008b63 100644 --- a/hw/uefi/Kconfig +++ b/hw/uefi/Kconfig @@ -1,3 +1,3 @@ config UEFI_VARS bool - default y if X86_64 || AARCH64 + default y if X86_64 || AARCH64 || RISCV64 From e1092f765d9c0bf33762a03fe45e3d0de86c86a6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Mar 2025 15:11:57 +0100 Subject: [PATCH 5/6] hw/uefi-vars-sysbus: allow for loongarch virt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the device being added to loongarch virt VMs. Reviewed-by: Daniel P. Berrangé Signed-off-by: Gerd Hoffmann Message-ID: <20250319141159.1461621-6-kraxel@redhat.com> --- hw/loongarch/virt.c | 2 ++ hw/uefi/Kconfig | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index a5840ff968..b6f5f6a3b5 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -38,6 +38,7 @@ #include "hw/mem/nvdimm.h" #include "hw/platform-bus.h" #include "hw/display/ramfb.h" +#include "hw/uefi/var-service-api.h" #include "hw/mem/pc-dimm.h" #include "system/tpm.h" #include "system/block-backend.h" @@ -1207,6 +1208,7 @@ static void virt_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "v-eiointc", "Enable Virt Extend I/O Interrupt Controller."); machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS); #ifdef CONFIG_TPM machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); #endif diff --git a/hw/uefi/Kconfig b/hw/uefi/Kconfig index f139008b63..046d55320e 100644 --- a/hw/uefi/Kconfig +++ b/hw/uefi/Kconfig @@ -1,3 +1,3 @@ config UEFI_VARS bool - default y if X86_64 || AARCH64 || RISCV64 + default y if X86_64 || AARCH64 || RISCV64 || LOONGARCH64 From 5e5d18d2ccd674778715f828df80fdddac73bdea Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Mar 2025 15:11:58 +0100 Subject: [PATCH 6/6] docs/firmware: add feature flag for host uefi variable store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Daniel P. Berrangé Signed-off-by: Gerd Hoffmann Message-ID: <20250319141159.1461621-7-kraxel@redhat.com> --- docs/interop/firmware.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json index 57f55f6c54..745d21d822 100644 --- a/docs/interop/firmware.json +++ b/docs/interop/firmware.json @@ -214,13 +214,23 @@ # PL011 UART. @verbose-static is mutually exclusive # with @verbose-dynamic. # +# @host-uefi-vars: The firmware expects the host to provide an uefi +# variable store. qemu supports that via +# "uefi-vars-sysbus" (aarch64, riscv64, loongarch64) +# or "uefi-vars-x64" (x86_64) devices. The firmware +# will not use flash for nvram. When loading the +# firmware into flash the 'stateless' setup should be +# used. It is recommened to load the firmware into +# memory though. +# # Since: 3.0 ## { 'enum' : 'FirmwareFeature', 'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'amd-sev-snp', 'intel-tdx', - 'enrolled-keys', 'requires-smm', 'secure-boot', + 'enrolled-keys', 'requires-smm', + 'secure-boot', 'host-uefi-vars', 'verbose-dynamic', 'verbose-static' ] } ##