diff options
Diffstat (limited to 'hw/qxl.c')
-rw-r--r-- | hw/qxl.c | 314 |
1 files changed, 228 insertions, 86 deletions
@@ -125,9 +125,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) { -#if SPICE_INTERFACE_QXL_MINOR >= 1 qxl_send_events(qxl, QXL_INTERRUPT_ERROR); -#endif if (qxl->guestdebug) { va_list ap; va_start(ap, msg); @@ -143,18 +141,15 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, struct QXLRect *area, struct QXLRect *dirty_rects, uint32_t num_dirty_rects, uint32_t clear_dirty_region, - qxl_async_io async) + qxl_async_io async, struct QXLCookie *cookie) { if (async == QXL_SYNC) { qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects, num_dirty_rects, clear_dirty_region); } else { -#if SPICE_INTERFACE_QXL_MINOR >= 1 + assert(cookie != NULL); spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, - clear_dirty_region, 0); -#else - abort(); -#endif + clear_dirty_region, (uint64_t)cookie); } } @@ -170,25 +165,25 @@ static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, qxl_async_io async) { + QXLCookie *cookie; + if (async) { -#if SPICE_INTERFACE_QXL_MINOR < 1 - abort(); -#else - spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, - (uint64_t)id); -#endif + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_DESTROY_SURFACE_ASYNC); + cookie->u.surface_id = id; + spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); } else { qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); qxl_spice_destroy_surface_wait_complete(qxl, id); } } -#if SPICE_INTERFACE_QXL_MINOR >= 1 static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) { - spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); + spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_FLUSH_SURFACES_ASYNC)); } -#endif void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, uint32_t count) @@ -217,11 +212,9 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) { if (async) { -#if SPICE_INTERFACE_QXL_MINOR < 1 - abort(); -#else - spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); -#endif + spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); } else { qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); qxl_spice_destroy_surfaces_complete(qxl); @@ -490,7 +483,6 @@ static const char *io_port_to_string(uint32_t io_port) [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY", [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT", [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES", -#if SPICE_INTERFACE_QXL_MINOR >= 1 [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC", [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC", [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC", @@ -500,7 +492,6 @@ static const char *io_port_to_string(uint32_t io_port) = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", -#endif }; return io_port_to_string[io_port]; } @@ -625,7 +616,7 @@ static void interface_release_resource(QXLInstance *sin, if (ext.group_id == MEMSLOT_GROUP_HOST) { /* host group -> vga mode update request */ - qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); + qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id); return; } @@ -735,12 +726,9 @@ static int interface_flush_resources(QXLInstance *sin) static void qxl_create_guest_primary_complete(PCIQXLDevice *d); -#if SPICE_INTERFACE_QXL_MINOR >= 1 - /* called from spice server thread context only */ -static void interface_async_complete(QXLInstance *sin, uint64_t cookie) +static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); uint32_t current_async; qemu_mutex_lock(&qxl->async_lock); @@ -748,8 +736,22 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) qxl->current_async = QXL_UNDEFINED_IO; qemu_mutex_unlock(&qxl->async_lock); - dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); + dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); + if (!cookie) { + fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); + return; + } + if (cookie && current_async != cookie->io) { + fprintf(stderr, + "qxl: %s: error: current_async = %d != %ld = cookie->io\n", + __func__, current_async, cookie->io); + } switch (current_async) { + case QXL_IO_MEMSLOT_ADD_ASYNC: + case QXL_IO_DESTROY_PRIMARY_ASYNC: + case QXL_IO_UPDATE_AREA_ASYNC: + case QXL_IO_FLUSH_SURFACES_ASYNC: + break; case QXL_IO_CREATE_PRIMARY_ASYNC: qxl_create_guest_primary_complete(qxl); break; @@ -757,13 +759,75 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) qxl_spice_destroy_surfaces_complete(qxl); break; case QXL_IO_DESTROY_SURFACE_ASYNC: - qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie); + qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); break; + default: + fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__, + current_async); } qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); } -#endif +/* called from spice server thread context only */ +static void interface_update_area_complete(QXLInstance *sin, + uint32_t surface_id, + QXLRect *dirty, uint32_t num_updated_rects) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int i; + int qxl_i; + + qemu_mutex_lock(&qxl->ssd.lock); + if (surface_id != 0 || !qxl->render_update_cookie_num) { + qemu_mutex_unlock(&qxl->ssd.lock); + return; + } + if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { + /* + * overflow - treat this as a full update. Not expected to be common. + */ + dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); + qxl->guest_primary.resized = 1; + } + if (qxl->guest_primary.resized) { + /* + * Don't bother copying or scheduling the bh since we will flip + * the whole area anyway on completion of the update_area async call + */ + qemu_mutex_unlock(&qxl->ssd.lock); + return; + } + qxl_i = qxl->num_dirty_rects; + for (i = 0; i < num_updated_rects; i++) { + qxl->dirty[qxl_i++] = dirty[i]; + } + qxl->num_dirty_rects += num_updated_rects; + dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", + __func__, qxl->num_dirty_rects); + qemu_bh_schedule(qxl->update_area_bh); + qemu_mutex_unlock(&qxl->ssd.lock); +} + +/* called from spice server thread context only */ +static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLCookie *cookie = (QXLCookie *)cookie_token; + + switch (cookie->type) { + case QXL_COOKIE_TYPE_IO: + interface_async_complete_io(qxl, cookie); + g_free(cookie); + break; + case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: + qxl_render_update_area_done(qxl, cookie); + break; + default: + fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", + __func__, cookie->type); + g_free(cookie); + } +} static const QXLInterface qxl_interface = { .base.type = SPICE_INTERFACE_QXL, @@ -784,9 +848,8 @@ static const QXLInterface qxl_interface = { .req_cursor_notification = interface_req_cursor_notification, .notify_update = interface_notify_update, .flush_resources = interface_flush_resources, -#if SPICE_INTERFACE_QXL_MINOR >= 1 .async_complete = interface_async_complete, -#endif + .update_area_complete = interface_update_area_complete, }; static void qxl_enter_vga_mode(PCIQXLDevice *d) @@ -913,6 +976,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, static const int regions[] = { QXL_RAM_RANGE_INDEX, QXL_VRAM_RANGE_INDEX, + QXL_VRAM64_RANGE_INDEX, }; uint64_t guest_start; uint64_t guest_end; @@ -959,6 +1023,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram); break; case QXL_VRAM_RANGE_INDEX: + case 4 /* vram 64bit */: virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar); break; default: @@ -1006,7 +1071,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) qxl_spice_destroy_surfaces(d, QXL_SYNC); } -/* called from spice server thread context only */ +/* can be also called from spice server thread context */ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) { uint64_t phys = le64_to_cpu(pqxl); @@ -1015,7 +1080,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) switch (group_id) { case MEMSLOT_GROUP_HOST: - return (void*)offset; + return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: PANIC_ON(slot >= NUM_MEMSLOTS); PANIC_ON(!qxl->guest_slots[slot].active); @@ -1077,9 +1142,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) if (d->mode == QXL_MODE_UNDEFINED) { return 0; } - dprint(d, 1, "%s\n", __FUNCTION__); - d->mode = QXL_MODE_UNDEFINED; qemu_spice_destroy_primary_surface(&d->ssd, 0, async); qxl_spice_reset_cursor(d); @@ -1136,9 +1199,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, PCIQXLDevice *d = opaque; uint32_t io_port = addr; qxl_async_io async = QXL_SYNC; -#if SPICE_INTERFACE_QXL_MINOR >= 1 uint32_t orig_io_port = io_port; -#endif switch (io_port) { case QXL_IO_RESET: @@ -1148,10 +1209,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, case QXL_IO_CREATE_PRIMARY: case QXL_IO_UPDATE_IRQ: case QXL_IO_LOG: -#if SPICE_INTERFACE_QXL_MINOR >= 1 case QXL_IO_MEMSLOT_ADD_ASYNC: case QXL_IO_CREATE_PRIMARY_ASYNC: -#endif break; default: if (d->mode != QXL_MODE_VGA) { @@ -1159,17 +1218,14 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, } dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", __func__, io_port, io_port_to_string(io_port)); -#if SPICE_INTERFACE_QXL_MINOR >= 1 /* be nice to buggy guest drivers */ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { qxl_send_events(d, QXL_INTERRUPT_IO_CMD); } -#endif return; } -#if SPICE_INTERFACE_QXL_MINOR >= 1 /* we change the io_port to avoid ifdeffery in the main switch */ orig_io_port = io_port; switch (io_port) { @@ -1208,14 +1264,21 @@ async_common: default: break; } -#endif switch (io_port) { case QXL_IO_UPDATE_AREA: { + QXLCookie *cookie = NULL; QXLRect update = d->ram->update_area; + + if (async == QXL_ASYNC) { + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_UPDATE_AREA_ASYNC); + cookie->u.area = update; + } qxl_spice_update_area(d, d->ram->update_surface, - &update, NULL, 0, 0, async); + cookie ? &cookie->u.area : &update, + NULL, 0, 0, async, cookie); break; } case QXL_IO_NOTIFY_CMD: @@ -1300,7 +1363,6 @@ async_common: } qxl_spice_destroy_surface_wait(d, val, async); break; -#if SPICE_INTERFACE_QXL_MINOR >= 1 case QXL_IO_FLUSH_RELEASE: { QXLReleaseRing *ring = &d->ram->release_ring; if (ring->prod - ring->cons + 1 == ring->num_items) { @@ -1321,7 +1383,6 @@ async_common: d->num_free_res); qxl_spice_flush_surfaces_async(d); break; -#endif case QXL_IO_DESTROY_ALL_SURFACES: d->mode = QXL_MODE_UNDEFINED; qxl_spice_destroy_surfaces(d, async); @@ -1332,16 +1393,12 @@ async_common: } return; cancel_async: -#if SPICE_INTERFACE_QXL_MINOR >= 1 if (async) { qxl_send_events(d, QXL_INTERRUPT_IO_CMD); qemu_mutex_lock(&d->async_lock); d->current_async = QXL_UNDEFINED_IO; qemu_mutex_unlock(&d->async_lock); } -#else - return; -#endif } static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, @@ -1435,7 +1492,7 @@ static void qxl_hw_invalidate(void *opaque) vga->invalidate(vga); } -static void qxl_hw_screen_dump(void *opaque, const char *filename) +static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch) { PCIQXLDevice *qxl = opaque; VGACommonState *vga = &qxl->vga; @@ -1447,7 +1504,7 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename) ppm_save(filename, qxl->ssd.ds->surface); break; case QXL_MODE_VGA: - vga->screen_dump(vga, filename); + vga->screen_dump(vga, filename, cswitch); break; default: break; @@ -1465,6 +1522,46 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) } } +static void qxl_dirty_surfaces(PCIQXLDevice *qxl) +{ + intptr_t vram_start; + int i; + + if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { + return; + } + + /* dirty the primary surface */ + qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, + qxl->shadow_rom.surface0_area_size); + + vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); + + /* dirty the off-screen surfaces */ + for (i = 0; i < NUM_SURFACES; i++) { + QXLSurfaceCmd *cmd; + intptr_t surface_offset; + int surface_size; + + if (qxl->guest_surfaces.cmds[i] == 0) { + continue; + } + + cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], + MEMSLOT_GROUP_GUEST); + assert(cmd->type == QXL_SURFACE_CMD_CREATE); + surface_offset = (intptr_t)qxl_phys2virt(qxl, + cmd->u.surface_create.data, + MEMSLOT_GROUP_GUEST); + surface_offset -= vram_start; + surface_size = cmd->u.surface_create.height * + abs(cmd->u.surface_create.stride); + dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, + i, (int)surface_offset, surface_size); + qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); + } +} + static void qxl_vm_change_state_handler(void *opaque, int running, RunState state) { @@ -1478,14 +1575,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running, * called */ qxl_update_irq(qxl); - } else if (qxl->mode == QXL_MODE_NATIVE) { - /* dirty all vram (which holds surfaces) and devram (primary surface) - * to make sure they are saved */ - /* FIXME #1: should go out during "live" stage */ - /* FIXME #2: we only need to save the areas which are actually used */ - qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size); - qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, - qxl->shadow_rom.surface0_area_size); + } else { + /* make sure surfaces are saved before migration */ + qxl_dirty_surfaces(qxl); } } @@ -1509,6 +1601,10 @@ static void display_refresh(struct DisplayState *ds) { if (qxl0->mode == QXL_MODE_VGA) { qemu_spice_display_refresh(&qxl0->ssd); + } else { + qemu_mutex_lock(&qxl0->ssd.lock); + qemu_spice_cursor_refresh_unlocked(&qxl0->ssd); + qemu_mutex_unlock(&qxl0->ssd.lock); } } @@ -1518,6 +1614,41 @@ static DisplayChangeListener display_listener = { .dpy_refresh = display_refresh, }; +static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) +{ + /* vga ram (bar 0) */ + if (qxl->ram_size_mb != -1) { + qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024; + } + if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { + qxl->vga.vram_size = ram_min_mb * 1024 * 1024; + } + + /* vram32 (surfaces, 32bit, bar 1) */ + if (qxl->vram32_size_mb != -1) { + qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024; + } + if (qxl->vram32_size < 4096) { + qxl->vram32_size = 4096; + } + + /* vram (surfaces, 64bit, bar 4+5) */ + if (qxl->vram_size_mb != -1) { + qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; + } + if (qxl->vram_size < qxl->vram32_size) { + qxl->vram_size = qxl->vram32_size; + } + + if (qxl->revision == 1) { + qxl->vram32_size = 4096; + qxl->vram_size = 4096; + } + qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1); + qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); +} + static int qxl_init_common(PCIQXLDevice *qxl) { uint8_t* config = qxl->pci.config; @@ -1539,9 +1670,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) case 2: /* spice 0.6 -- qxl-2 */ pci_device_rev = QXL_REVISION_STABLE_V06; break; -#if SPICE_INTERFACE_QXL_MINOR >= 1 case 3: /* qxl-3 */ -#endif default: pci_device_rev = QXL_DEFAULT_REVISION; break; @@ -1556,15 +1685,10 @@ static int qxl_init_common(PCIQXLDevice *qxl) init_qxl_rom(qxl); init_qxl_ram(qxl); - if (qxl->vram_size < 16 * 1024 * 1024) { - qxl->vram_size = 16 * 1024 * 1024; - } - if (qxl->revision == 1) { - qxl->vram_size = 4096; - } - qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size); vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); + memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, + 0, qxl->vram32_size); io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); if (qxl->revision == 1) { @@ -1588,7 +1712,29 @@ static int qxl_init_common(PCIQXLDevice *qxl) PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram); pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, - PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar); + PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar); + + if (qxl->vram32_size < qxl->vram_size) { + /* + * Make the 64bit vram bar show up only in case it is + * configured to be larger than the 32bit vram bar. + */ + pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH, + &qxl->vram_bar); + } + + /* print pci bar details */ + dprint(qxl, 1, "ram/%s: %d MB [region 0]\n", + qxl->id == 0 ? "pri" : "sec", + qxl->vga.vram_size / (1024*1024)); + dprint(qxl, 1, "vram/32: %d MB [region 1]\n", + qxl->vram32_size / (1024*1024)); + dprint(qxl, 1, "vram/64: %d MB %s\n", + qxl->vram_size / (1024*1024), + qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]"); qxl->ssd.qxl.base.sif = &qxl_interface.base; qxl->ssd.qxl.id = qxl->id; @@ -1598,6 +1744,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) init_pipe_signaling(qxl); qxl_reset_state(qxl); + qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl); + return 0; } @@ -1605,15 +1753,11 @@ static int qxl_init_primary(PCIDevice *dev) { PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; - ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); PortioList *qxl_vga_port_list = g_new(PortioList, 1); qxl->id = 0; - - if (ram_size < 32 * 1024 * 1024) { - ram_size = 32 * 1024 * 1024; - } - vga_common_init(vga, ram_size); + qxl_init_ramsize(qxl, 32); + vga_common_init(vga, qxl->vga.vram_size); vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false); portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); @@ -1632,14 +1776,9 @@ static int qxl_init_secondary(PCIDevice *dev) { static int device_id = 1; PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); - ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); qxl->id = device_id++; - - if (ram_size < 16 * 1024 * 1024) { - ram_size = 16 * 1024 * 1024; - } - qxl->vga.vram_size = ram_size; + qxl_init_ramsize(qxl, 16); memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size); vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev); qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); @@ -1814,13 +1953,16 @@ static VMStateDescription qxl_vmstate = { static Property qxl_properties[] = { DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), - DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, + DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size, 64 * 1024 * 1024), DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, QXL_DEFAULT_REVISION), DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), + DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), + DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), DEFINE_PROP_END_OF_LIST(), }; |