From b1af98ba3e4c4fd44f233fc7240df2612baeb1c2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 5 Sep 2012 08:25:08 +0200 Subject: spice: switch to queue for vga mode updates Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index 5b3f484266..257a37d3c5 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -597,9 +597,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) case QXL_MODE_VGA: ret = false; qemu_mutex_lock(&qxl->ssd.lock); - if (qxl->ssd.update != NULL) { - update = qxl->ssd.update; - qxl->ssd.update = NULL; + update = QTAILQ_FIRST(&qxl->ssd.updates); + if (update != NULL) { + QTAILQ_REMOVE(&qxl->ssd.updates, update, next); *ext = update->ext; ret = true; } -- cgit v1.2.3 From ccc2960d654a233a6ed415b37d8ff41728d817c5 Mon Sep 17 00:00:00 2001 From: Dunrong Huang Date: Fri, 31 Aug 2012 00:44:44 +0800 Subject: qxl: dont update invalid area This patch fixes the following error: $ ~/usr/bin/qemu-system-x86_64 -enable-kvm -m 1024 -spice port=5900,disable-ticketing -vga qxl -cdrom ~/Images/linuxmint-13-mate-dvd-32bit.iso (/home/mathslinux/usr/bin/qemu-system-x86_64:10068): SpiceWorker-CRITICAL **: red_worker.c:4599:red_update_area: condition `area->left >= 0 && area->top >= 0 && area->left < area->right && area->top < area->bottom' failed Aborted spice server terminates QEMU process if we pass invalid area to it, so dont update those invalid areas. Signed-off-by: Dunrong Huang Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index 257a37d3c5..0176b1a11a 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1470,6 +1470,13 @@ async_common: return; } + if (update.left < 0 || update.top < 0 || update.left >= update.right || + update.top >= update.bottom) { + qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " + "invalid area(%d,%d,%d,%d)\n", update.left, + update.right, update.top, update.bottom); + break; + } if (async == QXL_ASYNC) { cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, QXL_IO_UPDATE_AREA_ASYNC); -- cgit v1.2.3 From ab902981cf4d46834d82eb095f2b9ab159e017bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 7 Sep 2012 21:48:22 +0200 Subject: qxl: Ignore set_client_capabilities pre/post migrate The recent introduction of set_client_capabilities has broken (seamless) migration by trying to call qxl_send_events pre (seamless incoming) and post (*) migration, triggering the following assert: qxl_send_events: Assertion `qemu_spice_display_is_running(&d->ssd)' failed. The solution is easy, pre migration the guest will have already received the client caps on the migration source side, and post migration there no longer is a guest, so we can simply ignore the set_client_capabilities call in both those scenarios. *) Post migration, so not fatal for to the migration itself, but still a crash Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index 0176b1a11a..e539134c65 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -953,6 +953,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + if (runstate_check(RUN_STATE_INMIGRATE) || + runstate_check(RUN_STATE_POSTMIGRATE)) { + return; + } + qxl->shadow_rom.client_present = client_present; memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); qxl->rom->client_present = client_present; -- cgit v1.2.3 From 753b8b0d77ba1b343a35f9679cc777ea10a62bba Mon Sep 17 00:00:00 2001 From: Uri Lublin Date: Tue, 11 Sep 2012 10:09:58 +0300 Subject: qxl: better cleanup for surface destroy Add back a call to qxl_spice_destroy_surface_wait_complete() in qxl_spice_destroy_surface_wait(), that was removed by commit c480bb7da465186b84d8427e068ef7502e47ffbf It is needed to complete surface-removal cleanup, for non async. For async, qxl_spice_destroy_surface_wait_complete is called upon operation completion. Signed-off-by: Uri Lublin Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index e539134c65..12597e75de 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -201,6 +201,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); } else { qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl_spice_destroy_surface_wait_complete(qxl, id); } } -- cgit v1.2.3 From 917ae08ca1565aab2d10c8b6269cd905d6c5c05b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 12 Sep 2012 16:13:26 +0300 Subject: hw/qxl: tracing fixes Add two new trace events: qxl_send_events(int qid, uint32_t events) "%d %d" qxl_set_guest_bug(int qid) "%d" Change qxl_io_unexpected_vga_mode parameters to be equivalent to those of qxl_io_write for easier grouping under a single systemtap probe. Change d to qxl in one place. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index 12597e75de..8c46766b8e 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -141,6 +141,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) { + trace_qxl_set_guest_bug(qxl->id); qxl_send_events(qxl, QXL_INTERRUPT_ERROR); qxl->guest_bug = 1; if (qxl->guestdebug) { @@ -1408,7 +1409,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, break; } trace_qxl_io_unexpected_vga_mode(d->id, - io_port, io_port_to_string(io_port)); + addr, val, io_port_to_string(io_port)); /* be nice to buggy guest drivers */ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && io_port < QXL_IO_RANGE_SIZE) { @@ -1607,9 +1608,9 @@ cancel_async: static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, unsigned size) { - PCIQXLDevice *d = opaque; + PCIQXLDevice *qxl = opaque; - trace_qxl_io_read_unexpected(d->id); + trace_qxl_io_read_unexpected(qxl->id); return 0xff; } @@ -1639,6 +1640,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) uint32_t old_pending; uint32_t le_events = cpu_to_le32(events); + trace_qxl_send_events(d->id, events); assert(qemu_spice_display_is_running(&d->ssd)); old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); if ((old_pending & le_events) == le_events) { -- cgit v1.2.3 From 1a1bc08568b3fc3d893cab774806cdcedfe1b60b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 12 Sep 2012 16:13:27 +0300 Subject: qxl: add trace-event for QXL_IO_LOG Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index 8c46766b8e..5709e0d957 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1515,6 +1515,7 @@ async_common: qxl_set_mode(d, val, 0); break; case QXL_IO_LOG: + trace_qxl_io_log(d->id, d->ram->log_buf); if (d->guestdebug) { fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, qemu_get_clock_ns(vm_clock), d->ram->log_buf); -- cgit v1.2.3 From a639ab0482952c13c896f3e555d717caf98f138b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 12 Sep 2012 16:13:28 +0300 Subject: hw/qxl: support client monitor configuration via device 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 --- hw/qxl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'hw/qxl.c') diff --git a/hw/qxl.c b/hw/qxl.c index 5709e0d957..c464408421 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -18,6 +18,8 @@ * along with this program; if not, see . */ +#include + #include "qemu-common.h" #include "qemu-timer.h" #include "qemu-queue.h" @@ -971,6 +973,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 = memory_region_get_ram_ptr(&qxl->rom_bar); + 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", @@ -995,6 +1070,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) -- cgit v1.2.3