]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
bhyve: generate NVRAM bhyve arguments
authorRoman Bogorodskiy <bogorodskiy@gmail.com>
Wed, 7 May 2025 18:25:56 +0000 (20:25 +0200)
committerRoman Bogorodskiy <bogorodskiy@gmail.com>
Tue, 20 May 2025 16:24:52 +0000 (18:24 +0200)
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@gmail.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/bhyve/bhyve_command.c
src/bhyve/bhyve_process.c
src/bhyve/bhyve_process.h

index 44c66ea147bbdd5f951fb06ef2c8779a8785887f..cd1ccf61f3a05c9406ab31061354ea5131d40a57 100644 (file)
@@ -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"));
index a17994e2a07acd3713acdc9995fe50854bcfdf96..5e77a9c4d68763a36082e516f75733963b20883c 100644 (file)
@@ -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);
 }
 
index e69db41fc26f00fbf257514a85034cc74b551b3d..5e0acc810c8ed00b9ca03b58ef81727342f49882 100644 (file)
 
 #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,