From 6da3597cf4a787df642fb04d6c0464cece65461f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 10 Apr 2014 10:33:37 +0200 Subject: [PATCH 01/26] hw/qxl: support client monitor configuration via device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Gerd Hoffmann Message-id: <1397126017-10175-2-git-send-email-kraxel@redhat.com> Patchwork-id: 58416 O-Subject: [RHEL-6.6 qemu-kvm PATCH 1/1] hw/qxl: support client monitor configuration via device Bugzilla: 1075139 RH-Acked-by: Markus Armbruster RH-Acked-by: Laszlo Ersek RH-Acked-by: Marc-André Lureau From: Alon Levy Until now we used only the agent to change the monitor count and each monitor resolution. This patch introduces the qemu part of using the device as the mediator instead of the agent via virtio-serial. Spice (>=0.11.5) calls the new QXLInterface::client_monitors_config, which returns wether the interrupt is enabled, and if so and given a non NULL monitors config will generate an interrupt QXL_INTERRUPT_CLIENT_MONITORS_CONFIG with crc checksum for the guest to verify a second call hasn't interfered. The maximal number of monitors is limited on the QXLRom to 64. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann (cherry picked from commit a639ab0482952c13c896f3e555d717caf98f138b) Conflicts: hw/qxl.c trace-events --- configure | 7 ++++++ hw/qxl.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ trace-events | 4 ++++ 3 files changed, 89 insertions(+) Signed-off-by: Miroslav Rezanina --- configure | 7 +++++ hw/qxl.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ trace-events | 4 +++ 3 files changed, 89 insertions(+), 0 deletions(-) diff --git a/configure b/configure index d72ea4f..58a1747 100755 --- a/configure +++ b/configure @@ -2152,6 +2152,9 @@ EOF if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then spice_qxl_io_monitors_config_async="yes" fi + if $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1; then + spice_qxl_client_monitors_config="yes" + fi else if test "$spice" = "yes" ; then feature_not_found "spice" @@ -2672,6 +2675,10 @@ if test "$spice_qxl_io_monitors_config_async" = "yes" ; then echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak fi +if test "$spice_qxl_client_monitors_config" = "yes" ; then + echo "CONFIG_QXL_CLIENT_MONITORS_CONFIG=y" >> $config_host_mak +fi + if test "$smartcard" = "yes" ; then echo "CONFIG_SMARTCARD=y" >> $config_host_mak fi diff --git a/hw/qxl.c b/hw/qxl.c index e329326..2747c81 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -19,6 +19,7 @@ */ #include +#include #include "qemu-common.h" #include "qemu-timer.h" @@ -987,6 +988,79 @@ static void interface_set_client_capabilities(QXLInstance *sin, #endif +#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \ + && SPICE_SERVER_VERSION >= 0x000b05 + +static uint32_t qxl_crc32(const uint8_t *p, unsigned len) +{ + /* + * zlib xors the seed with 0xffffffff, and xors the result + * again with 0xffffffff; Both are not done with linux's crc32, + * which we want to be compatible with, so undo that. + */ + return crc32(0xffffffff, p, len) ^ 0xffffffff; +} + +/* called from main context only */ +static int interface_client_monitors_config(QXLInstance *sin, + VDAgentMonitorsConfig *monitors_config) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLRom *rom = qemu_get_ram_ptr(qxl->rom_offset); + int i; + + /* + * Older windows drivers set int_mask to 0 when their ISR is called, + * then later set it to ~0. So it doesn't relate to the actual interrupts + * handled. However, they are old, so clearly they don't support this + * interrupt + */ + if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 || + !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) { + trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id, + qxl->ram->int_mask, + monitors_config); + return 0; + } + if (!monitors_config) { + return 1; + } + memset(&rom->client_monitors_config, 0, + sizeof(rom->client_monitors_config)); + rom->client_monitors_config.count = monitors_config->num_of_monitors; + /* monitors_config->flags ignored */ + if (rom->client_monitors_config.count >= + ARRAY_SIZE(rom->client_monitors_config.heads)) { + trace_qxl_client_monitors_config_capped(qxl->id, + monitors_config->num_of_monitors, + ARRAY_SIZE(rom->client_monitors_config.heads)); + rom->client_monitors_config.count = + ARRAY_SIZE(rom->client_monitors_config.heads); + } + for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { + VDAgentMonConfig *monitor = &monitors_config->monitors[i]; + QXLURect *rect = &rom->client_monitors_config.heads[i]; + /* monitor->depth ignored */ + rect->left = monitor->x; + rect->top = monitor->y; + rect->right = monitor->x + monitor->width; + rect->bottom = monitor->y + monitor->height; + } + rom->client_monitors_config_crc = qxl_crc32( + (const uint8_t *)&rom->client_monitors_config, + sizeof(rom->client_monitors_config)); + trace_qxl_client_monitors_config_crc(qxl->id, + sizeof(rom->client_monitors_config), + rom->client_monitors_config_crc); + + trace_qxl_interrupt_client_monitors_config(qxl->id, + rom->client_monitors_config.count, + rom->client_monitors_config.heads); + qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); + return 1; +} +#endif + static const QXLInterface qxl_interface = { .base.type = SPICE_INTERFACE_QXL, .base.description = "qxl gpu", @@ -1011,6 +1085,10 @@ static const QXLInterface qxl_interface = { #if SPICE_SERVER_VERSION >= 0x000b04 .set_client_capabilities = interface_set_client_capabilities, #endif +#if SPICE_SERVER_VERSION >= 0x000b05 && \ + defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) + .client_monitors_config = interface_client_monitors_config, +#endif }; static void qxl_enter_vga_mode(PCIQXLDevice *d) diff --git a/trace-events b/trace-events index 51d2c08..b7e02f7 100644 --- a/trace-events +++ b/trace-events @@ -283,6 +283,10 @@ disable qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint3 disable qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" disable qxl_surfaces_dirty(int qid, int surface, int addr, int offset, int size) "%d surface=%d addr=%d offset=%d size=%d" disable qxl_set_client_capabilities_unsupported_by_revision(int qid, int revision) "%d revision=%d" +disable qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" +disable qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" +disable qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d" +disable qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u" # hw/qxl-render.c disable qxl_render_blit_guest_primary_initialized(void) "" -- 1.7.1