mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
hw/display: Allow injection of virtio-gpu EDID name
Thanks to72d277a7,1ed2cb32, and others, EDID (Extended Display Identification Data) is propagated by QEMU such that a virtual display presents legitimate metadata (e.g., name, serial number, preferred resolutions, etc.) to its connected guest. This change adds the ability to specify the EDID name for a particular virtio-vga display. Previously, every virtual display would have the same name: "QEMU Monitor". Now, we can inject names of displays in order to test guest behavior that is specific to display names. We provide the ability to inject the display name from the frontend since this is guest visible data. Furthermore, this makes it clear where N potential display outputs would get their name from (which will be added in a future change). Note that we have elected to use a struct here for output data for extensibility - we intend to add per-output fields like resolution in a future change. It should be noted that EDID names longer than 12 bytes will be truncated per spec (I think?). Testing: verified that when I specified 2 outputs for a virtio-gpu with edid_name set, the names matched those that I configured with my vnc display. -display vnc=localhost:0,id=aaa,display=vga,head=0 \ -display vnc=localhost:1,id=bbb,display=vga,head=1 \ -device '{"driver":"virtio-vga", "max_outputs":2, "id":"vga", "outputs":[ { "name":"AAA" }, { "name":"BBB" } ]}' Signed-off-by: Andrew Keesler <ankeesler@google.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20250709121126.2946088-2-ankeesler@google.com>
This commit is contained in:
committed by
Marc-André Lureau
parent
f851cd65eb
commit
454f4b0f59
@@ -1299,3 +1299,47 @@ const PropertyInfo qdev_prop_vmapple_virtio_blk_variant = {
|
||||
.set = qdev_propinfo_set_enum,
|
||||
.set_default_value = qdev_propinfo_set_default_value_enum,
|
||||
};
|
||||
|
||||
/* --- VirtIOGPUOutputList --- */
|
||||
|
||||
static void get_virtio_gpu_output_list(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque, Error **errp)
|
||||
{
|
||||
VirtIOGPUOutputList **prop_ptr =
|
||||
object_field_prop_ptr(obj, opaque);
|
||||
|
||||
visit_type_VirtIOGPUOutputList(v, name, prop_ptr, errp);
|
||||
}
|
||||
|
||||
static void set_virtio_gpu_output_list(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque, Error **errp)
|
||||
{
|
||||
VirtIOGPUOutputList **prop_ptr =
|
||||
object_field_prop_ptr(obj, opaque);
|
||||
VirtIOGPUOutputList *list;
|
||||
|
||||
if (!visit_type_VirtIOGPUOutputList(v, name, &list, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qapi_free_VirtIOGPUOutputList(*prop_ptr);
|
||||
*prop_ptr = list;
|
||||
}
|
||||
|
||||
static void release_virtio_gpu_output_list(Object *obj,
|
||||
const char *name, void *opaque)
|
||||
{
|
||||
VirtIOGPUOutputList **prop_ptr =
|
||||
object_field_prop_ptr(obj, opaque);
|
||||
|
||||
qapi_free_VirtIOGPUOutputList(*prop_ptr);
|
||||
*prop_ptr = NULL;
|
||||
}
|
||||
|
||||
const PropertyInfo qdev_prop_virtio_gpu_output_list = {
|
||||
.type = "VirtIOGPUOutputList",
|
||||
.description = "VirtIO GPU output list [{\"name\":\"<name>\"},...]",
|
||||
.get = get_virtio_gpu_output_list,
|
||||
.set = set_virtio_gpu_output_list,
|
||||
.release = release_virtio_gpu_output_list,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/display/edid.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/qapi-types-virtio.h"
|
||||
|
||||
void
|
||||
virtio_gpu_base_reset(VirtIOGPUBase *g)
|
||||
@@ -56,6 +57,8 @@ void
|
||||
virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout,
|
||||
struct virtio_gpu_resp_edid *edid)
|
||||
{
|
||||
size_t output_idx;
|
||||
VirtIOGPUOutputList *node;
|
||||
qemu_edid_info info = {
|
||||
.width_mm = g->req_state[scanout].width_mm,
|
||||
.height_mm = g->req_state[scanout].height_mm,
|
||||
@@ -64,6 +67,14 @@ virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout,
|
||||
.refresh_rate = g->req_state[scanout].refresh_rate,
|
||||
};
|
||||
|
||||
for (output_idx = 0, node = g->conf.outputs;
|
||||
output_idx <= scanout && node; output_idx++, node = node->next) {
|
||||
if (output_idx == scanout && node->value && node->value->name) {
|
||||
info.name = node->value->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
edid->size = cpu_to_le32(sizeof(edid->edid));
|
||||
qemu_edid_generate(edid->edid, sizeof(edid->edid), &info);
|
||||
}
|
||||
@@ -172,6 +183,8 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
|
||||
VirtIOHandleOutput cursor_cb,
|
||||
Error **errp)
|
||||
{
|
||||
size_t output_idx;
|
||||
VirtIOGPUOutputList *node;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev);
|
||||
int i;
|
||||
@@ -181,6 +194,20 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
|
||||
return false;
|
||||
}
|
||||
|
||||
for (output_idx = 0, node = g->conf.outputs;
|
||||
node; output_idx++, node = node->next) {
|
||||
if (output_idx == g->conf.max_outputs) {
|
||||
error_setg(errp, "invalid outputs > %d", g->conf.max_outputs);
|
||||
return false;
|
||||
}
|
||||
if (node->value && node->value->name &&
|
||||
strlen(node->value->name) > EDID_NAME_MAX_LENGTH) {
|
||||
error_setg(errp, "invalid output name '%s' > %d",
|
||||
node->value->name, EDID_NAME_MAX_LENGTH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||
error_setg(&g->migration_blocker, "virgl is not yet migratable");
|
||||
if (migrate_add_blocker(&g->migration_blocker, errp) < 0) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef EDID_H
|
||||
#define EDID_H
|
||||
|
||||
#define EDID_NAME_MAX_LENGTH 12
|
||||
|
||||
typedef struct qemu_edid_info {
|
||||
const char *vendor; /* http://www.uefi.org/pnp_id_list */
|
||||
const char *name;
|
||||
|
||||
@@ -32,6 +32,7 @@ extern const PropertyInfo qdev_prop_cpus390entitlement;
|
||||
extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
|
||||
extern const PropertyInfo qdev_prop_endian_mode;
|
||||
extern const PropertyInfo qdev_prop_vmapple_virtio_blk_variant;
|
||||
extern const PropertyInfo qdev_prop_virtio_gpu_output_list;
|
||||
|
||||
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
|
||||
@@ -110,4 +111,8 @@ extern const PropertyInfo qdev_prop_vmapple_virtio_blk_variant;
|
||||
qdev_prop_vmapple_virtio_blk_variant, \
|
||||
VMAppleVirtioBlkVariant)
|
||||
|
||||
#define DEFINE_PROP_VIRTIO_GPU_OUTPUT_LIST(_name, _state, _field) \
|
||||
DEFINE_PROP(_name, _state, _field, qdev_prop_virtio_gpu_output_list, \
|
||||
VirtIOGPUOutputList *)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "qemu/log.h"
|
||||
#include "system/vhost-user-backend.h"
|
||||
#include "qapi/qapi-types-virtio.h"
|
||||
|
||||
#include "standard-headers/linux/virtio_gpu.h"
|
||||
#include "standard-headers/linux/virtio_ids.h"
|
||||
@@ -128,6 +129,7 @@ struct virtio_gpu_base_conf {
|
||||
uint32_t xres;
|
||||
uint32_t yres;
|
||||
uint64_t hostmem;
|
||||
VirtIOGPUOutputList *outputs;
|
||||
};
|
||||
|
||||
struct virtio_gpu_ctrl_command {
|
||||
@@ -167,6 +169,7 @@ struct VirtIOGPUBaseClass {
|
||||
|
||||
#define VIRTIO_GPU_BASE_PROPERTIES(_state, _conf) \
|
||||
DEFINE_PROP_UINT32("max_outputs", _state, _conf.max_outputs, 1), \
|
||||
DEFINE_PROP_VIRTIO_GPU_OUTPUT_LIST("outputs", _state, _conf.outputs), \
|
||||
DEFINE_PROP_BIT("edid", _state, _conf.flags, \
|
||||
VIRTIO_GPU_FLAG_EDID_ENABLED, true), \
|
||||
DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1280), \
|
||||
|
||||
@@ -963,17 +963,31 @@
|
||||
{ 'struct': 'IOThreadVirtQueueMapping',
|
||||
'data': { 'iothread': 'str', '*vqs': ['uint16'] } }
|
||||
|
||||
##
|
||||
# @VirtIOGPUOutput:
|
||||
#
|
||||
# Describes configuration of a VirtIO GPU output.
|
||||
#
|
||||
# @name: the name of the output
|
||||
#
|
||||
# Since: 10.1
|
||||
##
|
||||
|
||||
{ 'struct': 'VirtIOGPUOutput',
|
||||
'data': { 'name': 'str' } }
|
||||
|
||||
##
|
||||
# @DummyVirtioForceArrays:
|
||||
#
|
||||
# Not used by QMP; hack to let us use IOThreadVirtQueueMappingList
|
||||
# internally
|
||||
# and VirtIOGPUOutputList internally
|
||||
#
|
||||
# Since: 9.0
|
||||
##
|
||||
|
||||
{ 'struct': 'DummyVirtioForceArrays',
|
||||
'data': { 'unused-iothread-vq-mapping': ['IOThreadVirtQueueMapping'] } }
|
||||
'data': { 'unused-iothread-vq-mapping': ['IOThreadVirtQueueMapping'],
|
||||
'unused-virtio-gpu-output': ['VirtIOGPUOutput'] } }
|
||||
|
||||
##
|
||||
# @GranuleMode:
|
||||
|
||||
Reference in New Issue
Block a user