* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <pthread.h>
-
#include "qemu-common.h"
#include "qemu-timer.h"
#include "qemu-queue.h"
void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
{
qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+ qemu_mutex_lock(&qxl->track_lock);
+ qxl->guest_cursor = 0;
+ qemu_mutex_unlock(&qxl->track_lock);
}
static void init_qxl_rom(PCIQXLDevice *d)
{
- QXLRom *rom = qemu_get_ram_ptr(d->rom_offset);
+ QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
QXLModes *modes = (QXLModes *)(rom + 1);
uint32_t ram_header_size;
uint32_t surface0_area_size;
d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC);
d->ram->int_pending = cpu_to_le32(0);
d->ram->int_mask = cpu_to_le32(0);
+ d->ram->update_surface = 0;
SPICE_RING_INIT(&d->ram->cmd_ring);
SPICE_RING_INIT(&d->ram->cursor_ring);
SPICE_RING_INIT(&d->ram->release_ring);
}
/* can be called from spice server thread context */
-static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end)
+static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
{
while (addr < end) {
- cpu_physical_memory_set_dirty(addr);
+ memory_region_set_dirty(mr, addr);
addr += TARGET_PAGE_SIZE;
}
}
static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
{
- ram_addr_t addr = qxl->rom_offset;
- qxl_set_dirty(addr, addr + qxl->rom_size);
+ qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
}
/* called from spice server thread context only */
static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
{
- ram_addr_t addr = qxl->vga.vram_offset;
void *base = qxl->vga.vram_ptr;
intptr_t offset;
offset = ptr - base;
offset &= ~(TARGET_PAGE_SIZE-1);
assert(offset < qxl->vga.vram_size);
- qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE);
+ qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
}
/* can be called from spice server thread context */
static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
{
- ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset;
- ram_addr_t end = qxl->vga.vram_offset + qxl->vga.vram_size;
- qxl_set_dirty(addr, end);
+ ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
+ ram_addr_t end = qxl->vga.vram_size;
+ qxl_set_dirty(&qxl->vga.vram, addr, end);
}
/*
{
QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
if (cmd->type == QXL_CURSOR_SET) {
+ qemu_mutex_lock(&qxl->track_lock);
qxl->guest_cursor = ext->cmd.data;
+ qemu_mutex_unlock(&qxl->track_lock);
}
break;
}
qxl_destroy_primary(d, QXL_SYNC);
}
-static void qxl_set_irq(PCIQXLDevice *d)
+static void qxl_update_irq(PCIQXLDevice *d)
{
uint32_t pending = le32_to_cpu(d->ram->int_pending);
uint32_t mask = le32_to_cpu(d->ram->int_mask);
qxl_ring_set_dirty(d);
}
-static void qxl_write_config(PCIDevice *d, uint32_t address,
- uint32_t val, int len)
-{
- PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d);
- VGACommonState *vga = &qxl->vga;
-
- vga_dirty_log_stop(vga);
- pci_default_write_config(d, address, val, len);
- if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) {
- vga->map_addr = 0;
- }
- vga_dirty_log_start(vga);
-}
-
static void qxl_check_state(PCIQXLDevice *d)
{
QXLRam *ram = d->ram;
- assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
- assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+ assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+ assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
}
static void qxl_reset_state(PCIQXLDevice *d)
{
- QXLRam *ram = d->ram;
QXLRom *rom = d->rom;
- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+ qxl_check_state(d);
d->shadow_rom.update_id = cpu_to_le32(0);
*rom = d->shadow_rom;
qxl_rom_set_dirty(d);
switch (pci_region) {
case QXL_RAM_RANGE_INDEX:
- virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset);
+ virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
break;
case QXL_VRAM_RANGE_INDEX:
- virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset);
+ virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
break;
default:
/* should not happen */
memslot.generation = d->rom->slot_generation = 0;
qxl_rom_set_dirty(d);
- dprint(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n",
+ dprint(d, 1, "%s: slot %d: host virt 0x%lx - 0x%lx\n",
__FUNCTION__, memslot.slot_id,
memslot.virt_start, memslot.virt_end);
d->mode = QXL_MODE_UNDEFINED;
qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+ qxl_spice_reset_cursor(d);
return 1;
}
.mem = devmem + d->shadow_rom.draw_area_offset,
};
- dprint(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__,
- modenr, mode->x_res, mode->y_res, mode->bits, devmem);
+ dprint(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%" PRIx64 " ]\n",
+ __func__, modenr, mode->x_res, mode->y_res, mode->bits, devmem);
if (!loadvm) {
qxl_hard_reset(d, 0);
}
qxl_rom_set_dirty(d);
}
-static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ioport_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
PCIQXLDevice *d = opaque;
- uint32_t io_port = addr - d->io_base;
+ uint32_t io_port = addr;
qxl_async_io async = QXL_SYNC;
#if SPICE_INTERFACE_QXL_MINOR >= 1
uint32_t orig_io_port = io_port;
}
d->current_async = orig_io_port;
qemu_mutex_unlock(&d->async_lock);
- dprint(d, 2, "start async %d (%d)\n", io_port, val);
+ dprint(d, 2, "start async %d (%"PRId64")\n", io_port, val);
break;
default:
break;
qemu_spice_wakeup(&d->ssd);
break;
case QXL_IO_UPDATE_IRQ:
- qxl_set_irq(d);
+ qxl_update_irq(d);
break;
case QXL_IO_NOTIFY_OOM:
- if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
- break;
- }
- pthread_yield();
if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
break;
}
d->oom_running = 0;
break;
case QXL_IO_SET_MODE:
- dprint(d, 1, "QXL_SET_MODE %d\n", val);
+ dprint(d, 1, "QXL_SET_MODE %d\n", (int)val);
qxl_set_mode(d, val, 0);
break;
case QXL_IO_LOG:
if (d->guestdebug) {
- fprintf(stderr, "qxl/guest-%d: %ld: %s", d->id,
+ fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
qemu_get_clock_ns(vm_clock), d->ram->log_buf);
}
break;
break;
}
case QXL_IO_FLUSH_SURFACES_ASYNC:
- dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n",
+ dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC"
+ " (%"PRId64") (%s, s#=%d, res#=%d)\n",
val, qxl_mode_to_string(d->mode), d->guest_surfaces.count,
d->num_free_res);
qxl_spice_flush_surfaces_async(d);
#endif
}
-static uint32_t ioport_read(void *opaque, uint32_t addr)
+static uint64_t ioport_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
PCIQXLDevice *d = opaque;
return 0xff;
}
-static void qxl_map(PCIDevice *pci, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- static const char *names[] = {
- [ QXL_IO_RANGE_INDEX ] = "ioports",
- [ QXL_RAM_RANGE_INDEX ] = "devram",
- [ QXL_ROM_RANGE_INDEX ] = "rom",
- [ QXL_VRAM_RANGE_INDEX ] = "vram",
- };
- PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci);
-
- dprint(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__,
- region_num, names[region_num], addr, size);
-
- switch (region_num) {
- case QXL_IO_RANGE_INDEX:
- register_ioport_write(addr, size, 1, ioport_write, pci);
- register_ioport_read(addr, size, 1, ioport_read, pci);
- qxl->io_base = addr;
- break;
- case QXL_RAM_RANGE_INDEX:
- cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM);
- qxl->vga.map_addr = addr;
- qxl->vga.map_end = addr + size;
- if (qxl->id == 0) {
- vga_dirty_log_start(&qxl->vga);
- }
- break;
- case QXL_ROM_RANGE_INDEX:
- cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM);
- break;
- case QXL_VRAM_RANGE_INDEX:
- cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM);
- break;
- }
-}
+static const MemoryRegionOps qxl_io_ops = {
+ .read = ioport_read,
+ .write = ioport_write,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
static void pipe_read(void *opaque)
{
do {
len = read(d->pipe[0], &dummy, sizeof(dummy));
} while (len == sizeof(dummy));
- qxl_set_irq(d);
+ qxl_update_irq(d);
}
-/* called from spice server thread context only */
static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
{
uint32_t old_pending;
if ((old_pending & le_events) == le_events) {
return;
}
- if (pthread_self() == d->main) {
- qxl_set_irq(d);
+ if (qemu_thread_is_self(&d->main)) {
+ qxl_update_irq(d);
} else {
if (write(d->pipe[1], d, 1) != 1) {
dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
return;
}
-#ifdef CONFIG_IOTHREAD
fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
-#else
- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
-#endif
fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
fcntl(d->pipe[0], F_SETOWN, getpid());
- d->main = pthread_self();
+ qemu_thread_get_self(&d->main);
qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
}
}
}
-static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
+static void qxl_vm_change_state_handler(void *opaque, int running,
+ RunState state)
{
PCIQXLDevice *qxl = opaque;
- qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
-
- if (!running && qxl->mode == QXL_MODE_NATIVE) {
+ qemu_spice_vm_change_state_handler(&qxl->ssd, running, state);
+
+ if (running) {
+ /*
+ * if qxl_send_events was called from spice server context before
+ * migration ended, qxl_update_irq for these events might not have been
+ * 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 */
- ram_addr_t vram_addr = qxl->vram_offset;
- ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
- qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size);
- qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
+ 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);
}
}
pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
qxl->rom_size = qxl_rom_size();
- qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
+ memory_region_init_ram(&qxl->rom_bar, &qxl->pci.qdev, "qxl.vrom",
+ qxl->rom_size);
init_qxl_rom(qxl);
init_qxl_ram(qxl);
qxl->vram_size = 4096;
}
qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
- qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
+ memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram",
+ qxl->vram_size);
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
if (qxl->revision == 1) {
io_size = 8;
}
+ memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
+ "qxl-ioports", io_size);
+ if (qxl->id == 0) {
+ vga_dirty_log_start(&qxl->vga);
+ }
+
+
pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
- io_size, PCI_BASE_ADDRESS_SPACE_IO, qxl_map);
+ PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
- qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
- qxl_map);
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
- qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
- qxl_map);
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
- pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size,
- PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map);
+ pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar);
qxl->ssd.qxl.base.sif = &qxl_interface.base;
qxl->ssd.qxl.id = qxl->id;
ram_size = 32 * 1024 * 1024;
}
vga_common_init(vga, ram_size);
- vga_init(vga);
+ vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga);
register_ioport_write(0x3b4, 2, 1, qxl_vga_ioport_write, vga);
register_ioport_write(0x3d4, 2, 1, qxl_vga_ioport_write, vga);
ram_size = 16 * 1024 * 1024;
}
qxl->vga.vram_size = ram_size;
- qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
- qxl->vga.vram_size);
- qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
+ memory_region_init_ram(&qxl->vga.vram, &qxl->pci.qdev, "qxl.vgavram",
+ qxl->vga.vram_size);
+ qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
return qxl_init_common(qxl);
}
return 0;
}
+static void qxl_create_memslots(PCIQXLDevice *d)
+{
+ int i;
+
+ for (i = 0; i < NUM_MEMSLOTS; i++) {
+ if (!d->guest_slots[i].active) {
+ continue;
+ }
+ dprint(d, 1, "%s: restoring guest slot %d\n", __func__, i);
+ qxl_add_memslot(d, i, 0, QXL_SYNC);
+ }
+}
+
static int qxl_post_load(void *opaque, int version)
{
PCIQXLDevice* d = opaque;
uint8_t *ram_start = d->vga.vram_ptr;
QXLCommandExt *cmds;
- int in, out, i, newmode;
+ int in, out, newmode;
dprint(d, 1, "%s: start\n", __FUNCTION__);
qxl_mode_to_string(d->mode));
newmode = d->mode;
d->mode = QXL_MODE_UNDEFINED;
+
switch (newmode) {
case QXL_MODE_UNDEFINED:
break;
case QXL_MODE_VGA:
+ qxl_create_memslots(d);
qxl_enter_vga_mode(d);
break;
case QXL_MODE_NATIVE:
- for (i = 0; i < NUM_MEMSLOTS; i++) {
- if (!d->guest_slots[i].active) {
- continue;
- }
- qxl_add_memslot(d, i, 0, QXL_SYNC);
- }
+ qxl_create_memslots(d);
qxl_create_guest_primary(d, 1, QXL_SYNC);
/* replay surface-create and cursor-set commands */
- cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
+ cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
for (in = 0, out = 0; in < NUM_SURFACES; in++) {
if (d->guest_surfaces.cmds[in] == 0) {
continue;
cmds[out].group_id = MEMSLOT_GROUP_GUEST;
out++;
}
- cmds[out].cmd.data = d->guest_cursor;
- cmds[out].cmd.type = QXL_CMD_CURSOR;
- cmds[out].group_id = MEMSLOT_GROUP_GUEST;
- out++;
+ if (d->guest_cursor) {
+ cmds[out].cmd.data = d->guest_cursor;
+ cmds[out].cmd.type = QXL_CMD_CURSOR;
+ cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+ out++;
+ }
qxl_spice_loadvm_commands(d, cmds, out);
- qemu_free(cmds);
+ g_free(cmds);
break;
case QXL_MODE_COMPAT:
+ /* note: no need to call qxl_create_memslots, qxl_set_mode
+ * creates the mem slot. */
qxl_set_mode(d, d->shadow_rom.mode, 1);
break;
}
},
};
+static Property qxl_properties[] = {
+ DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+ 64 * 1024 * 1024),
+ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_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_END_OF_LIST(),
+};
+
static PCIDeviceInfo qxl_info_primary = {
.qdev.name = "qxl-vga",
.qdev.desc = "Spice QXL GPU (primary, vga compatible)",
.qdev.vmsd = &qxl_vmstate,
.no_hotplug = 1,
.init = qxl_init_primary,
- .config_write = qxl_write_config,
.romfile = "vgabios-qxl.bin",
.vendor_id = REDHAT_PCI_VENDOR_ID,
.device_id = QXL_DEVICE_ID_STABLE,
.class_id = PCI_CLASS_DISPLAY_VGA,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
- 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_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_END_OF_LIST(),
- }
+ .qdev.props = qxl_properties,
};
static PCIDeviceInfo qxl_info_secondary = {
.vendor_id = REDHAT_PCI_VENDOR_ID,
.device_id = QXL_DEVICE_ID_STABLE,
.class_id = PCI_CLASS_DISPLAY_OTHER,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
- 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_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_END_OF_LIST(),
- }
+ .qdev.props = qxl_properties,
};
static void qxl_register(void)