Currently, bhyve bootrom specification looks like this:
bhyve ... -l bootrom,/path/to/firmware.fd
In addition to that, it supports specifying the VARS files using:
-l bootrom,/path/to/firmware.fd,/path/to/my_domain_VARS.fd
Update virBhyveProcessBuildBhyveCmd() to include the VARS file if NVRAM
is specified in the domain XML.
Additionally, support copying this file from the specified template. To
do that, introduce the bhyveProcessPrepareHost() and related helpers.
They are currently not doing anything but NVRAM preparations, but should
be useful for other host-side related tasks in the future.
Signed-off-by: Roman Bogorodskiy <bogorodskiy(a)gmail.com>
---
src/bhyve/bhyve_command.c | 8 ++-
src/bhyve/bhyve_process.c | 132 ++++++++++++++++++++++++++++++++++++++
src/bhyve/bhyve_process.h | 8 +++
3 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index 44c66ea147..cd1ccf61f3 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -808,8 +808,12 @@ virBhyveProcessBuildBhyveCmd(struct _bhyveConn *driver, virDomainDef
*def,
if (def->os.bootloader == NULL &&
def->os.loader) {
if ((bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_LPC_BOOTROM)) {
- virCommandAddArg(cmd, "-l");
- virCommandAddArgFormat(cmd, "bootrom,%s",
def->os.loader->path);
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+ virBufferAsprintf(&buf, "bootrom,%s",
def->os.loader->path);
+ if (def->os.loader->nvram &&
def->os.loader->nvram->path)
+ virBufferAsprintf(&buf, ",%s",
def->os.loader->nvram->path);
+
+ virCommandAddArgList(cmd, "-l", virBufferContentAndReset(&buf),
NULL);
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Installed bhyve binary does not support UEFI
loader"));
diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c
index a17994e2a0..5e77a9c4d6 100644
--- a/src/bhyve/bhyve_process.c
+++ b/src/bhyve/bhyve_process.c
@@ -1,6 +1,7 @@
/*
* bhyve_process.c: bhyve process management
*
+ * Copyright (C) 2006-2016 Red Hat, Inc.
* Copyright (C) 2014 Roman Bogorodskiy
* Copyright (C) 2025 The FreeBSD Foundation
*
@@ -275,6 +276,134 @@ bhyveProcessPrepareDomain(bhyveConn *driver,
return 0;
}
+
+struct bhyvePrepareNVRAMHelperData {
+ int srcFD;
+ const char *srcPath;
+};
+
+
+static int
+bhyvePrepareNVRAMHelper(int dstFD,
+ const char *dstPath,
+ const void *opaque)
+{
+ const struct bhyvePrepareNVRAMHelperData *data = opaque;
+ ssize_t r;
+
+ do {
+ char buf[1024];
+
+ if ((r = saferead(data->srcFD, buf, sizeof(buf))) < 0) {
+ virReportSystemError(errno,
+ _("Unable to read from file '%1$s'"),
+ data->srcPath);
+ return -2;
+ }
+
+ if (safewrite(dstFD, buf, r) < 0) {
+ virReportSystemError(errno,
+ _("Unable to write to file '%1$s'"),
+ dstPath);
+ return -1;
+ }
+ } while (r);
+
+ return 0;
+}
+
+
+static int
+bhyvePrepareNVRAMFile(bhyveConn *driver G_GNUC_UNUSED,
+ virDomainLoaderDef *loader)
+{
+ VIR_AUTOCLOSE srcFD = -1;
+ struct bhyvePrepareNVRAMHelperData data;
+
+ if (virFileExists(loader->nvram->path))
+ return 0;
+
+ if (!loader->nvramTemplate) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("unable to find any master var store for loader:
%1$s"),
+ loader->path);
+ return -1;
+ }
+
+ /* If 'nvramTemplateFormat' is empty it means that it's a user-provided
+ * template which we couldn't verify. Assume the user knows what they're
doing */
+ if (loader->nvramTemplateFormat != VIR_STORAGE_FILE_NONE &&
+ loader->nvram->format != loader->nvramTemplateFormat) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("conversion of the nvram template to another target format
is not supported"));
+ return -1;
+ }
+
+ if ((srcFD = virFileOpenAs(loader->nvramTemplate, O_RDONLY,
+ 0, -1, -1, 0)) < 0) {
+ virReportSystemError(-srcFD,
+ _("Failed to open file '%1$s'"),
+ loader->nvramTemplate);
+ return -1;
+ }
+
+ data.srcFD = srcFD;
+ data.srcPath = loader->nvramTemplate;
+
+ if (virFileRewrite(loader->nvram->path,
+ S_IRUSR | S_IWUSR,
+ 0, 0,
+ bhyvePrepareNVRAMHelper,
+ &data) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+bhyvePrepareNVRAM(bhyveConn *driver,
+ virDomainDef *def)
+{
+ virDomainLoaderDef *loader = def->os.loader;
+
+ if (!loader || !loader->nvram)
+ return 0;
+
+ VIR_DEBUG("nvram='%s'", NULLSTR(loader->nvram->path));
+
+ switch (virStorageSourceGetActualType(loader->nvram)) {
+ case VIR_STORAGE_TYPE_FILE:
+ return bhyvePrepareNVRAMFile(driver, loader);
+ case VIR_STORAGE_TYPE_BLOCK:
+ case VIR_STORAGE_TYPE_DIR:
+ case VIR_STORAGE_TYPE_NETWORK:
+ case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NVME:
+ case VIR_STORAGE_TYPE_VHOST_USER:
+ case VIR_STORAGE_TYPE_VHOST_VDPA:
+ case VIR_STORAGE_TYPE_LAST:
+ case VIR_STORAGE_TYPE_NONE:
+ break;
+ }
+
+ return 0;
+}
+
+int
+bhyveProcessPrepareHost(bhyveConn *driver,
+ virDomainDef *def,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (bhyvePrepareNVRAM(driver, def) < 0)
+ return -1;
+
+ return 0;
+}
+
int
virBhyveProcessStart(bhyveConn *driver,
virConnectPtr conn,
@@ -292,6 +421,9 @@ virBhyveProcessStart(bhyveConn *driver,
if (bhyveProcessPrepareDomain(driver, vm, flags) < 0)
return -1;
+ if (bhyveProcessPrepareHost(driver, vm->def, flags) < 0)
+ return -1;
+
return virBhyveProcessStartImpl(driver, vm, reason);
}
diff --git a/src/bhyve/bhyve_process.h b/src/bhyve/bhyve_process.h
index e69db41fc2..5e0acc810c 100644
--- a/src/bhyve/bhyve_process.h
+++ b/src/bhyve/bhyve_process.h
@@ -23,10 +23,18 @@
#include "bhyve_utils.h"
+int
+bhyvePrepareNVRAM(bhyveConn *driver,
+ virDomainDef *def);
+
int
bhyveProcessPrepareDomain(bhyveConn *driver,
virDomainObj *vm,
unsigned int flags);
+int
+bhyveProcessPrepareHost(bhyveConn *driver,
+ virDomainDef *def,
+ unsigned int flags);
int virBhyveProcessStart(bhyveConn *driver,
virConnectPtr conn,
--
2.49.0