]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
bhyve: improve loader handling on arm64
authorRoman Bogorodskiy <bogorodskiy@gmail.com>
Fri, 23 Jan 2026 17:59:56 +0000 (18:59 +0100)
committerRoman Bogorodskiy <bogorodskiy@gmail.com>
Thu, 12 Feb 2026 18:18:35 +0000 (19:18 +0100)
Bhyve on arm64 does not have the bhyveload(8) tool.
That means that it cannot be used as a default if the loader is not
configured for the domain.

To prevent users from getting unusable configurations, handle loader
configuration on arm64 like that:

 - if loader is specified in the domain XML, just use it
 - if not specified, try to check whether the default uboot loader
   is available on the system. In case it is, set is as the loader,
   otherwise fail with the error.

Additionally, the loader could be configured in bhyve.conf.
By default, it uses the loader installed by the
sysutils/u-boot-bhyve-arm64 port or a corresponding package.

Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
15 files changed:
src/bhyve/bhyve.conf
src/bhyve/bhyve_conf.c
src/bhyve/bhyve_domain.c
src/bhyve/bhyve_utils.h
src/bhyve/libvirtd_bhyve.aug
src/bhyve/test_libvirtd_bhyve.aug.in
tests/bhyvexml2argvdata/aarch64/bhyvexml2argv-base.args
tests/bhyvexml2argvdata/aarch64/bhyvexml2argv-base.ldargs
tests/bhyvexml2argvdata/aarch64/bhyvexml2argv-console.args
tests/bhyvexml2argvdata/aarch64/bhyvexml2argv-console.ldargs
tests/bhyvexml2argvmock.c
tests/bhyvexml2argvtest.c
tests/bhyvexml2xmloutdata/aarch64/bhyvexml2xmlout-base.xml
tests/bhyvexml2xmloutdata/aarch64/bhyvexml2xmlout-console.xml
tests/bhyvexml2xmltest.c

index dc8d3d8fd898aee978b3e8f00ac9ab66d38de1b7..a845937d877b7e0cbb43c136b6b1292cf5a42a7f 100644 (file)
@@ -6,6 +6,11 @@
 # to the directory that sysutils/bhyve-firmware installs files into.
 #firmware_dir = "/usr/local/share/uefi-firmware"
 
+# Path to the U-Boot loader for the arm64 guests.
+# By default it's pointing to the loader installed
+# by the sysutils/u-boot-bhyve-arm64 port
+#uboot_path = "/usr/local/share/u-boot/u-boot-bhyve-arm64/u-boot.bin"
+
 # Set timeout for the bhyveload(8) command. This might be necessary
 # because in case of errors bhyveload(8) drops to an interactive
 # loader and hangs indefinitely. These timeout values are passed
index 182e00ee1d676bd1a45de29ba55ca391e95752cf..f9a657f402bb0fdf9c9f58a75c7e9a129beb9f28 100644 (file)
@@ -61,6 +61,8 @@ virBhyveDriverConfigNew(void)
     cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR);
     cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir);
 
+    cfg->ubootPath = g_strdup(DATADIR "/u-boot/u-boot-bhyve-arm64/u-boot.bin");
+
     cfg->bhyveloadTimeout = 300;
     cfg->bhyveloadTimeoutKill = 15;
 
@@ -85,6 +87,10 @@ virBhyveLoadDriverConfig(struct _virBhyveDriverConfig *cfg,
                               &cfg->firmwareDir) < 0)
         return -1;
 
+    if (virConfGetValueString(conf, "uboot_path",
+                              &cfg->ubootPath) < 0)
+        return -1;
+
     if (virConfGetValueInt(conf, "bhyveload_timeout",
                            &cfg->bhyveloadTimeout) < 0)
         return -1;
@@ -111,6 +117,8 @@ virBhyveDriverConfigDispose(void *obj)
     g_free(cfg->firmwareDir);
     g_free(cfg->libDir);
     g_free(cfg->nvramDir);
+
+    g_free(cfg->ubootPath);
 }
 
 void
index df0a008ecde2a9b92747bc9e5ee5bc89b833de3c..8fc97337566b42ecad2e636957a7a6965545e326 100644 (file)
@@ -27,6 +27,7 @@
 #include "bhyve_domain.h"
 #include "bhyve_capabilities.h"
 #include "viralloc.h"
+#include "virfile.h"
 #include "virlog.h"
 #include "virutil.h"
 
@@ -112,6 +113,28 @@ bhyveDomainDefPostParse(virDomainDef *def,
         !(bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_RTC_UTC))
         def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
 
+    /* bhyve/arm64 does not provide the bhyveload(8) tool,
+     * so if the loader is not specified and we cannot fall back to the
+     * default one, then this results in an unusable configuration. */
+    if (ARCH_IS_ARM(def->os.arch)) {
+        if (def->os.loader == NULL) {
+            g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(driver);
+            char *uboot_path = cfg->ubootPath;
+
+            if (virFileExists(uboot_path)) {
+                def->os.loader = virDomainLoaderDefNew();
+                def->os.loader->path = g_strdup(uboot_path);
+                def->os.loader->readonly = true;
+                def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
+            } else {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("loader is not specified and the default loader (%1$s) not found"),
+                               uboot_path);
+                return -1;
+            }
+        }
+    }
+
     return 0;
 }
 
index 8ed1fa550944b6c6b32c428a4ce8ce6e7ec766dd..19369047fef2b7ff93deab5685068abc279844e6 100644 (file)
@@ -42,6 +42,8 @@ struct _virBhyveDriverConfig {
     char *libDir;
     char *nvramDir;
 
+    char *ubootPath;
+
     int bhyveloadTimeout;
     int bhyveloadTimeoutKill;
 };
index 0fd74d4bb3f6759cad8530ce2d2c5370766abcae..00e0db02853393bbd63ae8b42800c6b3509876d5 100644 (file)
@@ -25,9 +25,10 @@ module Libvirtd_bhyve =
    let log_entry = str_entry "firmware_dir"
    let bhyveload_timeout = int_entry "bhyveload_timeout"
    let bhyveload_timeout_kill = int_entry "bhyveload_timeout_kill"
+   let uboot_path = str_entry "uboot_path"
 
    (* Each entry in the config is one of the following three ... *)
-   let entry = log_entry | bhyveload_timeout | bhyveload_timeout_kill
+   let entry = log_entry | bhyveload_timeout | bhyveload_timeout_kill | uboot_path
    let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
    let empty = [ label "#empty" . eol ]
 
index 391648e71fa8d1392ff2c85903ccaac8104a09bc..371f11ef82c5931c8975df6c8c53e21747142d68 100644 (file)
@@ -3,5 +3,6 @@ module Test_libvirtd_bhyve =
 
   test Libvirtd_bhyve.lns get conf =
 { "firmware_dir" = "/usr/local/share/uefi-firmware" }
+{ "uboot_path" = "/usr/local/share/u-boot/u-boot-bhyve-arm64/u-boot.bin" }
 { "bhyveload_timeout" = "300" }
 { "bhyveload_timeout_kill" = "15" }
index aef3ebd01782086211fc28be4421debb567c1269..37292aa3fe48d2eb4e6292f4dd6ddf8d503539a4 100644 (file)
@@ -2,6 +2,7 @@ bhyve \
 -c 1 \
 -m 214 \
 -s 0:0,hostbridge \
+-o bootrom=fakeubootpath/u-boot.bin \
 -s 3:0,virtio-net,faketapdev,mac=52:54:00:b9:94:02 \
 -s 2:0,virtio-blk,/tmp/freebsd.img \
 bhyve
index 264ae48441d65208ca04107537505a77a9a14680..421376db9e8aee847e9d774891e73098a7415e94 100644 (file)
@@ -1,7 +1 @@
-timeout \
---foreground \
---verbose \
--k 20s 300s bhyveload \
--m 214 \
--d /tmp/freebsd.img \
-bhyve
+dummy
index 4a031afb71881be539815e42bd88054d60deedcb..afd5f5d7b251cbd901115daa7521ac30eeabe4cf 100644 (file)
@@ -2,6 +2,7 @@ bhyve \
 -c 1 \
 -m 214 \
 -s 0:0,hostbridge \
+-o bootrom=fakeubootpath/u-boot.bin \
 -s 3:0,virtio-net,faketapdev,mac=52:54:00:b9:94:02 \
 -s 2:0,virtio-blk,/tmp/freebsd.img \
 -o console=/dev/nmdm0A \
index 264ae48441d65208ca04107537505a77a9a14680..421376db9e8aee847e9d774891e73098a7415e94 100644 (file)
@@ -1,7 +1 @@
-timeout \
---foreground \
---verbose \
--k 20s 300s bhyveload \
--m 214 \
--d /tmp/freebsd.img \
-bhyve
+dummy
index 7dbdd486827221c9ca7214978f1663e99acc6eec..2248b721d09605e5055fbe70348aaee82e4c443a 100644 (file)
@@ -2,7 +2,9 @@
 
 #include <dirent.h>
 
+#include "configmake.h"
 #include "viralloc.h"
+#include "virfile.h"
 #include "virstring.h"
 #include "virnetdev.h"
 #include "virnetdevtap.h"
 #define VIR_FROM_THIS VIR_FROM_BHYVE
 
 static DIR * (*real_opendir)(const char *name);
+static bool (*real_virFileExists)(const char *path);
 
 static void
 init_syms(void)
 {
-    VIR_MOCK_REAL_INIT(opendir);
+    if (!real_opendir)
+        VIR_MOCK_REAL_INIT(opendir);
+
+    if (!real_virFileExists)
+        VIR_MOCK_REAL_INIT(virFileExists);
 }
 
 #define FAKEFIRMWAREDIR abs_srcdir "/bhyvefirmwaredata/three_firmwares"
@@ -97,3 +104,14 @@ virCPUProbeHost(virArch arch)
 {
     return testUtilsHostCpusGetDefForArch(arch);
 }
+
+bool
+virFileExists(const char *path)
+{
+    init_syms();
+
+    if (STREQ(path, "fakeubootpath/u-boot.bin"))
+        return true;
+
+    return real_virFileExists(path);
+}
index 7dc97daf4fa22dd45edf58dfd5756d3043e4df8f..21d568088483cc49d1e9cd92db7d067744bcc54c 100644 (file)
@@ -151,6 +151,7 @@ mymain(void)
     g_autofree char *fakefirmwaredir = g_strdup("fakefirmwaredir");
     g_autofree char *fakenvramdir = g_strdup("fakenvramdir");
     g_autofree char *fakefirmwareemptydir = g_strdup("fakefirmwareemptydir");
+    g_autofree char *fakeubootpath = g_strdup("fakeubootpath/u-boot.bin");
 
     if ((driver.caps = virBhyveCapsBuild()) == NULL)
         return EXIT_FAILURE;
@@ -166,8 +167,10 @@ mymain(void)
 
     VIR_FREE(driver.config->firmwareDir);
     VIR_FREE(driver.config->nvramDir);
+    VIR_FREE(driver.config->ubootPath);
     driver.config->firmwareDir = g_steal_pointer(&fakefirmwaredir);
     driver.config->nvramDir = g_steal_pointer(&fakenvramdir);
+    driver.config->ubootPath = g_steal_pointer(&fakeubootpath);
     driver.config->bhyveloadTimeout = 0;
     driver.config->bhyveloadTimeoutKill = 0;
 
index ee72370047f9f516b81829f06bfec092c3d35ba4..b2d88789c82b673d7391111b25bbdb9a3db482db 100644 (file)
@@ -6,6 +6,7 @@
   <vcpu placement='static'>1</vcpu>
   <os>
     <type arch='aarch64'>hvm</type>
+    <loader readonly='yes' type='pflash'>fakeubootpath/u-boot.bin</loader>
     <boot dev='hd'/>
   </os>
   <clock offset='localtime'/>
index d43ce8fd6f5934cab0a1294a646d2763863dc460..741570a5b5c1e6990e9230843260d5e7b063bce4 100644 (file)
@@ -6,6 +6,7 @@
   <vcpu placement='static'>1</vcpu>
   <os>
     <type arch='aarch64'>hvm</type>
+    <loader readonly='yes' type='pflash'>fakeubootpath/u-boot.bin</loader>
     <boot dev='hd'/>
   </os>
   <clock offset='localtime'/>
index 9e3bd6c45fc8f394ebc2ec574c71dfad6d475575..7f9de2bc36cba7f52fe05513660e555bfa156908 100644 (file)
@@ -5,6 +5,7 @@
 #ifdef WITH_BHYVE
 
 # include "bhyve/bhyve_capabilities.h"
+# include "bhyve/bhyve_conf.h"
 # include "bhyve/bhyve_domain.h"
 # include "bhyve/bhyve_utils.h"
 
@@ -55,6 +56,7 @@ testCompareXMLToXMLHelper(const void *data)
 static int
 mymain(void)
 {
+    g_autofree char *fakeubootpath = g_strdup("fakeubootpath/u-boot.bin");
     int ret = 0;
 
     if ((driver.caps = virBhyveCapsBuild()) == NULL)
@@ -63,6 +65,11 @@ mymain(void)
     if ((driver.xmlopt = virBhyveDriverCreateXMLConf(&driver)) == NULL)
         return EXIT_FAILURE;
 
+    if (!(driver.config = virBhyveDriverConfigNew()))
+        return EXIT_FAILURE;
+
+    driver.config->ubootPath = fakeubootpath;
+
 # define DO_TEST_FULL(name, flags) \
     do { \
         const struct testInfo info = {name, (flags)}; \