提交 b4a5fd95 编写于 作者: P Pavel Hrdina

qemu: introduce vram64 attribute for QXL video device

This attribute is used to extend secondary PCI bar and expose it to the
guest as 64bit memory.  It works like this: attribute vram is there to
set size of secondary PCI bar and guest sees it as 32bit memory,
attribute vram64 can extend this secondary PCI bar.  If both attributes
are used, guest sees two memory bars, both address the same memory, with
the difference that the 32bit bar can address only the first part of the
whole memory.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1260749Signed-off-by: NPavel Hrdina <phrdina@redhat.com>
上级 37b74633
...@@ -5200,6 +5200,8 @@ qemu-kvm -net nic,model=? /dev/null ...@@ -5200,6 +5200,8 @@ qemu-kvm -net nic,model=? /dev/null
two as <code>vram</code>. There is also optional attribute two as <code>vram</code>. There is also optional attribute
<code>vgamem</code> (<span class="since">since 1.2.11</span>) to set <code>vgamem</code> (<span class="since">since 1.2.11</span>) to set
the size of VGA framebuffer for fallback mode of QXL device. the size of VGA framebuffer for fallback mode of QXL device.
Attribute <code>vram64</code> (<span class="since">since 1.3.2</span>)
extends secondary bar and makes it addressable as 64bit memory.
</p> </p>
</dd> </dd>
......
...@@ -2946,6 +2946,11 @@ ...@@ -2946,6 +2946,11 @@
<ref name="unsignedInt"/> <ref name="unsignedInt"/>
</attribute> </attribute>
</optional> </optional>
<optional>
<attribute name="vram64">
<ref name="unsignedInt"/>
</attribute>
</optional>
</group> </group>
</choice> </choice>
<optional> <optional>
......
...@@ -11918,6 +11918,7 @@ virDomainVideoDefParseXML(xmlNodePtr node, ...@@ -11918,6 +11918,7 @@ virDomainVideoDefParseXML(xmlNodePtr node,
char *type = NULL; char *type = NULL;
char *heads = NULL; char *heads = NULL;
char *vram = NULL; char *vram = NULL;
char *vram64 = NULL;
char *ram = NULL; char *ram = NULL;
char *vgamem = NULL; char *vgamem = NULL;
char *primary = NULL; char *primary = NULL;
...@@ -11933,6 +11934,7 @@ virDomainVideoDefParseXML(xmlNodePtr node, ...@@ -11933,6 +11934,7 @@ virDomainVideoDefParseXML(xmlNodePtr node,
type = virXMLPropString(cur, "type"); type = virXMLPropString(cur, "type");
ram = virXMLPropString(cur, "ram"); ram = virXMLPropString(cur, "ram");
vram = virXMLPropString(cur, "vram"); vram = virXMLPropString(cur, "vram");
vram64 = virXMLPropString(cur, "vram64");
vgamem = virXMLPropString(cur, "vgamem"); vgamem = virXMLPropString(cur, "vgamem");
heads = virXMLPropString(cur, "heads"); heads = virXMLPropString(cur, "heads");
...@@ -11987,6 +11989,19 @@ virDomainVideoDefParseXML(xmlNodePtr node, ...@@ -11987,6 +11989,19 @@ virDomainVideoDefParseXML(xmlNodePtr node,
def->vram = virDomainVideoDefaultRAM(dom, def->type); def->vram = virDomainVideoDefaultRAM(dom, def->type);
} }
if (vram64) {
if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("vram64 attribute only supported for type of qxl"));
goto error;
}
if (virStrToLong_uip(vram64, NULL, 10, &def->vram64) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("cannot parse video vram64 '%s'"), vram64);
goto error;
}
}
if (vgamem) { if (vgamem) {
if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) { if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
virReportError(VIR_ERR_XML_ERROR, "%s", virReportError(VIR_ERR_XML_ERROR, "%s",
...@@ -12013,9 +12028,11 @@ virDomainVideoDefParseXML(xmlNodePtr node, ...@@ -12013,9 +12028,11 @@ virDomainVideoDefParseXML(xmlNodePtr node,
if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
goto error; goto error;
cleanup:
VIR_FREE(type); VIR_FREE(type);
VIR_FREE(ram); VIR_FREE(ram);
VIR_FREE(vram); VIR_FREE(vram);
VIR_FREE(vram64);
VIR_FREE(vgamem); VIR_FREE(vgamem);
VIR_FREE(heads); VIR_FREE(heads);
...@@ -12023,12 +12040,8 @@ virDomainVideoDefParseXML(xmlNodePtr node, ...@@ -12023,12 +12040,8 @@ virDomainVideoDefParseXML(xmlNodePtr node,
error: error:
virDomainVideoDefFree(def); virDomainVideoDefFree(def);
VIR_FREE(type); def = NULL;
VIR_FREE(ram); goto cleanup;
VIR_FREE(vram);
VIR_FREE(vgamem);
VIR_FREE(heads);
return NULL;
} }
static virDomainHostdevDefPtr static virDomainHostdevDefPtr
...@@ -17041,6 +17054,13 @@ virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src, ...@@ -17041,6 +17054,13 @@ virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src,
return false; return false;
} }
if (src->vram64 != dst->vram64) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target video card vram64 %u does not match source %u"),
dst->vram64, src->vram64);
return false;
}
if (src->vgamem != dst->vgamem) { if (src->vgamem != dst->vgamem) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target video card vgamem %u does not match source %u"), _("Target video card vgamem %u does not match source %u"),
...@@ -20726,6 +20746,8 @@ virDomainVideoDefFormat(virBufferPtr buf, ...@@ -20726,6 +20746,8 @@ virDomainVideoDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " ram='%u'", def->ram); virBufferAsprintf(buf, " ram='%u'", def->ram);
if (def->vram) if (def->vram)
virBufferAsprintf(buf, " vram='%u'", def->vram); virBufferAsprintf(buf, " vram='%u'", def->vram);
if (def->vram64)
virBufferAsprintf(buf, " vram64='%u'", def->vram64);
if (def->vgamem) if (def->vgamem)
virBufferAsprintf(buf, " vgamem='%u'", def->vgamem); virBufferAsprintf(buf, " vgamem='%u'", def->vgamem);
if (def->heads) if (def->heads)
......
...@@ -1399,6 +1399,7 @@ struct _virDomainVideoDef { ...@@ -1399,6 +1399,7 @@ struct _virDomainVideoDef {
int type; int type;
unsigned int ram; /* kibibytes (multiples of 1024) */ unsigned int ram; /* kibibytes (multiples of 1024) */
unsigned int vram; /* kibibytes (multiples of 1024) */ unsigned int vram; /* kibibytes (multiples of 1024) */
unsigned int vram64; /* kibibytes (multiples of 1024) */
unsigned int vgamem; /* kibibytes (multiples of 1024) */ unsigned int vgamem; /* kibibytes (multiples of 1024) */
unsigned int heads; unsigned int heads;
bool primary; bool primary;
......
...@@ -3346,6 +3346,14 @@ qemuBuildDeviceVideoStr(virDomainDefPtr def, ...@@ -3346,6 +3346,14 @@ qemuBuildDeviceVideoStr(virDomainDefPtr def,
virBufferAsprintf(&buf, ",vram_size=%u", video->vram * 1024); virBufferAsprintf(&buf, ",vram_size=%u", video->vram * 1024);
} }
if ((video->primary &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VRAM64)) ||
(!video->primary &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VRAM64))) {
/* QEMU accepts mebibytes for vram64_size_mb. */
virBufferAsprintf(&buf, ",vram64_size_mb=%u", video->vram64 / 1024);
}
if ((video->primary && if ((video->primary &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) || virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) ||
(!video->primary && (!video->primary &&
...@@ -8272,6 +8280,7 @@ qemuBuildCommandLine(virConnectPtr conn, ...@@ -8272,6 +8280,7 @@ qemuBuildCommandLine(virConnectPtr conn,
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
unsigned int ram = def->videos[0]->ram; unsigned int ram = def->videos[0]->ram;
unsigned int vram = def->videos[0]->vram; unsigned int vram = def->videos[0]->vram;
unsigned int vram64 = def->videos[0]->vram64;
unsigned int vgamem = def->videos[0]->vgamem; unsigned int vgamem = def->videos[0]->vgamem;
if (vram > (UINT_MAX / 1024)) { if (vram > (UINT_MAX / 1024)) {
...@@ -8297,6 +8306,12 @@ qemuBuildCommandLine(virConnectPtr conn, ...@@ -8297,6 +8306,12 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandAddArgFormat(cmd, "%s.vram_size=%u", virCommandAddArgFormat(cmd, "%s.vram_size=%u",
dev, vram * 1024); dev, vram * 1024);
} }
if (vram64 &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VRAM64)) {
virCommandAddArg(cmd, "-global");
virCommandAddArgFormat(cmd, "%s.vram64_size_mb=%u",
dev, vram64 / 1024);
}
if (vgamem && if (vgamem &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) { virQEMUCapsGet(qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) {
virCommandAddArg(cmd, "-global"); virCommandAddArg(cmd, "-global");
......
...@@ -1154,6 +1154,41 @@ qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon, ...@@ -1154,6 +1154,41 @@ qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon,
} }
/**
* To update video vram64 size in status XML we need to load correct value from
* QEMU. This is supported only with JSON monitor.
*
* Returns 0 on success, -1 on failure and sets proper error message.
*/
int
qemuMonitorUpdateVideoVram64Size(qemuMonitorPtr mon,
virDomainVideoDefPtr video,
const char *videoName)
{
int ret = -1;
char *path = NULL;
QEMU_CHECK_MONITOR(mon);
if (mon->json) {
ret = qemuMonitorJSONFindLinkPath(mon, videoName, &path);
if (ret < 0) {
if (ret == -2)
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to find QOM Object path for "
"device '%s'"), videoName);
return -1;
}
ret = qemuMonitorJSONUpdateVideoVram64Size(mon, video, path);
VIR_FREE(path);
return ret;
}
return 0;
}
int int
qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon, qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
const char *cmd, const char *cmd,
......
...@@ -269,6 +269,10 @@ int qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon, ...@@ -269,6 +269,10 @@ int qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon,
virDomainVideoDefPtr video, virDomainVideoDefPtr video,
const char *videoName) const char *videoName)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorUpdateVideoVram64Size(qemuMonitorPtr mon,
virDomainVideoDefPtr video,
const char *videoName)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon, int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
const char *cmd, const char *cmd,
int scm_fd, int scm_fd,
......
...@@ -1436,6 +1436,18 @@ qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon, ...@@ -1436,6 +1436,18 @@ qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
return -1; return -1;
} }
video->vram = prop.val.ul / 1024; video->vram = prop.val.ul / 1024;
if (video->vram64 != 0) {
if (qemuMonitorJSONGetObjectProperty(mon, path,
"vram64_size_mb", &prop) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("QOM Object '%s' has no property 'vram64_size_mb'"),
path);
return -1;
}
video->vram64 = prop.val.ul / 1024;
}
if (qemuMonitorJSONGetObjectProperty(mon, path, "ram_size", &prop) < 0) { if (qemuMonitorJSONGetObjectProperty(mon, path, "ram_size", &prop) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("QOM Object '%s' has no property 'ram_size'"), _("QOM Object '%s' has no property 'ram_size'"),
...@@ -1471,6 +1483,48 @@ qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon, ...@@ -1471,6 +1483,48 @@ qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
} }
/**
* Loads correct video vram64 size value from QEMU and update the video
* definition.
*
* Return 0 on success, -1 on failure and set proper error message.
*/
int
qemuMonitorJSONUpdateVideoVram64Size(qemuMonitorPtr mon,
virDomainVideoDefPtr video,
char *path)
{
qemuMonitorJSONObjectProperty prop = {
QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
{0}
};
switch (video->type) {
case VIR_DOMAIN_VIDEO_TYPE_QXL:
if (video->vram64 != 0) {
if (qemuMonitorJSONGetObjectProperty(mon, path,
"vram64_size_mb", &prop) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("QOM Object '%s' has no property 'vram64_size_mb'"),
path);
return -1;
}
video->vram64 = prop.val.ul / 1024;
}
break;
case VIR_DOMAIN_VIDEO_TYPE_VGA:
case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
case VIR_DOMAIN_VIDEO_TYPE_XEN:
case VIR_DOMAIN_VIDEO_TYPE_VBOX:
case VIR_DOMAIN_VIDEO_TYPE_LAST:
break;
}
return 0;
}
int int
qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon, qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
unsigned long long *currmem) unsigned long long *currmem)
......
...@@ -60,6 +60,9 @@ int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon, ...@@ -60,6 +60,9 @@ int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon, int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
virDomainVideoDefPtr video, virDomainVideoDefPtr video,
char *path); char *path);
int qemuMonitorJSONUpdateVideoVram64Size(qemuMonitorPtr mon,
virDomainVideoDefPtr video,
char *path);
int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon, int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
unsigned long long *currmem); unsigned long long *currmem);
int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon, int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
......
...@@ -2740,17 +2740,25 @@ qemuProcessUpdateVideoRamSize(virQEMUDriverPtr driver, ...@@ -2740,17 +2740,25 @@ qemuProcessUpdateVideoRamSize(virQEMUDriverPtr driver,
break; break;
case VIR_DOMAIN_VIDEO_TYPE_QXL: case VIR_DOMAIN_VIDEO_TYPE_QXL:
if (i == 0) { if (i == 0) {
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) { if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM) &&
if (qemuMonitorUpdateVideoMemorySize(priv->mon, video, qemuMonitorUpdateVideoMemorySize(priv->mon, video,
"qxl-vga") < 0) "qxl-vga") < 0)
goto error; goto error;
}
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGA_VRAM64) &&
qemuMonitorUpdateVideoVram64Size(priv->mon, video,
"qxl-vga") < 0)
goto error;
} else { } else {
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGAMEM)) { if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGAMEM) &&
if (qemuMonitorUpdateVideoMemorySize(priv->mon, video, qemuMonitorUpdateVideoMemorySize(priv->mon, video,
"qxl") < 0) "qxl") < 0)
goto error;
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VRAM64) &&
qemuMonitorUpdateVideoVram64Size(priv->mon, video,
"qxl") < 0)
goto error; goto error;
}
} }
break; break;
case VIR_DOMAIN_VIDEO_TYPE_VMVGA: case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
......
LC_ALL=C \
PATH=/bin \
HOME=/home/test \
USER=test \
LOGNAME=test \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu-system-x86_64 \
-name QEMUGuest1 \
-S \
-M pc \
-m 1024 \
-smp 1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
-nodefaults \
-monitor unix:/tmp/test-monitor,server,nowait \
-no-acpi \
-boot c \
-usb \
-drive file=/var/lib/libvirt/images/QEMUGuest1,format=qcow2,if=none,\
id=drive-ide0-0-0,cache=none \
-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
-device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,\
vram64_size_mb=128,vgamem_mb=16,bus=pci.0,addr=0x2 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
<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='x86_64' 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-x86_64</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='qxl' vram64='131072' heads='1'/>
</video>
<memballoon model='virtio'/>
</devices>
</domain>
LC_ALL=C \
PATH=/bin \
HOME=/home/test \
USER=test \
LOGNAME=test \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu \
-name QEMUGuest1 \
-S \
-M pc \
-m 1024 \
-smp 1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
-nodefaults \
-monitor unix:/tmp/test-monitor,server,nowait \
-no-acpi \
-boot c \
-usb \
-drive file=/var/lib/libvirt/images/QEMUGuest1,format=qcow2,if=none,\
id=drive-ide0-0-0,cache=none \
-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
-device qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vgamem_mb=16,\
bus=pci.0,addr=0x2 \
-device qxl,id=video1,ram_size=67108864,vram_size=67108864,vram64_size_mb=128,\
vgamem_mb=16,bus=pci.0,addr=0x4 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
<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</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='qxl' heads='1'/>
</video>
<video>
<model type='qxl' vram64='131072' heads='1'/>
</video>
<memballoon model='virtio'/>
</devices>
</domain>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册