From 48f4ba671bbb3dd212002d57b72a23375f51619b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Mon, 15 Oct 2012 14:54:03 +0200 Subject: [PATCH 1/7] hw/qxl: guest bug on primary create with stride %4 != 0 Due to usage of pixman for rendering on all spice surfaces we have pixman's requirement that the stride be word aligned. A guest not honoring that can crash spice and qemu with it due to failure to create a surface (in spice-server). Avoid this early on in primary surface creation and offscreen surface creation. Recently windows guests got odd width support which triggers a non word aligned primary surface in 16bit color depth. Off screen surfaces have always been word aligned, but doesn't hurt to check them here too. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index 1f56fcd169..cc16eaf2aa 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -447,6 +447,12 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) qxl->ssd.num_surfaces); return 1; } + if (cmd->type == QXL_SURFACE_CMD_CREATE && + (cmd->u.surface_create.stride & 0x03) != 0) { + qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n", + cmd->u.surface_create.stride); + return 1; + } qemu_mutex_lock(&qxl->track_lock); if (cmd->type == QXL_SURFACE_CMD_CREATE) { qxl->guest_surfaces.cmds[id] = ext->cmd.data; @@ -1357,6 +1363,12 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type, sc->flags); + if ((surface.stride & 0x3) != 0) { + qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0", + surface.stride); + return; + } + surface.mouse_mode = true; surface.group_id = MEMSLOT_GROUP_GUEST; if (loadvm) { From 511aefb0c60e3063ead76d4ba6aabf619eed18ef Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Thu, 1 Nov 2012 14:56:00 +0200 Subject: [PATCH 2/7] hw/qxl: qxl_send_events: nop if stopped Added a trace point for easy logging. RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=870972 Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 8 +++++++- trace-events | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/qxl.c b/hw/qxl.c index cc16eaf2aa..f19451bd6f 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1701,7 +1701,13 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) uint32_t le_events = cpu_to_le32(events); trace_qxl_send_events(d->id, events); - assert(qemu_spice_display_is_running(&d->ssd)); + if (!qemu_spice_display_is_running(&d->ssd)) { + /* spice-server tracks guest running state and should not do this */ + fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n", + __func__); + trace_qxl_send_events_vm_stopped(d->id, events); + return; + } old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); if ((old_pending & le_events) == le_events) { return; diff --git a/trace-events b/trace-events index b84d631dc7..e1a37cc26f 100644 --- a/trace-events +++ b/trace-events @@ -1001,6 +1001,7 @@ qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t righ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" qxl_send_events(int qid, uint32_t events) "%d %d" +qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d" qxl_set_guest_bug(int qid) "%d" qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" From 958c2bceba06696e9c223498aaf81d06ce95f608 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 14 Sep 2012 22:17:44 +0200 Subject: [PATCH 3/7] qxl: fix cursor reset When resetting the qxl cursor notify the qemu displaystate too. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index f19451bd6f..063970dc28 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -293,6 +293,10 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) qemu_mutex_lock(&qxl->track_lock); qxl->guest_cursor = 0; qemu_mutex_unlock(&qxl->track_lock); + if (qxl->ssd.cursor) { + cursor_put(qxl->ssd.cursor); + } + qxl->ssd.cursor = cursor_builtin_hidden(); } From e32c25b5f2452c7fed4dbe8962f4a9f4831fbe24 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 30 Oct 2012 14:55:12 +0100 Subject: [PATCH 4/7] qxl: call dpy_gfx_resize when entering vga mode When entering vga mode the display size likely changes, notify all displaychangelisteners about this. Probably went unnoticed for a while as one if the first things the guest does after leaving qxl native mode and entering qxl vga mode is to set the vga video mode. But there is still a small window where qemu can operate on stale data, leading to crashes now and then. https://bugzilla.redhat.com/show_bug.cgi?id=865767 Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/qxl.c b/hw/qxl.c index 063970dc28..e7bf3a11a7 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1069,7 +1069,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) trace_qxl_enter_vga_mode(d->id); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; - memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); + dpy_gfx_resize(d->ssd.ds); vga_dirty_log_start(&d->vga); } From d9a86569ca3617a495ffb352e9a390747eaa6b24 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 2 Nov 2012 09:12:49 +0100 Subject: [PATCH 5/7] spice: switch to pixman Switch over spice-display.c to use the pixman library instead of the home-grown pflib bits. Signed-off-by: Gerd Hoffmann --- console.h | 5 +++++ qemu-pixman.c | 13 ++++++++++++ qemu-pixman.h | 2 ++ ui/spice-display.c | 51 ++++++++++++++++++++-------------------------- ui/spice-display.h | 7 +++---- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/console.h b/console.h index 70c9a55942..50a0512f32 100644 --- a/console.h +++ b/console.h @@ -377,6 +377,11 @@ static inline pixman_format_code_t ds_get_format(DisplayState *ds) return ds->surface->format; } +static inline pixman_image_t *ds_get_image(DisplayState *ds) +{ + return ds->surface->image; +} + static inline int ds_get_depth(DisplayState *ds) { return ds->surface->pf.depth; diff --git a/qemu-pixman.c b/qemu-pixman.c index 7547ed74c1..71a9ea43a6 100644 --- a/qemu-pixman.c +++ b/qemu-pixman.c @@ -51,6 +51,19 @@ void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, 0, y, 0, 0, 0, 0, width, 1); } +pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, + pixman_image_t *image) +{ + pixman_image_t *mirror; + + mirror = pixman_image_create_bits(format, + pixman_image_get_width(image), + pixman_image_get_height(image), + NULL, + pixman_image_get_stride(image)); + return mirror; +} + void qemu_pixman_image_unref(pixman_image_t *image) { if (image == NULL) { diff --git a/qemu-pixman.h b/qemu-pixman.h index 7652c41277..e267d73683 100644 --- a/qemu-pixman.h +++ b/qemu-pixman.h @@ -27,6 +27,8 @@ pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, int width); void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, int width, int y); +pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, + pixman_image_t *image); void qemu_pixman_image_unref(pixman_image_t *image); #endif /* QEMU_PIXMAN_H */ diff --git a/ui/spice-display.c b/ui/spice-display.c index fb99148349..fe2fdfba68 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -150,9 +150,9 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, QXLDrawable *drawable; QXLImage *image; QXLCommand *cmd; - uint8_t *src, *mirror, *dst; - int by, bw, bh, offset, bytes; + int bw, bh; struct timespec time_space; + pixman_image_t *dest; trace_qemu_spice_create_update( rect->left, rect->right, @@ -195,20 +195,15 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, image->bitmap.palette = 0; image->bitmap.format = SPICE_BITMAP_FMT_32BIT; - offset = - rect->top * ds_get_linesize(ssd->ds) + - rect->left * ds_get_bytes_per_pixel(ssd->ds); - bytes = ds_get_bytes_per_pixel(ssd->ds) * bw; - src = ds_get_data(ssd->ds) + offset; - mirror = ssd->ds_mirror + offset; - dst = update->bitmap; - for (by = 0; by < bh; by++) { - memcpy(mirror, src, bytes); - qemu_pf_conv_run(ssd->conv, dst, mirror, bw); - src += ds_get_linesize(ssd->ds); - mirror += ds_get_linesize(ssd->ds); - dst += image->bitmap.stride; - } + dest = pixman_image_create_bits(PIXMAN_x8r8g8b8, bw, bh, + (void *)update->bitmap, bw * 4); + pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror, + rect->left, rect->top, 0, 0, + rect->left, rect->top, bw, bh); + pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest, + rect->left, rect->top, 0, 0, + 0, 0, bw, bh); + pixman_image_unref(dest); cmd->type = QXL_CMD_DRAW; cmd->data = (uintptr_t)drawable; @@ -229,14 +224,10 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) return; }; - if (ssd->conv == NULL) { - PixelFormat dst = qemu_default_pixelformat(32); - ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); - assert(ssd->conv); - } - if (ssd->ds_mirror == NULL) { - int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds); - ssd->ds_mirror = g_malloc0(size); + if (ssd->surface == NULL) { + ssd->surface = pixman_image_ref(ds_get_image(ssd->ds)); + ssd->mirror = qemu_pixman_mirror_create(ds_get_format(ssd->ds), + ds_get_image(ssd->ds)); } for (blk = 0; blk < blocks; blk++) { @@ -244,7 +235,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) } guest = ds_get_data(ssd->ds); - mirror = ssd->ds_mirror; + mirror = (void *)pixman_image_get_data(ssd->mirror); for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { yoff = y * ds_get_linesize(ssd->ds); for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { @@ -383,10 +374,12 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) dprint(1, "%s:\n", __FUNCTION__); memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - qemu_pf_conv_put(ssd->conv); - ssd->conv = NULL; - g_free(ssd->ds_mirror); - ssd->ds_mirror = NULL; + if (ssd->surface) { + pixman_image_unref(ssd->surface); + ssd->surface = NULL; + pixman_image_unref(ssd->mirror); + ssd->mirror = NULL; + } qemu_mutex_lock(&ssd->lock); while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { diff --git a/ui/spice-display.h b/ui/spice-display.h index d7669277fd..38b6ea98b3 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -20,8 +20,7 @@ #include #include "qemu-thread.h" -#include "console.h" -#include "pflib.h" +#include "qemu-pixman.h" #include "sysemu.h" #define NUM_MEMSLOTS 8 @@ -72,13 +71,13 @@ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; struct SimpleSpiceDisplay { DisplayState *ds; - uint8_t *ds_mirror; void *buf; int bufsize; QXLWorker *worker; QXLInstance qxl; uint32_t unique; - QemuPfConv *conv; + pixman_image_t *surface; + pixman_image_t *mirror; int32_t num_surfaces; QXLRect dirty; From 365b1e9e3486aaa55f30df6f16ecafffaef6ec98 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 18 Sep 2012 08:52:26 +0200 Subject: [PATCH 6/7] pflib: unused, remove it. Replaced by pixman library. Signed-off-by: Gerd Hoffmann --- Makefile.objs | 1 - pflib.c | 215 -------------------------------------------------- pflib.h | 20 ----- 3 files changed, 236 deletions(-) delete mode 100644 pflib.c delete mode 100644 pflib.h diff --git a/Makefile.objs b/Makefile.objs index 593a59267c..37be7e26f7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -78,7 +78,6 @@ common-obj-y += input.o common-obj-y += buffered_file.o migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o common-obj-y += block-migration.o iohandler.o -common-obj-y += pflib.o common-obj-y += bitmap.o bitops.o common-obj-y += page_cache.o diff --git a/pflib.c b/pflib.c deleted file mode 100644 index 987e11001a..0000000000 --- a/pflib.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * PixelFormat conversion library. - * - * Author: Gerd Hoffmann - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu-common.h" -#include "console.h" -#include "pflib.h" - -typedef struct QemuPixel QemuPixel; - -typedef void (*pf_convert)(QemuPfConv *conv, - void *dst, void *src, uint32_t cnt); -typedef void (*pf_convert_from)(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt); -typedef void (*pf_convert_to)(PixelFormat *pf, - void *dst, QemuPixel *src, uint32_t cnt); - -struct QemuPfConv { - pf_convert convert; - PixelFormat src; - PixelFormat dst; - - /* for copy_generic() */ - pf_convert_from conv_from; - pf_convert_to conv_to; - QemuPixel *conv_buf; - uint32_t conv_cnt; -}; - -struct QemuPixel { - uint8_t red; - uint8_t green; - uint8_t blue; - uint8_t alpha; -}; - -/* ----------------------------------------------------------------------- */ -/* PixelFormat -> QemuPixel conversions */ - -static void conv_16_to_pixel(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt) -{ - uint16_t *src16 = src; - - while (cnt > 0) { - dst->red = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); - dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); - dst->blue = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); - dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits); - dst++, src16++, cnt--; - } -} - -/* assumes pf->{r,g,b,a}bits == 8 */ -static void conv_32_to_pixel_fast(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt) -{ - uint32_t *src32 = src; - - while (cnt > 0) { - dst->red = (*src32 & pf->rmask) >> pf->rshift; - dst->green = (*src32 & pf->gmask) >> pf->gshift; - dst->blue = (*src32 & pf->bmask) >> pf->bshift; - dst->alpha = (*src32 & pf->amask) >> pf->ashift; - dst++, src32++, cnt--; - } -} - -static void conv_32_to_pixel_generic(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt) -{ - uint32_t *src32 = src; - - while (cnt > 0) { - if (pf->rbits < 8) { - dst->red = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); - } else { - dst->red = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8); - } - if (pf->gbits < 8) { - dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); - } else { - dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8); - } - if (pf->bbits < 8) { - dst->blue = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); - } else { - dst->blue = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8); - } - if (pf->abits < 8) { - dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits); - } else { - dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8); - } - dst++, src32++, cnt--; - } -} - -/* ----------------------------------------------------------------------- */ -/* QemuPixel -> PixelFormat conversions */ - -static void conv_pixel_to_16(PixelFormat *pf, - void *dst, QemuPixel *src, uint32_t cnt) -{ - uint16_t *dst16 = dst; - - while (cnt > 0) { - *dst16 = ((uint16_t)src->red >> (8 - pf->rbits)) << pf->rshift; - *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift; - *dst16 |= ((uint16_t)src->blue >> (8 - pf->bbits)) << pf->bshift; - *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift; - dst16++, src++, cnt--; - } -} - -static void conv_pixel_to_32(PixelFormat *pf, - void *dst, QemuPixel *src, uint32_t cnt) -{ - uint32_t *dst32 = dst; - - while (cnt > 0) { - *dst32 = ((uint32_t)src->red >> (8 - pf->rbits)) << pf->rshift; - *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift; - *dst32 |= ((uint32_t)src->blue >> (8 - pf->bbits)) << pf->bshift; - *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift; - dst32++, src++, cnt--; - } -} - -/* ----------------------------------------------------------------------- */ -/* PixelFormat -> PixelFormat conversions */ - -static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) -{ - uint32_t bytes = cnt * conv->src.bytes_per_pixel; - memcpy(dst, src, bytes); -} - -static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) -{ - if (conv->conv_cnt < cnt) { - conv->conv_cnt = cnt; - conv->conv_buf = g_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt); - } - conv->conv_from(&conv->src, conv->conv_buf, src, cnt); - conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt); -} - -/* ----------------------------------------------------------------------- */ -/* public interface */ - -QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src) -{ - QemuPfConv *conv = g_malloc0(sizeof(QemuPfConv)); - - conv->src = *src; - conv->dst = *dst; - - if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) { - /* formats identical, can simply copy */ - conv->convert = convert_copy; - } else { - /* generic two-step conversion: src -> QemuPixel -> dst */ - switch (conv->src.bytes_per_pixel) { - case 2: - conv->conv_from = conv_16_to_pixel; - break; - case 4: - if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) { - conv->conv_from = conv_32_to_pixel_fast; - } else { - conv->conv_from = conv_32_to_pixel_generic; - } - break; - default: - goto err; - } - switch (conv->dst.bytes_per_pixel) { - case 2: - conv->conv_to = conv_pixel_to_16; - break; - case 4: - conv->conv_to = conv_pixel_to_32; - break; - default: - goto err; - } - conv->convert = convert_generic; - } - return conv; - -err: - g_free(conv); - return NULL; -} - -void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) -{ - conv->convert(conv, dst, src, cnt); -} - -void qemu_pf_conv_put(QemuPfConv *conv) -{ - if (conv) { - g_free(conv->conv_buf); - g_free(conv); - } -} diff --git a/pflib.h b/pflib.h deleted file mode 100644 index b70c313acf..0000000000 --- a/pflib.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __QEMU_PFLIB_H -#define __QEMU_PFLIB_H - -/* - * PixelFormat conversion library. - * - * Author: Gerd Hoffmann - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -typedef struct QemuPfConv QemuPfConv; - -QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src); -void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt); -void qemu_pf_conv_put(QemuPfConv *conv); - -#endif From bdd4df332a1bdb20b7fa39ea741f7830e41e1187 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 2 Nov 2012 09:37:27 +0100 Subject: [PATCH 7/7] spice: fix initialization order Register displaychangelistener last, after spice is fully initialized, otherwise we may hit NULL pointer dereferences when qemu starts calling our callbacks. Commit e250d949feb1334828f27f0d145c35f29c4b7639 triggers this bug. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 10 ++++++++-- ui/spice-display.c | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index e7bf3a11a7..1bc2d32aa8 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -2049,6 +2049,7 @@ static int qxl_init_primary(PCIDevice *dev) PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; PortioList *qxl_vga_port_list = g_new(PortioList, 1); + int rc; qxl->id = 0; qxl_init_ramsize(qxl); @@ -2063,9 +2064,14 @@ static int qxl_init_primary(PCIDevice *dev) qemu_spice_display_init_common(&qxl->ssd, vga->ds); qxl0 = qxl; - register_displaychangelistener(vga->ds, &display_listener); - return qxl_init_common(qxl); + rc = qxl_init_common(qxl); + if (rc != 0) { + return rc; + } + + register_displaychangelistener(vga->ds, &display_listener); + return rc; } static int qxl_init_secondary(PCIDevice *dev) diff --git a/ui/spice-display.c b/ui/spice-display.c index fe2fdfba68..0cc0116a5d 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -573,7 +573,6 @@ void qemu_spice_display_init(DisplayState *ds) { assert(sdpy.ds == NULL); qemu_spice_display_init_common(&sdpy, ds); - register_displaychangelistener(ds, &display_listener); sdpy.qxl.base.sif = &dpy_interface.base; qemu_spice_add_interface(&sdpy.qxl.base); @@ -581,4 +580,5 @@ void qemu_spice_display_init(DisplayState *ds) qemu_spice_create_host_memslot(&sdpy); qemu_spice_create_host_primary(&sdpy); + register_displaychangelistener(ds, &display_listener); }