Extend bhyveFirmwareFillDomain() so that when we find the default edk2
firmware, also look for its matching template file, and use it as a
nvramTemplate if found.
Extend bhyvexml2argvtest to verify various NVRAM configurations.
Signed-off-by: Roman Bogorodskiy <bogorodskiy(a)gmail.com>
---
src/bhyve/bhyve_firmware.c | 119 +++++++++++++++---
...gv-uefi-nvram-template-and-source-set.args | 12 ++
...-uefi-nvram-template-and-source-set.ldargs | 1 +
...rgv-uefi-nvram-template-and-source-set.xml | 24 ++++
...bhyvexml2argv-uefi-nvram-template-set.args | 12 ++
...yvexml2argv-uefi-nvram-template-set.ldargs | 1 +
.../bhyvexml2argv-uefi-nvram-template-set.xml | 24 ++++
.../bhyvexml2argv-uefi-nvram.args | 12 ++
.../bhyvexml2argv-uefi-nvram.ldargs | 1 +
.../bhyvexml2argv-uefi-nvram.xml | 24 ++++
tests/bhyvexml2argvtest.c | 5 +
11 files changed, 221 insertions(+), 14 deletions(-)
create mode 100644
tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.args
create mode 100644
tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.ldargs
create mode 100644
tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.args
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.ldargs
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.args
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.ldargs
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.xml
diff --git a/src/bhyve/bhyve_firmware.c b/src/bhyve/bhyve_firmware.c
index 8aaf05dc62..35a1097e5d 100644
--- a/src/bhyve/bhyve_firmware.c
+++ b/src/bhyve/bhyve_firmware.c
@@ -1,7 +1,9 @@
/*
* bhyve_firmware.c: bhyve firmware management
*
+ * Copyright (C) 2019 Red Hat, Inc.
* Copyright (C) 2021 Roman Bogorodskiy
+ * Copyright (C) 2025 The FreeBSD Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,6 +27,7 @@
#include "viralloc.h"
#include "virlog.h"
#include "virfile.h"
+#include "virstring.h"
#include "bhyve_conf.h"
#include "bhyve_firmware.h"
@@ -34,6 +37,76 @@ VIR_LOG_INIT("bhyve.bhyve_firmware");
#define BHYVE_DEFAULT_FIRMWARE "BHYVE_UEFI.fd"
+#define BHYVE_DEFAULT_NVRAM_TEMPLATE "BHYVE_UEFI_VARS.fd"
+
+static void
+bhyveFirmwareEnsureNVRAM(virDomainDef *def,
+ bhyveConn *driver)
+{
+ g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(driver);
+ virDomainLoaderDef *loader = def->os.loader;
+ const char *ext = NULL;
+
+ if (!loader)
+ return;
+
+ if (loader->type != VIR_DOMAIN_LOADER_TYPE_PFLASH)
+ return;
+
+ if (loader->readonly != VIR_TRISTATE_BOOL_YES)
+ return;
+
+ if (loader->stateless == VIR_TRISTATE_BOOL_YES)
+ return;
+
+ /* If the NVRAM format hasn't been set yet, inherit the same as
+ * the loader */
+ if (loader->nvram && !loader->nvram->format)
+ loader->nvram->format = loader->format;
+
+ if (loader->nvram) {
+ /* Nothing to do if a proper NVRAM backend is already configured */
+ if (!virStorageSourceIsEmpty(loader->nvram))
+ return;
+
+ /* otherwise we want to reset and re-populate the definition */
+ virObjectUnref(loader->nvram);
+ } else {
+ /* Also do nothing if NVRAM is not requested */
+ return;
+ }
+
+ loader->nvram = virStorageSourceNew();
+ loader->nvram->type = VIR_STORAGE_TYPE_FILE;
+
+ /* The nvram template format should be always present but as a failsafe,
+ * duplicate the loader format if it is not available. */
+ if (loader->nvramTemplateFormat > VIR_STORAGE_FILE_NONE)
+ loader->nvram->format = loader->nvramTemplateFormat;
+ else
+ loader->nvram->format = loader->format;
+
+ /* The extension used by raw edk2 builds has historically
+ * been .fd, but more recent aarch64 builds have started
+ * using the .raw extension instead.
+ *
+ * If we're defining a new domain, we should try to match the
+ * extension for the file backing its NVRAM store with the
+ * one used by the template to keep things nice and
+ * consistent.
+ *
+ * If we're loading an existing domain, however, we need to
+ * stick with the .fd extension to ensure compatibility */
+ if (loader->nvramTemplate &&
+ virStringHasSuffix(loader->nvramTemplate, ".raw"))
+ ext = ".raw";
+ else
+ ext = ".fd";
+
+ loader->nvram->path = g_strdup_printf("%s/%s_VARS%s",
+ cfg->nvramDir, def->name,
+ NULLSTR_EMPTY(ext));
+}
int
bhyveFirmwareFillDomain(bhyveConn *driver,
@@ -42,25 +115,31 @@ bhyveFirmwareFillDomain(bhyveConn *driver,
{
g_autoptr(DIR) dir = NULL;
g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(driver);
+ virDomainLoaderDef *loader = def->os.loader;
const char *firmware_dir = cfg->firmwareDir;
struct dirent *entry;
g_autofree char *matching_firmware = NULL;
+ g_autofree char *matching_nvram_template = NULL;
g_autofree char *first_found = NULL;
virCheckFlags(0, -1);
if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_NONE)
- return 0;
+ goto out;
if (virDirOpenIfExists(&dir, firmware_dir) > 0) {
while ((virDirRead(dir, &entry, firmware_dir)) > 0) {
if (g_str_has_prefix(entry->d_name, "."))
continue;
- if (STREQ(entry->d_name, BHYVE_DEFAULT_FIRMWARE)) {
+ if (!matching_firmware &&
+ STREQ(entry->d_name, BHYVE_DEFAULT_FIRMWARE))
matching_firmware = g_strdup(entry->d_name);
- break;
- }
+
+ if (!matching_nvram_template &&
+ STREQ(entry->d_name, BHYVE_DEFAULT_NVRAM_TEMPLATE))
+ matching_nvram_template = g_strdup(entry->d_name);
+
if (!first_found)
first_found = g_strdup(entry->d_name);
}
@@ -77,25 +156,37 @@ bhyveFirmwareFillDomain(bhyveConn *driver,
}
}
- if (!def->os.loader)
- def->os.loader = virDomainLoaderDefNew();
+ if (!loader) {
+ loader = virDomainLoaderDefNew();
+ def->os.loader = loader;
+ }
- if (!def->os.loader->format)
- def->os.loader->format = VIR_STORAGE_FILE_RAW;
+ if (!loader->format)
+ loader->format = VIR_STORAGE_FILE_RAW;
- if (def->os.loader->format != VIR_STORAGE_FILE_RAW) {
+ if (loader->format != VIR_STORAGE_FILE_RAW) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported loader format '%1$s'"),
- virStorageFileFormatTypeToString(def->os.loader->format));
+ virStorageFileFormatTypeToString(loader->format));
return -1;
}
- def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
- def->os.loader->readonly = VIR_TRISTATE_BOOL_YES;
+ if (!loader->nvramTemplate
+ && matching_firmware && matching_nvram_template) {
+ loader->nvramTemplate = g_build_filename(firmware_dir,
+ matching_firmware,
+ NULL);
+ }
+
+ loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
+ loader->readonly = VIR_TRISTATE_BOOL_YES;
+
+ VIR_FREE(loader->path);
- VIR_FREE(def->os.loader->path);
+ loader->path = g_build_filename(firmware_dir, matching_firmware, NULL);
- def->os.loader->path = g_build_filename(firmware_dir, matching_firmware,
NULL);
+ out:
+ bhyveFirmwareEnsureNVRAM(def, driver);
return 0;
}
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.args
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.args
new file mode 100644
index 0000000000..05a9e8df2c
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.args
@@ -0,0 +1,12 @@
+bhyve \
+-c 1 \
+-m 214 \
+-u \
+-H \
+-P \
+-s 0:0,hostbridge \
+-l bootrom,/path/to/test.fd,/path/to/nvram/guest_VARS.fd \
+-s 1:0,lpc \
+-s 2:0,ahci,hd:/tmp/freebsd.img \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+bhyve
diff --git
a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.ldargs
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.ldargs
new file mode 100644
index 0000000000..421376db9e
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.ldargs
@@ -0,0 +1 @@
+dummy
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.xml
new file mode 100644
index 0000000000..cdcbfd081c
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-and-source-set.xml
@@ -0,0 +1,24 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ <loader readonly="yes"
type="pflash">/path/to/test.fd</loader>
+ <nvram
template='/path/to/test_VARS.fd'>/path/to/nvram/guest_VARS.fd</nvram>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ <address type='drive' controller='0' bus='0'
target='2' unit='0'/>
+ </disk>
+ <interface type='bridge'>
+ <model type='virtio'/>
+ <source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.args
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.args
new file mode 100644
index 0000000000..0d367e99f1
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.args
@@ -0,0 +1,12 @@
+bhyve \
+-c 1 \
+-m 214 \
+-u \
+-H \
+-P \
+-s 0:0,hostbridge \
+-l bootrom,/path/to/test.fd,fakenvramdir/bhyve_VARS.fd \
+-s 1:0,lpc \
+-s 2:0,ahci,hd:/tmp/freebsd.img \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.ldargs
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.ldargs
new file mode 100644
index 0000000000..421376db9e
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.ldargs
@@ -0,0 +1 @@
+dummy
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.xml
new file mode 100644
index 0000000000..c05dd4ff95
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram-template-set.xml
@@ -0,0 +1,24 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ <loader readonly="yes"
type="pflash">/path/to/test.fd</loader>
+ <nvram template='/path/to/test_VARS.fd'/>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ <address type='drive' controller='0' bus='0'
target='2' unit='0'/>
+ </disk>
+ <interface type='bridge'>
+ <model type='virtio'/>
+ <source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.args
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.args
new file mode 100644
index 0000000000..0d367e99f1
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.args
@@ -0,0 +1,12 @@
+bhyve \
+-c 1 \
+-m 214 \
+-u \
+-H \
+-P \
+-s 0:0,hostbridge \
+-l bootrom,/path/to/test.fd,fakenvramdir/bhyve_VARS.fd \
+-s 1:0,lpc \
+-s 2:0,ahci,hd:/tmp/freebsd.img \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \
+bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.ldargs
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.ldargs
new file mode 100644
index 0000000000..421376db9e
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.ldargs
@@ -0,0 +1 @@
+dummy
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.xml
b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.xml
new file mode 100644
index 0000000000..bec38ad65d
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-uefi-nvram.xml
@@ -0,0 +1,24 @@
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ <loader readonly="yes"
type="pflash">/path/to/test.fd</loader>
+ <nvram/>
+ </os>
+ <devices>
+ <disk type='file'>
+ <driver name='file' type='raw'/>
+ <source file='/tmp/freebsd.img'/>
+ <target dev='hda' bus='sata'/>
+ <address type='drive' controller='0' bus='0'
target='2' unit='0'/>
+ </disk>
+ <interface type='bridge'>
+ <model type='virtio'/>
+ <source bridge="virbr0"/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c
index 3831f0c65d..58b404ca7d 100644
--- a/tests/bhyvexml2argvtest.c
+++ b/tests/bhyvexml2argvtest.c
@@ -148,6 +148,7 @@ mymain(void)
{
int ret = 0;
g_autofree char *fakefirmwaredir = g_strdup("fakefirmwaredir");
+ g_autofree char *fakenvramdir = g_strdup("fakenvramdir");
g_autofree char *fakefirmwareemptydir = g_strdup("fakefirmwareemptydir");
if ((driver.caps = virBhyveCapsBuild()) == NULL)
@@ -163,6 +164,7 @@ mymain(void)
return EXIT_FAILURE;
driver.config->firmwareDir = fakefirmwaredir;
+ driver.config->nvramDir = fakenvramdir;
# define DO_TEST_FULL(name, flags) \
do { \
@@ -218,6 +220,9 @@ mymain(void)
DO_TEST("localtime");
DO_TEST("net-e1000");
DO_TEST("uefi");
+ DO_TEST("uefi-nvram");
+ DO_TEST("uefi-nvram-template-set");
+ DO_TEST("uefi-nvram-template-and-source-set");
DO_TEST("vnc");
DO_TEST("vnc-vgaconf-on");
DO_TEST("vnc-vgaconf-off");
--
2.49.0