qemu: add a new video device model 'ramfb'

This device is a very simple framebuffer device supported by qemu that
is mostly intended to use as a boot framebuffer in conjunction with a
vgpu. However, there is also a standalone ramfb device that can be used
as a primary display device and is useful for e.g. aarch64 guests where
different memory mappings between the host and guest can prevent use of
other devices with framebuffers such as virtio-vga.

https://bugzilla.redhat.com/show_bug.cgi?id=1679680 describes the
issues in more detail.

Reviewed-by: Cole Robinson <crobinso@redhat.com>
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
Jonathon Jongsma 2019-09-13 16:20:29 -05:00 committed by Cole Robinson
parent 9bfcf0f62d
commit fd03d0e692
12 changed files with 101 additions and 7 deletions

View File

@ -7032,9 +7032,10 @@ qemu-kvm -net nic,model=? /dev/null
"vbox", "qxl" (<span class="since">since 0.8.6</span>), "vbox", "qxl" (<span class="since">since 0.8.6</span>),
"virtio" (<span class="since">since 1.3.0</span>), "virtio" (<span class="since">since 1.3.0</span>),
"gop" (<span class="since">since 3.2.0</span>), "gop" (<span class="since">since 3.2.0</span>),
"none" (<span class="since">since 4.6.0</span>, or "bochs" "bochs" (<span class="since">since 5.6.0</span>), "ramfb"
(<span class="since">since 5.6.0</span>) (<span class="since">since 5.9.0</span>), or "none"
depending on the hypervisor features available. (<span class="since">since 4.6.0</span>, depending on the hypervisor
features available.
The purpose of the type <code>none</code> is to instruct libvirt not The purpose of the type <code>none</code> is to instruct libvirt not
to add a default video device in the guest (see the paragraph above). to add a default video device in the guest (see the paragraph above).
This legacy behaviour can be inconvenient in cases where GPU mediated This legacy behaviour can be inconvenient in cases where GPU mediated

View File

@ -41,6 +41,15 @@
<libvirt> <libvirt>
<release version="v5.9.0" date="unreleased"> <release version="v5.9.0" date="unreleased">
<section title="New features"> <section title="New features">
<change>
<summary>
qemu: Introduce a new video model of type 'ramfb'
</summary>
<description>
Introduce a new video model type to the domain XML that supports the
<code>ramfb</code> standalone device in qemu.
</description>
</change>
</section> </section>
<section title="Improvements"> <section title="Improvements">
</section> </section>

View File

@ -3598,6 +3598,7 @@
<value>gop</value> <value>gop</value>
<value>none</value> <value>none</value>
<value>bochs</value> <value>bochs</value>
<value>ramfb</value>
</choice> </choice>
</attribute> </attribute>
<group> <group>

View File

@ -748,6 +748,7 @@ VIR_ENUM_IMPL(virDomainVideo,
"gop", "gop",
"none", "none",
"bochs", "bochs",
"ramfb",
); );
VIR_ENUM_IMPL(virDomainVideoVGAConf, VIR_ENUM_IMPL(virDomainVideoVGAConf,
@ -15299,6 +15300,7 @@ virDomainVideoDefaultRAM(const virDomainDef *def,
case VIR_DOMAIN_VIDEO_TYPE_VIRTIO: case VIR_DOMAIN_VIDEO_TYPE_VIRTIO:
case VIR_DOMAIN_VIDEO_TYPE_GOP: case VIR_DOMAIN_VIDEO_TYPE_GOP:
case VIR_DOMAIN_VIDEO_TYPE_NONE: case VIR_DOMAIN_VIDEO_TYPE_NONE:
case VIR_DOMAIN_VIDEO_TYPE_RAMFB:
case VIR_DOMAIN_VIDEO_TYPE_LAST: case VIR_DOMAIN_VIDEO_TYPE_LAST:
default: default:
return 0; return 0;

View File

@ -1399,6 +1399,7 @@ typedef enum {
VIR_DOMAIN_VIDEO_TYPE_GOP, VIR_DOMAIN_VIDEO_TYPE_GOP,
VIR_DOMAIN_VIDEO_TYPE_NONE, VIR_DOMAIN_VIDEO_TYPE_NONE,
VIR_DOMAIN_VIDEO_TYPE_BOCHS, VIR_DOMAIN_VIDEO_TYPE_BOCHS,
VIR_DOMAIN_VIDEO_TYPE_RAMFB,
VIR_DOMAIN_VIDEO_TYPE_LAST VIR_DOMAIN_VIDEO_TYPE_LAST
} virDomainVideoType; } virDomainVideoType;

View File

@ -114,6 +114,7 @@ VIR_ENUM_IMPL(qemuVideo,
"" /* don't support gop */, "" /* don't support gop */,
"" /* 'none' doesn't make sense here */, "" /* 'none' doesn't make sense here */,
"bochs-display", "bochs-display",
"", /* ramfb can't be used with -vga */
); );
VIR_ENUM_DECL(qemuDeviceVideo); VIR_ENUM_DECL(qemuDeviceVideo);
@ -132,6 +133,7 @@ VIR_ENUM_IMPL(qemuDeviceVideo,
"" /* don't support gop */, "" /* don't support gop */,
"" /* 'none' doesn't make sense here */, "" /* 'none' doesn't make sense here */,
"bochs-display", "bochs-display",
"ramfb",
); );
VIR_ENUM_DECL(qemuDeviceVideoSecondary); VIR_ENUM_DECL(qemuDeviceVideoSecondary);
@ -150,6 +152,7 @@ VIR_ENUM_IMPL(qemuDeviceVideoSecondary,
"" /* don't support gop */, "" /* don't support gop */,
"" /* 'none' doesn't make sense here */, "" /* 'none' doesn't make sense here */,
"" /* no secondary device for bochs */, "" /* no secondary device for bochs */,
"" /* no secondary device for ramfb */,
); );
VIR_ENUM_DECL(qemuSoundCodec); VIR_ENUM_DECL(qemuSoundCodec);

View File

@ -5725,6 +5725,7 @@ qemuDomainDeviceDefValidateVideo(const virDomainVideoDef *video)
case VIR_DOMAIN_VIDEO_TYPE_QXL: case VIR_DOMAIN_VIDEO_TYPE_QXL:
case VIR_DOMAIN_VIDEO_TYPE_VIRTIO: case VIR_DOMAIN_VIDEO_TYPE_VIRTIO:
case VIR_DOMAIN_VIDEO_TYPE_BOCHS: case VIR_DOMAIN_VIDEO_TYPE_BOCHS:
case VIR_DOMAIN_VIDEO_TYPE_RAMFB:
case VIR_DOMAIN_VIDEO_TYPE_LAST: case VIR_DOMAIN_VIDEO_TYPE_LAST:
break; break;
} }

View File

@ -936,6 +936,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev,
case VIR_DOMAIN_VIDEO_TYPE_DEFAULT: case VIR_DOMAIN_VIDEO_TYPE_DEFAULT:
case VIR_DOMAIN_VIDEO_TYPE_GOP: case VIR_DOMAIN_VIDEO_TYPE_GOP:
case VIR_DOMAIN_VIDEO_TYPE_NONE: case VIR_DOMAIN_VIDEO_TYPE_NONE:
case VIR_DOMAIN_VIDEO_TYPE_RAMFB:
case VIR_DOMAIN_VIDEO_TYPE_LAST: case VIR_DOMAIN_VIDEO_TYPE_LAST:
return 0; return 0;
} }
@ -1787,8 +1788,10 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
return -1; return -1;
} }
/* ramfb is not a PCI device */
if (def->nvideos > 0 && if (def->nvideos > 0 &&
def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_NONE) { def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_NONE &&
def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_RAMFB) {
/* Because the PIIX3 integrated IDE/USB controllers are /* Because the PIIX3 integrated IDE/USB controllers are
* already at slot 1, when qemu looks for the first free slot * already at slot 1, when qemu looks for the first free slot
* to place the VGA controller (which is always the first * to place the VGA controller (which is always the first
@ -1971,8 +1974,10 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
return -1; return -1;
} }
/* ramfb is not a PCI device */
if (def->nvideos > 0 && if (def->nvideos > 0 &&
def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_NONE) { def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_NONE &&
def->videos[0]->type != VIR_DOMAIN_VIDEO_TYPE_RAMFB) {
/* NB: unlike the pc machinetypes, on q35 machinetypes the /* NB: unlike the pc machinetypes, on q35 machinetypes the
* integrated devices are at slot 0x1f, so when qemu looks for * integrated devices are at slot 0x1f, so when qemu looks for
* the first free slot for the first VGA, it will always be at * the first free slot for the first VGA, it will always be at
@ -2351,7 +2356,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
/* Video devices */ /* Video devices */
for (i = 0; i < def->nvideos; i++) { for (i = 0; i < def->nvideos; i++) {
if (def->videos[i]->type == VIR_DOMAIN_VIDEO_TYPE_NONE) if (def->videos[i]->type == VIR_DOMAIN_VIDEO_TYPE_NONE ||
def->videos[i]->type == VIR_DOMAIN_VIDEO_TYPE_RAMFB)
continue; continue;
if (!virDeviceInfoPCIAddressIsWanted(&def->videos[i]->info)) if (!virDeviceInfoPCIAddressIsWanted(&def->videos[i]->info))

View File

@ -5273,7 +5273,9 @@ qemuProcessStartValidateVideo(virDomainObjPtr vm,
video->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW && video->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_GPU_CCW)) || !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_GPU_CCW)) ||
(video->type == VIR_DOMAIN_VIDEO_TYPE_BOCHS && (video->type == VIR_DOMAIN_VIDEO_TYPE_BOCHS &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_BOCHS_DISPLAY))) { !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_BOCHS_DISPLAY)) ||
(video->type == VIR_DOMAIN_VIDEO_TYPE_RAMFB &&
!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_RAMFB))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("this QEMU does not support '%s' video device"), _("this QEMU does not support '%s' video device"),
virDomainVideoTypeToString(video->type)); virDomainVideoTypeToString(video->type));

View File

@ -0,0 +1,38 @@
LC_ALL=C \
PATH=/bin \
HOME=/tmp/lib/domain--1-QEMUGuest1 \
USER=test \
LOGNAME=test \
XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-i686 \
-name guest=QEMUGuest1,debug-threads=on \
-S \
-object secret,id=masterKey0,format=raw,\
file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
-machine pc,accel=tcg,usb=off,dump-guest-core=off \
-m 1024 \
-overcommit mem-lock=off \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-display none \
-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 \
-drive file=/var/lib/libvirt/images/QEMUGuest1,format=qcow2,if=none,\
id=drive-ide0-0-0,cache=none \
-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1,\
write-cache=on \
-device ramfb,id=video0 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
resourcecontrol=deny \
-msg timestamp=on

View File

@ -0,0 +1,29 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/var/lib/libvirt/images/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='ide' index='0'/>
<video>
<model type='ramfb' />
</video>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -2083,6 +2083,7 @@ mymain(void)
QEMU_CAPS_DEVICE_VIDEO_PRIMARY, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
QEMU_CAPS_VIRTIO_GPU_MAX_OUTPUTS); QEMU_CAPS_VIRTIO_GPU_MAX_OUTPUTS);
DO_TEST_CAPS_LATEST("video-bochs-display-device"); DO_TEST_CAPS_LATEST("video-bochs-display-device");
DO_TEST_CAPS_LATEST("video-ramfb-display-device");
DO_TEST("video-none-device", DO_TEST("video-none-device",
QEMU_CAPS_VNC); QEMU_CAPS_VNC);
DO_TEST_PARSE_ERROR("video-invalid-multiple-devices", NONE); DO_TEST_PARSE_ERROR("video-invalid-multiple-devices", NONE);