diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 3095111c4bb729d207a7478da852d0cf2128fc78..9a204f845c12f06c2a3fa6346d8d7d8a8c275c3b 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -5891,8 +5891,9 @@ qemu-kvm -net nic,model=? /dev/null
The model
element has a mandatory type
attribute which takes the value "vga", "cirrus", "vmvga", "xen",
- "vbox", "qxl" (since 0.8.6) or
+ "vbox", "qxl" (since 0.8.6),
"virtio" (since 1.3.0)
+ or "gop" (since 3.2.0)
depending on the hypervisor features available.
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 1860f9075b725f3e53e7ce6d88f082640843d058..5e593285efd0d9cdc35b1e05a55e9fc015d14fa2 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3166,6 +3166,7 @@
xen
vbox
virtio
+ gop
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c8d01147bff38d24d4361fde16aa95779c9792ec..bd831a37c990e4dabba1b995a730a093e03100df 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,6 +12,7 @@ gnulib/lib/getopt.c
gnulib/lib/regcomp.c
src/access/viraccessdriverpolkit.c
src/access/viraccessmanager.c
+src/bhyve/bhyve_capabilities.c
src/bhyve/bhyve_command.c
src/bhyve/bhyve_device.c
src/bhyve/bhyve_domain.c
diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c
index 6f686a9af01dcc6a72138fcbda9345470ee0296d..5e6094e3c0ec4ba6c69d9ccb65dcdf3d98647594 100644
--- a/src/bhyve/bhyve_capabilities.c
+++ b/src/bhyve/bhyve_capabilities.c
@@ -117,6 +117,7 @@ virBhyveDomainCapsBuild(const char *emulatorbin,
virDomainVirtType virttype)
{
virDomainCapsPtr caps = NULL;
+ unsigned int bhyve_caps = 0;
DIR *dir;
struct dirent *entry;
const char *firmware_dir = "/usr/local/share/uefi-firmware";
@@ -125,6 +126,12 @@ virBhyveDomainCapsBuild(const char *emulatorbin,
if (!(caps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
goto cleanup;
+ if (virBhyveProbeCaps(&bhyve_caps)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed probing capabilities"));
+ goto cleanup;
+ }
+
caps->os.supported = true;
caps->os.loader.supported = true;
VIR_DOMAIN_CAPS_ENUM_SET(caps->os.loader.type,
@@ -155,6 +162,12 @@ virBhyveDomainCapsBuild(const char *emulatorbin,
VIR_DOMAIN_DISK_BUS_SATA,
VIR_DOMAIN_DISK_BUS_VIRTIO);
+ if (bhyve_caps & BHYVE_CAP_FBUF) {
+ caps->graphics.supported = true;
+ caps->video.supported = true;
+ VIR_DOMAIN_CAPS_ENUM_SET(caps->graphics.type, VIR_DOMAIN_GRAPHICS_TYPE_VNC);
+ VIR_DOMAIN_CAPS_ENUM_SET(caps->video.modelType, VIR_DOMAIN_VIDEO_TYPE_GOP);
+ }
cleanup:
VIR_DIR_CLOSE(dir);
return caps;
@@ -290,6 +303,30 @@ bhyveProbeCapsLPC_Bootrom(unsigned int *caps, char *binary)
return ret;
}
+
+static int
+bhyveProbeCapsFramebuffer(unsigned int *caps, char *binary)
+{
+ char *error;
+ virCommandPtr cmd = NULL;
+ int ret = -1, exit;
+
+ cmd = virCommandNew(binary);
+ virCommandAddArgList(cmd, "-s", "0,fbuf", NULL);
+ virCommandSetErrorBuffer(cmd, &error);
+ if (virCommandRun(cmd, &exit) < 0)
+ goto cleanup;
+
+ if (strstr(error, "pci slot 0:0: unknown device \"fbuf\"") == NULL)
+ *caps |= BHYVE_CAP_FBUF;
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(error);
+ virCommandFree(cmd);
+ return ret;
+}
+
int
virBhyveProbeCaps(unsigned int *caps)
{
@@ -314,6 +351,9 @@ virBhyveProbeCaps(unsigned int *caps)
if ((ret = bhyveProbeCapsLPC_Bootrom(caps, binary)))
goto out;
+ if ((ret = bhyveProbeCapsFramebuffer(caps, binary)))
+ goto out;
+
out:
VIR_FREE(binary);
return ret;
diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h
index 746c77181b05c847f979010d00f77361f709504f..8fb97d73019a97ebc6f642f71693e3bac56b030e 100644
--- a/src/bhyve/bhyve_capabilities.h
+++ b/src/bhyve/bhyve_capabilities.h
@@ -41,6 +41,7 @@ typedef enum {
BHYVE_CAP_AHCI32SLOT = 1 << 1,
BHYVE_CAP_NET_E1000 = 1 << 2,
BHYVE_CAP_LPC_BOOTROM = 1 << 3,
+ BHYVE_CAP_FBUF = 1 << 4,
} virBhyveCapsFlags;
int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps);
diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index 4508009209b634c07e7604a2bcceadca2b7f38d6..ec7a71572eb1ee8661e144e70badcf29dad321ae 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -290,6 +290,94 @@ bhyveBuildLPCArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
return 0;
}
+static int
+bhyveBuildGraphicsArgStr(const virDomainDef *def ATTRIBUTE_UNUSED,
+ virDomainGraphicsDefPtr graphics,
+ virDomainVideoDefPtr video,
+ virConnectPtr conn,
+ virCommandPtr cmd)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ virDomainGraphicsListenDefPtr glisten = NULL;
+ bool escapeAddr;
+
+ if (!(bhyveDriverGetCaps(conn) & BHYVE_CAP_LPC_BOOTROM) ||
+ def->os.bootloader ||
+ !def->os.loader) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Graphics are only supported"
+ " when booting using UEFI"));
+ return -1;
+ }
+
+ if (!(bhyveDriverGetCaps(conn) & BHYVE_CAP_FBUF)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Bhyve version does not support framebuffer"));
+ return -1;
+ }
+
+ if (graphics->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Only VNC supported"));
+ return -1;
+ }
+
+ if (!(glisten = virDomainGraphicsGetListen(graphics, 0))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing listen element"));
+ goto error;
+ }
+
+ virBufferAsprintf(&opt, "%d:%d,fbuf", video->info.addr.pci.slot, video->info.addr.pci.function);
+
+ switch (glisten->type) {
+ case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
+ case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
+ virBufferAddLit(&opt, ",tcp=");
+
+ if (!graphics->data.vnc.autoport &&
+ (graphics->data.vnc.port < 5900 ||
+ graphics->data.vnc.port > 65535)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("vnc port must be in range [5900,65535]"));
+ goto error;
+ }
+
+ if (graphics->data.vnc.auth.passwd) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("vnc password auth not supported"));
+ goto error;
+ } else {
+ /* Bhyve doesn't support VNC Auth yet, so print a warning about
+ * unauthenticated VNC sessions */
+ VIR_WARN("%s", _("Security warning: currently VNC auth is not"
+ " supported."));
+ }
+
+ if (glisten->address) {
+ escapeAddr = strchr(glisten->address, ':') != NULL;
+ if (escapeAddr)
+ virBufferAsprintf(&opt, "[%s]", glisten->address);
+ else
+ virBufferAdd(&opt, glisten->address, -1);
+ }
+
+ virBufferAsprintf(&opt, ":%d", graphics->data.vnc.port);
+ break;
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Unsupported listen type"));
+ }
+
+ virCommandAddArg(cmd, "-s");
+ virCommandAddArgBuffer(cmd, &opt);
+ return 0;
+
+ error:
+ virBufferFreeAndReset(&opt);
+ return -1;
+}
+
virCommandPtr
virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
virDomainDefPtr def, bool dryRun)
@@ -413,6 +501,18 @@ virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
}
}
+ if (def->ngraphics && def->nvideos) {
+ if (def->ngraphics == 1 && def->nvideos == 1) {
+ if (bhyveBuildGraphicsArgStr(def, def->graphics[0], def->videos[0], conn, cmd) < 0)
+ goto error;
+ add_lpc = true;
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Multiple graphics devices are not supported"));
+ goto error;
+ }
+ }
+
if (add_lpc || def->nserials)
bhyveBuildLPCArgStr(def, cmd);
diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c
index 55ce631ec464d04e08472f223db5843c15f6a8a7..a3a263b7e27954ec1bee8275f267a0026e18014d 100644
--- a/src/bhyve/bhyve_device.c
+++ b/src/bhyve/bhyve_device.c
@@ -145,6 +145,17 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def,
goto error;
}
+ for (i = 0; i < def->nvideos; i++) {
+ if (!virDeviceInfoPCIAddressWanted(&def->videos[i]->info))
+ continue;
+ if (virDomainPCIAddressReserveNextAddr(addrs,
+ &def->videos[i]->info,
+ VIR_PCI_CONNECT_TYPE_PCI_DEVICE,
+ -1) < 0)
+ goto error;
+ }
+
+
return 0;
error:
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 569becb99d74ca8fa0ff66149154891519ee8451..88d419e27d46bdb7f70ce72fdcee2e501a699bb6 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -545,7 +545,8 @@ VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
"vbox",
"qxl",
"parallels",
- "virtio")
+ "virtio",
+ "gop")
VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
"mouse",
@@ -13049,6 +13050,8 @@ virDomainVideoDefaultType(const virDomainDef *def)
return VIR_DOMAIN_VIDEO_TYPE_VGA;
else
return VIR_DOMAIN_VIDEO_TYPE_PARALLELS;
+ case VIR_DOMAIN_VIRT_BHYVE:
+ return VIR_DOMAIN_VIDEO_TYPE_GOP;
default:
return -1;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1e53cc3280212f3d5fdf5244e0f2782728fe89b6..b788a827102342d1d3b867987212b2c349d8bf11 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1335,6 +1335,7 @@ typedef enum {
VIR_DOMAIN_VIDEO_TYPE_QXL,
VIR_DOMAIN_VIDEO_TYPE_PARALLELS, /* pseudo device for VNC in containers */
VIR_DOMAIN_VIDEO_TYPE_VIRTIO,
+ VIR_DOMAIN_VIDEO_TYPE_GOP,
VIR_DOMAIN_VIDEO_TYPE_LAST
} virDomainVideoType;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 145a0127f2728056886ffac79af09ff0990a3998..b484b7ba0716559d42af5f34c595f81d4fbd1209 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -101,7 +101,8 @@ VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
"", /* don't support vbox */
"qxl",
"", /* don't support parallels */
- "" /* no need for virtio */);
+ "", /* no need for virtio */
+ "" /* don't support gop */);
VIR_ENUM_DECL(qemuDeviceVideo)
@@ -113,7 +114,8 @@ VIR_ENUM_IMPL(qemuDeviceVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
"", /* don't support vbox */
"qxl-vga",
"", /* don't support parallels */
- "virtio-vga");
+ "virtio-vga",
+ "" /* don't support gop */);
VIR_ENUM_DECL(qemuDeviceVideoSecondary)
@@ -125,7 +127,8 @@ VIR_ENUM_IMPL(qemuDeviceVideoSecondary, VIR_DOMAIN_VIDEO_TYPE_LAST,
"", /* don't support vbox */
"qxl",
"", /* don't support parallels */
- "virtio-gpu-pci");
+ "virtio-gpu-pci",
+ "" /* don't support gop */);
VIR_ENUM_DECL(qemuSoundCodec)
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 20f4ba25bbe6d771b7e95d4854795b0983cb8b1e..64aa4efa6b2b37d8e1f52263dc7e4502d6001d7c 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -742,6 +742,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev,
case VIR_DOMAIN_VIDEO_TYPE_PARALLELS:
return pciFlags;
+ case VIR_DOMAIN_VIDEO_TYPE_GOP:
case VIR_DOMAIN_VIDEO_TYPE_LAST:
return 0;
}
diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml
index 6abd4995aa5d9139cd5b5f37439b0cd67a49312e..6a676253c38e7b6f2c2354b21ea788ad02a3efe5 100644
--- a/tests/domaincapsschemadata/full.xml
+++ b/tests/domaincapsschemadata/full.xml
@@ -70,6 +70,7 @@
qxl
parallels
virtio
+ gop