diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 4c60392a08d847b2a89ea8fa5d49705b1b94a1a5..a1042a314c6b2e19000b6910f9f043f4fe3f22a7 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4847,6 +4847,14 @@
graphical framebuffer in order to
use this attribute, currently only supported with VNC, Spice and
egl-headless graphics devices.
+
+ Since version 5.10.0, there is an optional
+ ramfb attribute for devices with
+ model='vfio-pci'. Supported values are either
+ on or off (default is 'off'). When
+ enabled, this attribute provides a memory framebuffer device to the
+ guest. This framebuffer will be used as a boot display when a vgpu
+ device is the primary display.
Note: There are also some implications on the usage of guest's
address type depending on the model attribute,
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index e06f892da3931375bd32f118382713bbe7541d37..a83c9ae7a53bcc2563e611ad48d1c4bc94343168 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4779,6 +4779,11 @@
vfio-ap
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f825e521ec87d98b8ef38aeede2fd3b28e3f829c..561e25ff6e4a45d9e91c5d59535377131fc30c40 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -8135,6 +8135,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
g_autofree char *backendStr = NULL;
g_autofree char *model = NULL;
g_autofree char *display = NULL;
+ g_autofree char *ramfb = NULL;
/* @managed can be read from the xml document - it is always an
* attribute of the toplevel element, no matter what type of
@@ -8148,6 +8149,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
rawio = virXMLPropString(node, "rawio");
model = virXMLPropString(node, "model");
display = virXMLPropString(node, "display");
+ ramfb = virXMLPropString(node, "ramfb");
/* @type is passed in from the caller rather than read from the
* xml document, because it is specified in different places for
@@ -8256,6 +8258,15 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
display);
return -1;
}
+
+ if (ramfb &&
+ (mdevsrc->ramfb = virTristateSwitchTypeFromString(ramfb)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown value '%s' for attribute "
+ "'ramfb'"),
+ ramfb);
+ return -1;
+ }
}
switch (def->source.subsys.type) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2f7a006711f6d06d8cbab1e9003aada1d5c783f9..39fb42e29dff861ebfbedf165f837abadfbdd9f1 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -262,6 +262,7 @@ struct _virDomainHostdevSubsysMediatedDev {
int model; /* enum virMediatedDeviceModelType */
int display; /* virTristateSwitch */
char uuidstr[VIR_UUID_STRING_BUFLEN]; /* mediated device's uuid string */
+ int ramfb; /* virTristateSwitch */
};
typedef enum {
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 0f0d9c434f3386ad3fbb5bf6680aceacc1679286..ca1bd125940f265a7c9a42882d249188176a50fa 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5329,6 +5329,19 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager,
}
+static const char *
+qemuBuildHostdevMdevModelTypeString(virDomainHostdevSubsysMediatedDevPtr mdev)
+{
+ /* when the 'ramfb' attribute is set, we must use the nohotplug variant
+ * rather than 'vfio-pci' */
+ if (mdev->model == VIR_MDEV_MODEL_TYPE_VFIO_PCI &&
+ mdev->ramfb == VIR_TRISTATE_SWITCH_ON)
+ return "vfio-pci-nohotplug";
+
+ return virMediatedDeviceModelTypeToString(mdev->model);
+}
+
+
char *
qemuBuildHostdevMediatedDevStr(const virDomainDef *def,
virDomainHostdevDefPtr dev,
@@ -5342,7 +5355,7 @@ qemuBuildHostdevMediatedDevStr(const virDomainDef *def,
if (!(mdevPath = virMediatedDeviceGetSysfsPath(mdevsrc->uuidstr)))
return NULL;
- dev_str = virMediatedDeviceModelTypeToString(mdevsrc->model);
+ dev_str = qemuBuildHostdevMdevModelTypeString(mdevsrc);
if (!dev_str)
return NULL;
@@ -5360,6 +5373,10 @@ qemuBuildHostdevMediatedDevStr(const virDomainDef *def,
if (dev->info->bootIndex)
virBufferAsprintf(&buf, ",bootindex=%u", dev->info->bootIndex);
+ if (mdevsrc->ramfb == VIR_TRISTATE_SWITCH_ON)
+ virBufferAsprintf(&buf, ",ramfb=%s",
+ virTristateSwitchTypeToString(mdevsrc->ramfb));
+
return virBufferContentAndReset(&buf);
}
diff --git a/tests/qemuxml2argvdata/hostdev-mdev-display-ramfb.x86_64-latest.args b/tests/qemuxml2argvdata/hostdev-mdev-display-ramfb.x86_64-latest.args
new file mode 100644
index 0000000000000000000000000000000000000000..30d2f83318d41c20661017df0104bba6f7a34b3b
--- /dev/null
+++ b/tests/qemuxml2argvdata/hostdev-mdev-display-ramfb.x86_64-latest.args
@@ -0,0 +1,37 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest2 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest2/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest2/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest2/.config \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-i686 \
+-name guest=QEMUGuest2,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest2/master-key.aes \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-overcommit mem-lock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot strict=on \
+-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 \
+-vnc 127.0.0.1:0 \
+-device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,\
+vram64_size_mb=0,vgamem_mb=16,max_outputs=1,bus=pci.0,addr=0x2 \
+-device vfio-pci-nohotplug,id=hostdev0,\
+sysfsdev=/sys/bus/mdev/devices/53764d0e-85a0-42b4-af5c-2046b460b1dc,display=on,\
+bus=pci.0,addr=0x3,ramfb=on \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
+resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/hostdev-mdev-display-ramfb.xml b/tests/qemuxml2argvdata/hostdev-mdev-display-ramfb.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2e7851b2b0d311fd627bccc59a7767c028c96246
--- /dev/null
+++ b/tests/qemuxml2argvdata/hostdev-mdev-display-ramfb.xml
@@ -0,0 +1,33 @@
+
+ QEMUGuest2
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-i686
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 09a7254907bb428684d6bdd1b30ae117e9d83a8a..f839d77e8e8d6fd7947476928b4d53f824e3053b 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1605,6 +1605,7 @@ mymain(void)
DO_TEST_PARSE_ERROR("hostdev-mdev-display-missing-graphics",
QEMU_CAPS_DEVICE_VFIO_PCI,
QEMU_CAPS_VFIO_PCI_DISPLAY);
+ DO_TEST_CAPS_LATEST("hostdev-mdev-display-ramfb");
DO_TEST_PARSE_ERROR("hostdev-vfio-zpci-wrong-arch",
QEMU_CAPS_DEVICE_VFIO_PCI);
DO_TEST("hostdev-vfio-zpci",