1 From f5c2bd00890dc32e940e8b2fae09f62f758317eb Mon Sep 17 00:00:00 2001
2 From: Alon Levy <alevy@redhat.com>
3 Date: Wed, 12 Sep 2012 16:13:28 +0300
4 Subject: [PATCH] hw/qxl: support client monitor configuration via device
6 Until now we used only the agent to change the monitor count and each
7 monitor resolution. This patch introduces the qemu part of using the
8 device as the mediator instead of the agent via virtio-serial.
10 Spice (>=0.11.5) calls the new QXLInterface::client_monitors_config,
11 which returns wether the interrupt is enabled, and if so and given a non
12 NULL monitors config will
13 generate an interrupt QXL_INTERRUPT_CLIENT_MONITORS_CONFIG with crc
14 checksum for the guest to verify a second call hasn't interfered.
16 The maximal number of monitors is limited on the QXLRom to 64.
18 Signed-off-by: Alon Levy <alevy@redhat.com>
19 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
22 hw/qxl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 trace-events | 6 ++++-
24 3 files changed, 91 insertions(+), 1 deletion(-)
26 diff --git a/configure b/configure
27 index f528146..83c478c 100755
30 @@ -2706,6 +2706,9 @@ EOF
31 if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then
32 spice_qxl_io_monitors_config_async="yes"
34 + if $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1; then
35 + spice_qxl_client_monitors_config="yes"
38 if test "$spice" = "yes" ; then
39 feature_not_found "spice"
40 @@ -3453,6 +3456,10 @@ if test "$spice_qxl_io_monitors_config_async" = "yes" ; then
41 echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak
44 +if test "$spice_qxl_client_monitors_config" = "yes" ; then
45 + echo "CONFIG_QXL_CLIENT_MONITORS_CONFIG=y" >> $config_host_mak
48 if test "$smartcard" = "yes" ; then
49 echo "CONFIG_SMARTCARD=y" >> $config_host_mak
51 diff --git a/hw/qxl.c b/hw/qxl.c
52 index 1ef117a..0695872 100644
56 * along with this program; if not, see <http://www.gnu.org/licenses/>.
61 #include "qemu-common.h"
62 #include "qemu-timer.h"
63 #include "qemu-queue.h"
64 @@ -971,6 +973,79 @@ static void interface_set_client_capabilities(QXLInstance *sin,
68 +#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \
69 + && SPICE_SERVER_VERSION >= 0x000b05
71 +static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
74 + * zlib xors the seed with 0xffffffff, and xors the result
75 + * again with 0xffffffff; Both are not done with linux's crc32,
76 + * which we want to be compatible with, so undo that.
78 + return crc32(0xffffffff, p, len) ^ 0xffffffff;
81 +/* called from main context only */
82 +static int interface_client_monitors_config(QXLInstance *sin,
83 + VDAgentMonitorsConfig *monitors_config)
85 + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
86 + QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
90 + * Older windows drivers set int_mask to 0 when their ISR is called,
91 + * then later set it to ~0. So it doesn't relate to the actual interrupts
92 + * handled. However, they are old, so clearly they don't support this
95 + if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
96 + !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
97 + trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
102 + if (!monitors_config) {
105 + memset(&rom->client_monitors_config, 0,
106 + sizeof(rom->client_monitors_config));
107 + rom->client_monitors_config.count = monitors_config->num_of_monitors;
108 + /* monitors_config->flags ignored */
109 + if (rom->client_monitors_config.count >=
110 + ARRAY_SIZE(rom->client_monitors_config.heads)) {
111 + trace_qxl_client_monitors_config_capped(qxl->id,
112 + monitors_config->num_of_monitors,
113 + ARRAY_SIZE(rom->client_monitors_config.heads));
114 + rom->client_monitors_config.count =
115 + ARRAY_SIZE(rom->client_monitors_config.heads);
117 + for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
118 + VDAgentMonConfig *monitor = &monitors_config->monitors[i];
119 + QXLURect *rect = &rom->client_monitors_config.heads[i];
120 + /* monitor->depth ignored */
121 + rect->left = monitor->x;
122 + rect->top = monitor->y;
123 + rect->right = monitor->x + monitor->width;
124 + rect->bottom = monitor->y + monitor->height;
126 + rom->client_monitors_config_crc = qxl_crc32(
127 + (const uint8_t *)&rom->client_monitors_config,
128 + sizeof(rom->client_monitors_config));
129 + trace_qxl_client_monitors_config_crc(qxl->id,
130 + sizeof(rom->client_monitors_config),
131 + rom->client_monitors_config_crc);
133 + trace_qxl_interrupt_client_monitors_config(qxl->id,
134 + rom->client_monitors_config.count,
135 + rom->client_monitors_config.heads);
136 + qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
141 static const QXLInterface qxl_interface = {
142 .base.type = SPICE_INTERFACE_QXL,
143 .base.description = "qxl gpu",
144 @@ -995,6 +1070,10 @@ static const QXLInterface qxl_interface = {
145 #if SPICE_SERVER_VERSION >= 0x000b04
146 .set_client_capabilities = interface_set_client_capabilities,
148 +#if SPICE_SERVER_VERSION >= 0x000b05 && \
149 + defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG)
150 + .client_monitors_config = interface_client_monitors_config,
154 static void qxl_enter_vga_mode(PCIQXLDevice *d)
155 diff --git a/trace-events b/trace-events
156 index 80a52d9..07b63f1 100644
159 @@ -930,7 +930,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d
160 qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d"
161 qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d"
162 qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s"
163 -qxl_io_log(int qid, const uint8_t *str) "%d %s"
164 +qxl_io_log(int qid, const uint8_t *log_buf) "%d %s"
165 qxl_io_read_unexpected(int qid) "%d"
166 qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)"
167 qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d"
168 @@ -974,6 +974,10 @@ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dir
169 qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d"
170 qxl_send_events(int qid, uint32_t events) "%d %d"
171 qxl_set_guest_bug(int qid) "%d"
172 +qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p"
173 +qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p"
174 +qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d"
175 +qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u"
178 qxl_render_blit_guest_primary_initialized(void) ""