diff options
Diffstat (limited to 'hw/display/qxl.c')
-rw-r--r-- | hw/display/qxl.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 0d02f0e..4d94cec 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -26,6 +26,7 @@ #include "qemu/queue.h" #include "qemu/atomic.h" #include "sysemu/sysemu.h" +#include "migration/migration.h" #include "trace.h" #include "qxl.h" @@ -304,6 +305,16 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) qxl->ssd.cursor = cursor_builtin_hidden(); } +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; +} + static ram_addr_t qxl_rom_size(void) { #define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes)) @@ -368,6 +379,18 @@ static void init_qxl_rom(PCIQXLDevice *d) rom->num_pages = cpu_to_le32(num_pages); rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size); + if (d->xres && d->yres) { + /* needs linux kernel 4.12+ to work */ + rom->client_monitors_config.count = 1; + rom->client_monitors_config.heads[0].left = 0; + rom->client_monitors_config.heads[0].top = 0; + rom->client_monitors_config.heads[0].right = cpu_to_le32(d->xres); + rom->client_monitors_config.heads[0].bottom = cpu_to_le32(d->yres); + rom->client_monitors_config_crc = qxl_crc32( + (const uint8_t *)&rom->client_monitors_config, + sizeof(rom->client_monitors_config)); + } + d->shadow_rom = *rom; d->rom = rom; d->modes = modes; @@ -639,6 +662,30 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) qxl->guest_primary.commands++; qxl_track_command(qxl, ext); qxl_log_command(qxl, "cmd", ext); + { + /* + * Windows 8 drivers place qxl commands in the vram + * (instead of the ram) bar. We can't live migrate such a + * guest, so add a migration blocker in case we detect + * this, to avoid triggering the assert in pre_save(). + * + * https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa + */ + void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + if (msg != NULL && ( + msg < (void *)qxl->vga.vram_ptr || + msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) { + if (!qxl->migration_blocker) { + Error *local_err = NULL; + error_setg(&qxl->migration_blocker, + "qxl: guest bug: command not in ram bar"); + migrate_add_blocker(qxl->migration_blocker, &local_err); + if (local_err) { + error_report_err(local_err); + } + } + } + } trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); return true; default: @@ -986,16 +1033,6 @@ static void interface_set_client_capabilities(QXLInstance *sin, qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); } -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; -} - static bool qxl_rom_monitors_config_changed(QXLRom *rom, VDAgentMonitorsConfig *monitors_config, unsigned int max_outputs) @@ -1146,6 +1183,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; + qemu_spice_display_switch(&d->ssd, d->ssd.ds); vga_dirty_log_start(&d->vga); graphic_hw_update(d->vga.con); } @@ -1235,6 +1273,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) qemu_spice_create_host_memslot(&d->ssd); qxl_soft_reset(d); + if (d->migration_blocker) { + migrate_del_blocker(d->migration_blocker); + error_free(d->migration_blocker); + d->migration_blocker = NULL; + } + if (startstop) { qemu_spice_display_start(); } @@ -2365,6 +2409,8 @@ static Property qxl_properties[] = { #if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0), #endif + DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0), + DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0), DEFINE_PROP_END_OF_LIST(), }; |