From 242b7cd981d8e1adcf401054a314ef9bef49e88a Mon Sep 17 00:00:00 2001 From: Izik Eidus Date: Thu, 28 Jan 2010 04:45:12 +0200 Subject: qemu: qxl device: add surface 0 support no detach/attach anymore, memory is still alive no matter what. Signed-off-by: Izik Eidus --- qemu/configure | 2 +- qemu/hw/qxl.c | 522 +++++++++++++++++++++----------------------- qemu/hw/qxl_dev.h | 45 +++- qemu/hw/qxl_interface.h | 35 ++- qemu/hw/qxl_native_worker.c | 151 +++++++++---- qemu/hw/ring.h | 20 +- 6 files changed, 436 insertions(+), 339 deletions(-) diff --git a/qemu/configure b/qemu/configure index 5c3d36f8..e3142727 100755 --- a/qemu/configure +++ b/qemu/configure @@ -1220,7 +1220,7 @@ fi ########################################## # spice probe if test "$spice" = "yes" ; then - `pkg-config --atleast-version=0.5.1 spice` || spice="no" + `pkg-config --atleast-version=0.5.2 spice` || spice="no" fi if test "$spice" = "yes" ; then cat > $TMPC << EOF diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c index 60210efb..890d521c 100644 --- a/qemu/hw/qxl.c +++ b/qemu/hw/qxl.c @@ -82,6 +82,7 @@ typedef struct __attribute__ ((__packed__)) PCIConf_s /*little-endian*/ { } PCIConf; #define NUM_MEMSLOTS 256 +#define NUM_MEMSLOTS_GROUPS 2 #define MEMSLOT_GENERATION_BITS 8 #define MEMSLOT_SLOT_BITS 8 @@ -115,7 +116,7 @@ typedef struct QXLState { QXLAddressRange *address_ranges; uint8_t num_ranges; - MemSlot mem_slots[NUM_MEMSLOTS]; + MemSlot mem_slots[NUM_MEMSLOTS_GROUPS][NUM_MEMSLOTS]; uint8_t *vram; unsigned long vram_offset; @@ -131,6 +132,10 @@ typedef struct QXLState { QXLCommandRing vga_ring; uint32_t bits_unique; int running; + QXLCommandRing *rings_flip[2]; + int send_event_flip[2]; + int group_ids_flip[2]; + int flip_counter; } QXLState; typedef struct PCIQXLDevice PCIQXLDevice; @@ -332,81 +337,61 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) } } -static void set_dreaw_area(PCIQXLDevice *d, QXLDevInfo *info) -{ - int stride = info->x_res * sizeof(uint32_t); - info->draw_area.buf = (uint8_t *)d->state.ram_start + d->state.rom->draw_area_offset; - info->draw_area.size = stride * info->y_res; - info->draw_area.line_0 = info->draw_area.buf + info->draw_area.size - stride; - info->draw_area.stride = -stride; - info->draw_area.width = info->x_res; - info->draw_area.heigth = info->y_res; -} - static void _qxl_get_init_info(PCIQXLDevice *d, QXLDevInitInfo *info) { info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; info->memslot_id_bits = MEMSLOT_SLOT_BITS; info->num_memslots = NUM_MEMSLOTS; + info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; + info->internal_groupslot_id = 0; + info->qxl_ram_size = d->state.rom->num_pages << TARGET_PAGE_BITS; } -static void _qxl_get_info(PCIQXLDevice *d, QXLDevInfo *info) +static int qxl_get_ring_command(PCIQXLDevice *d, QXLCommandExt *cmd_ext, QXLCommandRing *ring, + int group_id, int send_event) { - QXLState *state = &d->state; - QXLMode *mode; - - info->ram_size = state->rom->num_io_pages << TARGET_PAGE_BITS; - - if (state->mode == QXL_MODE_VGA) { - info->x_res = qxl_vga.ds->width; - info->y_res = qxl_vga.ds->height; - info->bits = qxl_vga.ds->depth; - info->use_hardware_cursor = FALSE; - - set_dreaw_area(d, info); - return; - } - - mode = &qxl_modes[d->state.rom->mode]; - - info->x_res = mode->x_res; - info->y_res = mode->y_res; - info->bits = mode->bits; - info->use_hardware_cursor = TRUE; - - set_dreaw_area(d, info); -} - -static QXLCommandRing *qxl_active_ring(PCIQXLDevice *d) -{ - return (d->state.mode == QXL_MODE_VGA) ? &d->state.vga_ring : &d->state.ram->cmd_ring; -} - -static int _qxl_get_command(PCIQXLDevice *d, QXLCommand *cmd) -{ - QXLCommandRing *ring = qxl_active_ring(d); int notify; - + QXLCommand* cmd; + if (RING_IS_EMPTY(ring)) { return FALSE; } - *cmd = *RING_CONS_ITEM(ring); + + RING_CONS_ITEM_SAFE(ring, ring, ring + 1, cmd) + cmd_ext->group_id = group_id; + cmd_ext->cmd = *cmd; RING_POP(ring, notify); - if (d->state.mode != QXL_MODE_VGA && notify) { + if (send_event && notify) { qxl_send_events(d, QXL_INTERRUPT_DISPLAY); } return TRUE; } +static int _qxl_get_command(PCIQXLDevice *d, QXLCommandExt *cmd) +{ + int x = 0; + + for (; x < 2; ++x) { + if (qxl_get_ring_command(d, cmd, d->state.rings_flip[d->state.flip_counter % 2], + d->state.group_ids_flip[d->state.flip_counter % 2], + d->state.send_event_flip[d->state.flip_counter % 2])) { + d->state.flip_counter++; + return TRUE; + } + d->state.flip_counter++; + } + return FALSE; +} + static int _qxl_has_command(PCIQXLDevice *d) { - QXLCommandRing *ring = qxl_active_ring(d); - return !RING_IS_EMPTY(ring); + return !RING_IS_EMPTY(d->state.rings_flip[0]) | !RING_IS_EMPTY(d->state.rings_flip[1]); } -static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommand *cmd) +static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommandExt *cmd_ext) { QXLCursorRing *ring; + QXLCommand* cmd; int notify; if (d->state.mode == QXL_MODE_VGA) { @@ -418,9 +403,11 @@ static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommand *cmd) if (RING_IS_EMPTY(ring)) { return 0; } - *cmd = *RING_CONS_ITEM(ring); + RING_CONS_ITEM_SAFE(ring, ring, ring + 1, cmd); + cmd_ext->group_id = 1; + cmd_ext->cmd = *cmd; RING_POP(ring, notify); - if (d->state.mode != QXL_MODE_VGA && notify) { + if (notify) { qxl_send_events(d, QXL_INTERRUPT_CURSOR); } return 1; @@ -434,18 +421,19 @@ static const Rect *_qxl_get_update_area(PCIQXLDevice *d) static int _qxl_req_cmd_notification(PCIQXLDevice *d) { int wait; - RING_CONS_WAIT(qxl_active_ring(d), wait); - return wait; + + RING_CONS_WAIT(&d->state.ram->cmd_ring, wait); + if (wait) { + RING_CONS_WAIT(&d->state.vga_ring, wait); + return wait; + } + return 0; } static int _qxl_req_cursor_notification(PCIQXLDevice *d) { int wait; - if (d->state.mode == QXL_MODE_VGA) { - return 1; - } - RING_CONS_WAIT(&d->state.ram->cursor_ring, wait); return wait; } @@ -456,8 +444,8 @@ static inline void qxl_push_free_res(PCIQXLDevice *d) { QXLState *state = &d->state; QXLReleaseRing *ring = &state->ram->release_ring; + UINT64 *item; - ASSERT(state->mode != QXL_MODE_VGA); if (RING_IS_EMPTY(ring) || (state->num_free_res == QXL_FREE_BUNCH_SIZE && ring->prod - ring->cons + 1 != ring->num_items)) { int notify; @@ -466,25 +454,27 @@ static inline void qxl_push_free_res(PCIQXLDevice *d) if (notify) { qxl_send_events(d, QXL_INTERRUPT_DISPLAY); } - *RING_PROD_ITEM(ring) = 0; + RING_PROD_ITEM_SAFE(ring, ring, ring + 1, item); + *item = 0; state->num_free_res = 0; state->last_release = NULL; } } -static void _qxl_release_resource(PCIQXLDevice *d, QXLReleaseInfo *release_info) +static void _qxl_release_resource(PCIQXLDevice *d, QXLReleaseInfoExt *release_info_ext) { + QXLReleaseInfo *release_info = release_info_ext->info; UINT64 id = release_info->id; QXLState *state = &d->state; QXLReleaseRing *ring; UINT64 *item; - if (state->mode == QXL_MODE_VGA) { + if (release_info_ext->group_id == 0) { free((void *)id); return; } ring = &state->ram->release_ring; - item = RING_PROD_ITEM(ring); + RING_PROD_ITEM_SAFE(ring, ring, ring + 1, item); if (*item == 0) { release_info->next = 0; *item = id; @@ -518,9 +508,7 @@ static void *_qxl_get_save_data(PCIQXLDevice *d) static int _qxl_flush_resources(PCIQXLDevice *d) { int ret; - if (d->state.mode == QXL_MODE_VGA) { - return 0; - } + ret = d->state.num_free_res; if (ret) { qxl_push_free_res(d); @@ -530,22 +518,14 @@ static int _qxl_flush_resources(PCIQXLDevice *d) static void _qxl_notify_update(PCIQXLDevice *d, uint32_t update_id) { - if (d->state.mode == QXL_MODE_VGA) { - return; - } d->state.rom->update_id = update_id; qxl_send_events(d, QXL_INTERRUPT_DISPLAY); } -static void qxl_detach(PCIQXLDevice *d) +static void qxl_release_commands(PCIQXLDevice *d) { QXLCommandRing *ring; - if (d->state.mode == QXL_MODE_UNDEFINED) { - return; - } - - d->worker->detach(d->worker); if (d->state.mode != QXL_MODE_VGA) { RING_INIT(&d->state.ram->cmd_ring); RING_INIT(&d->state.ram->cursor_ring); @@ -555,54 +535,25 @@ static void qxl_detach(PCIQXLDevice *d) ring = &d->state.vga_ring; while (!RING_IS_EMPTY(ring)) { - QXLDrawable *drawable; QXLCommand *cmd; int notify; - cmd = RING_CONS_ITEM(ring); + RING_CONS_ITEM_SAFE(ring, ring, ring + 1, cmd); RING_POP(ring, notify); - ASSERT(cmd->type == QXL_CMD_DRAW); - drawable = (QXLDrawable *)cmd->data; - free(drawable); - } -} - -#ifdef CONFIG_SPICE - -static void hold_mode_notifier(QXLModeNotifier* notifier) -{ - notifier->refs++; -} - -static void release_mode_notifier(QXLModeNotifier* notifier) -{ - if (--notifier->refs) { - return; - } - QXLModeNotifier **now = ¬ifier->d->mode_notifiers; - while (*now != notifier) { - now = &(*now)->next; + switch (cmd->type) { + case QXL_CMD_DRAW: { + QXLDrawable *drawable; + drawable = (QXLDrawable *)cmd->data; + free(drawable); + break; + } + default: + printf("%s: wrong type\n", __FUNCTION__); + abort(); + } } - *now = notifier->next; - free(notifier); -} -#endif - -static void qxl_notify_mode_change(PCIQXLDevice *d) -{ -#ifdef CONFIG_SPICE - QXLModeNotifier *now = d->mode_notifiers; - QXLModeNotifier *tmp; - - while (now) { - hold_mode_notifier(now); - now->proc(now->opaque); - tmp = now; - now = now->next; - release_mode_notifier(tmp); - } -#endif + RING_INIT(&d->state.ram->cursor_ring); } static void qxl_create_host_memslot(PCIQXLDevice *d) @@ -612,14 +563,15 @@ static void qxl_create_host_memslot(PCIQXLDevice *d) printf("%s\n", __FUNCTION__); - PANIC_ON(d->state.mem_slots[0].active); + PANIC_ON(d->state.mem_slots[0][0].active); - device_slot = &d->state.mem_slots[0]; + device_slot = &d->state.mem_slots[0][0]; device_slot->active = TRUE; device_slot->address_delta = 0; device_slot->virt_start = 0; device_slot->virt_end = ~(unsigned long)0; + qxl_dev_slot.slot_group_id = 0; qxl_dev_slot.slot_id = 0; qxl_dev_slot.addr_delta = device_slot->address_delta; qxl_dev_slot.virt_start = device_slot->virt_start; @@ -631,44 +583,30 @@ static void qxl_create_host_memslot(PCIQXLDevice *d) static void qxl_init_memslots(PCIQXLDevice *d) { + int x; int i; - for (i = 1; i < NUM_MEMSLOTS; ++i) { - d->state.mem_slots[i].generation = 1; + for (x = 0; x < NUM_MEMSLOTS_GROUPS; ++x) { + for (i = 1; i < NUM_MEMSLOTS; ++i) { + d->state.mem_slots[x][i].generation = 1; + } } } static void qxl_reset_memslots(PCIQXLDevice *d) { int i; + int x; - for (i = 0; i < NUM_MEMSLOTS; ++i) { - d->state.mem_slots[i].active = FALSE; + for (x = 0; x < NUM_MEMSLOTS_GROUPS; ++x) { + for (i = 0; i < NUM_MEMSLOTS; ++i) { + d->state.mem_slots[x][i].active = FALSE; + } } d->worker->reset_memslots(d->worker); } -static void qxl_set_mode(PCIQXLDevice *d, uint32_t mode) -{ - if (mode > sizeof(qxl_modes) / sizeof(QXLMode)) { - printf("%s: bad mode %u\n", __FUNCTION__, mode); - return; - } - printf("%s: %u\n",__FUNCTION__, mode); - qxl_detach(d); - ASSERT(RING_IS_EMPTY(&d->state.ram->cmd_ring)); - ASSERT(RING_IS_EMPTY(&d->state.ram->cursor_ring)); - ASSERT(RING_IS_EMPTY(&d->state.vga_ring)); - qxl_reset_state(d); - qxl_exit_vga_mode(d); - d->state.rom->mode = mode; - memset(d->state.vram, 0, d->state.vram_size); - d->state.mode = QXL_MODE_NATIVE; - qxl_notify_mode_change(d); - d->worker->attach(d->worker); -} - static void qxl_add_vga_client(void) { if (qxl_vga.active_clients++ == 0) { @@ -681,24 +619,93 @@ static void qxl_remove_vga_client(void) qxl_vga.active_clients--; } +static void qxl_create_primary_surface(PCIQXLDevice *d) +{ + QXLDevSurfaceCreate surface; + + printf("%s\n", __FUNCTION__); + + surface.depth = 32; + surface.width = qxl_vga.ds->width; + surface.height = qxl_vga.ds->height; + surface.stride = -qxl_vga.ds->width * 4; + surface.mouse_mode = 0; + surface.flags = 0; + surface.type = 0; + surface.mem = (PHYSICAL)d->state.ram_start; + surface.group_id = 0; + + d->worker->create_primary_surface(d->worker, 0, &surface); +} + +static void qxl_destroy_primary_surface(PCIQXLDevice *d) +{ + printf("%s\n", __FUNCTION__); + + d->worker->destroy_primary_surface(d->worker, 0); +} + static void qxl_enter_vga_mode(PCIQXLDevice *d) { + qxl_create_primary_surface(d); + if (d->state.mode == QXL_MODE_VGA || (!QXL_SHARED_VGA_MODE && d->id)) { return; } printf("%u: %s\n", d->id, __FUNCTION__); - d->state.rom->mode = ~0; d->state.mode = QXL_MODE_VGA; memset(&d->dirty_rect, 0, sizeof(d->dirty_rect)); - qxl_notify_mode_change(d); qxl_add_vga_client(); } -/* reset the state (assuming the worker is detached) */ +static void qxl_destroy_primary(PCIQXLDevice *d) +{ + ASSERT(d->state.mode == QXL_MODE_NATIVE); + d->state.mode = QXL_MODE_UNDEFINED; + + printf("%s\n", __FUNCTION__); + + d->worker->destroy_primary_surface(d->worker, 0); +} + +static void qxl_create_primary(PCIQXLDevice *d) +{ + QXLDevSurfaceCreate surface; + + printf("%s\n", __FUNCTION__); + + ASSERT(d->state.mode != QXL_MODE_NATIVE); + qxl_exit_vga_mode(d); + d->state.mode = QXL_MODE_NATIVE; + + surface.depth = d->state.ram->create_surface.depth; + surface.height = d->state.ram->create_surface.height; + surface.mem = d->state.ram->create_surface.mem; + surface.mouse_mode = TRUE; + surface.position = d->state.ram->create_surface.position; + surface.stride = d->state.ram->create_surface.stride; + surface.width = d->state.ram->create_surface.width; + surface.type = d->state.ram->create_surface.type; + surface.flags = d->state.ram->create_surface.flags; + surface.group_id = 1; + + d->worker->create_primary_surface(d->worker, 0, &surface); +} + +static void qxl_check_state(PCIQXLDevice *d) +{ + QXLRam *ram = d->state.ram; + + ASSERT(RING_IS_EMPTY(&ram->cmd_ring)); + ASSERT(RING_IS_EMPTY(&ram->cursor_ring)); + ASSERT(RING_IS_EMPTY(&d->state.vga_ring)); +} + static void qxl_reset_state(PCIQXLDevice *d) { QXLRam *ram = d->state.ram; QXLRom *rom = d->state.rom; + UINT64 *item; ASSERT(RING_IS_EMPTY(&ram->cmd_ring)); ASSERT(RING_IS_EMPTY(&ram->cursor_ring)); @@ -711,33 +718,37 @@ static void qxl_reset_state(PCIQXLDevice *d) RING_INIT(&ram->cursor_ring); RING_INIT(&d->state.vga_ring); RING_INIT(&ram->release_ring); - *RING_PROD_ITEM(&ram->release_ring) = 0; + RING_PROD_ITEM_SAFE(&ram->release_ring, &ram->release_ring, &ram->release_ring + 1, item); + *item = 0; d->state.num_free_res = 0; d->state.last_release = NULL; + qemu_set_irq(d->pci_dev.irq[0], irq_level(d)); } -/* reset: detach, reset_state, re-attach */ static void qxl_reset(PCIQXLDevice *d) { printf("%s\n", __FUNCTION__); - qxl_detach(d); - qxl_reset_state(d); + qxl_check_state(d); if (QXL_SHARED_VGA_MODE || !d->id) { qxl_enter_vga_mode(d); - d->worker->attach(d->worker); } else { d->state.mode = QXL_MODE_UNDEFINED; - qxl_notify_mode_change(d); } - qemu_set_irq(d->pci_dev.irq[0], irq_level(d)); } static void qxl_hard_reset(PCIQXLDevice *d) { - qxl_reset(d); + printf("%s\n", __FUNCTION__); + + qxl_release_commands(d); + d->worker->destroy_surfaces(d->worker); + d->worker->reset_cursor(d->worker); + d->worker->reset_image_cache(d->worker); qxl_reset_memslots(d); qxl_create_host_memslot(d); + qxl_reset_state(d); + qxl_reset(d); } static inline void vdi_port_set_dirty(PCIVDIPortDevice *d, void *start, uint32_t length) @@ -830,7 +841,7 @@ static int vdi_port_interface_write(VDIPortInterface *port, VDObjectRef plug, break; } - packet = RING_PROD_ITEM(ring); + RING_PROD_ITEM_SAFE(ring, ring, ring + 1, packet); packet->gen = d->ram->generation; packet->size = MIN(len, sizeof(packet->data)); memcpy(packet->data, buf, packet->size); @@ -856,6 +867,7 @@ static int vdi_port_interface_read(VDIPortInterface *port, VDObjectRef plug, PCIVDIPortDevice *d = container_of(port, PCIVDIPortDevice, interface); VDIPortRing *ring = &d->ram->input; uint32_t gen = d->ram->generation; + VDIPortPacket *packet; int do_notify = FALSE; int actual_read = 0; @@ -863,14 +875,18 @@ static int vdi_port_interface_read(VDIPortInterface *port, VDObjectRef plug, return 0; } - while (!RING_IS_EMPTY(ring) && RING_CONS_ITEM(ring)->gen != gen) { + while (!RING_IS_EMPTY(ring)) { int notify; + RING_CONS_ITEM_SAFE(ring, ring, ring + 1, packet); + if (packet->gen == gen) { + break; + } + RING_POP(ring, notify); do_notify = do_notify || notify; } while (len) { - VDIPortPacket *packet; int wait; int now; @@ -880,7 +896,7 @@ static int vdi_port_interface_read(VDIPortInterface *port, VDObjectRef plug, break; } - packet = RING_CONS_ITEM(ring); + RING_CONS_ITEM_SAFE(ring, ring, ring + 1, packet); if (packet->size > sizeof(packet->data)) { vdi_port_set_dirty(d, ring, sizeof(*ring) - sizeof(ring->items)); printf("%s: bad packet size\n", __FUNCTION__); @@ -1015,13 +1031,16 @@ static void qxl_check_memslot_range(PCIQXLDevice *d, unsigned long virt_start, unsigned long virt_end) { int x; + int i; MemSlot *slot; - for (x = 1; x < NUM_MEMSLOTS; ++x) { - slot = &d->state.mem_slots[x]; + for (i = 0; i < NUM_MEMSLOTS_GROUPS; ++i) { + for (x = 1; x < NUM_MEMSLOTS; ++x) { + slot = &d->state.mem_slots[i][x]; - if (slot->active) { - PANIC_ON(is_intersecting_memslot(slot, virt_start, virt_end)); + if (slot->active) { + PANIC_ON(is_intersecting_memslot(slot, virt_start, virt_end)); + } } } } @@ -1048,8 +1067,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id) printf("%s: slot %d start: 0x%lx end: 0x%lx\n", __FUNCTION__, slot_id, start, end); PANIC_ON(slot_id >= NUM_MEMSLOTS); - PANIC_ON(d->state.mem_slots[slot_id].active); - PANIC_ON(slot_id == 0); + PANIC_ON(d->state.mem_slots[1][slot_id].active); for (i = 0; i < d->state.num_ranges; ++i) { if (address_in_range(start, end, &d->state.address_ranges[i])) { @@ -1072,7 +1090,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id) qxl_check_memslot_range(d, new_virt_start, new_virt_end); - device_slot = &d->state.mem_slots[slot_id]; + device_slot = &d->state.mem_slots[1][slot_id]; device_slot->active = TRUE; device_slot->address_delta = ram_start + start - ram_phys_addr; device_slot->virt_start = new_virt_start; @@ -1083,6 +1101,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id) qxl_dev_slot.virt_start = device_slot->virt_start; qxl_dev_slot.virt_end = device_slot->virt_end; qxl_dev_slot.generation = d->state.rom->slot_generation = device_slot->generation++; + qxl_dev_slot.slot_group_id = 1; d->worker->add_memslot(d->worker, &qxl_dev_slot); } @@ -1094,21 +1113,23 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) printf("%s: slot %d\n", __FUNCTION__, slot_id); PANIC_ON(slot_id >= NUM_MEMSLOTS); - PANIC_ON(slot_id == 0); - device_slot = &d->state.mem_slots[slot_id]; + device_slot = &d->state.mem_slots[1][slot_id]; PANIC_ON(!device_slot->active); device_slot->active = FALSE; - d->worker->del_memslot(d->worker, slot_id); + d->worker->del_memslot(d->worker, 1, slot_id); } static inline int is_any_none_host_slot_active(PCIQXLDevice *d) { int i; + int x; - for (i = 1; i < NUM_MEMSLOTS; ++i) { - if (d->state.mem_slots[i].active) { - return TRUE; + for (x = 1; x < NUM_MEMSLOTS_GROUPS; ++x) { + for (i = 0; i < NUM_MEMSLOTS; ++i) { + if (d->state.mem_slots[x][i].active) { + return TRUE; + } } } return FALSE; @@ -1122,9 +1143,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("%s: addr 0x%x val 0x%x\n", __FUNCTION__, addr, val); #endif if (d->state.mode != QXL_MODE_NATIVE && io_port != QXL_IO_RESET && - io_port != QXL_IO_SET_MODE && io_port != QXL_IO_MEMSLOT_ADD && - io_port != QXL_IO_MEMSLOT_DEL) { + io_port != QXL_IO_MEMSLOT_ADD && io_port != QXL_IO_MEMSLOT_DEL && + io_port != QXL_IO_CREATE_PRIMARY) { printf("%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port); + PANIC_ON(io_port == QXL_IO_DESTROY_PRIMARY); return; } switch (io_port) { @@ -1158,16 +1180,23 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("%u: QXL_IO_RESET\n", d->id); qxl_hard_reset(d); break; - case QXL_IO_SET_MODE: - printf("%u: QXL_IO_SET_MODE\n", d->id); - qxl_set_mode(d, val); - break; case QXL_IO_MEMSLOT_ADD: qxl_add_memslot(d, val); break; case QXL_IO_MEMSLOT_DEL: qxl_del_memslot(d, val); break; + case QXL_IO_CREATE_PRIMARY: + PANIC_ON(val != 0); + qxl_create_primary(d); + break; + case QXL_IO_DESTROY_PRIMARY: + PANIC_ON(val != 0); + qxl_destroy_primary(d); + break; + case QXL_IO_DESTROY_SURFACE_WAIT: + d->worker->destroy_surface_wait(d->worker, val); + break; default: printf("%s: unexpected addr 0x%x val 0x%x\n", __FUNCTION__, addr, val); } @@ -1303,9 +1332,8 @@ static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size, rom->magic = QXL_ROM_MAGIC; rom->id = d->id; - rom->mode = 0; rom->modes_offset = sizeof(QXLRom); - rom->draw_area_size = qxl_max_res_area()* sizeof(uint32_t); + rom->surface0_area_size = qxl_max_res_area()* sizeof(uint32_t); rom->compression_level = QXL_DEFAULT_COMPRESSION_LEVEL; rom->log_level = 0; @@ -1328,14 +1356,15 @@ static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size, static void init_qxl_ram(QXLState *s, uint8_t *buf, uint32_t actual_ram_size) { - uint32_t draw_area_size; + uint32_t surface0_area_size; uint32_t ram_header_size; + uint64_t *item; s->ram_start = buf; - draw_area_size = s->rom->draw_area_size; + surface0_area_size = ALIGN(s->rom->surface0_area_size, (1 << TARGET_PAGE_BITS)); ram_header_size = ALIGN(sizeof(*s->ram), 8); - ASSERT(ram_header_size + draw_area_size < actual_ram_size); + ASSERT(ram_header_size + surface0_area_size < actual_ram_size); s->rom->ram_header_offset = actual_ram_size - ram_header_size; s->ram = (QXLRam *)(buf + s->rom->ram_header_offset); @@ -1343,12 +1372,13 @@ static void init_qxl_ram(QXLState *s, uint8_t *buf, uint32_t actual_ram_size) RING_INIT(&s->ram->cmd_ring); RING_INIT(&s->ram->cursor_ring); RING_INIT(&s->ram->release_ring); - *RING_PROD_ITEM(&s->ram->release_ring) = 0; + RING_PROD_ITEM_SAFE(&s->ram->release_ring, &s->ram->release_ring, &s->ram->release_ring + 1, + item); + *item = 0; + s->rom->num_pages = (actual_ram_size - (surface0_area_size + ram_header_size)) >> + TARGET_PAGE_BITS; - s->rom->draw_area_offset = s->rom->ram_header_offset - draw_area_size; - s->rom->pages_offset = 0; - s->rom->num_io_pages = (actual_ram_size - (draw_area_size + ram_header_size)) >> TARGET_PAGE_BITS; - printf("%s: npages %u\n", __FUNCTION__, s->rom->num_io_pages); + printf("%s: npages %u\n", __FUNCTION__, s->rom->num_pages); } inline uint32_t msb_mask(uint32_t val) @@ -1443,7 +1473,7 @@ static void qxl_vga_update(void) drawable->clip.data = 0; drawable->effect = QXL_EFFECT_OPAQUE; drawable->release_info.id = (UINT64)drawable; - drawable->bitmap_offset = 0; + drawable->self_bitmap = 0; drawable->type = QXL_DRAW_COPY; drawable->u.copy.rop_decriptor = ROPD_OP_PUT; @@ -1465,7 +1495,7 @@ static void qxl_vga_update(void) image->bitmap.data = (PHYSICAL)(qxl_vga.ds->data + dirty_rect->top * qxl_vga.ds->linesize + dirty_rect->left * 4); image->bitmap.palette = 0; - cmd = RING_PROD_ITEM(ring); + RING_PROD_ITEM_SAFE(ring, ring, ring + 1, cmd); cmd->type = QXL_CMD_DRAW; cmd->data = (PHYSICAL)drawable; RING_PUSH(ring, notify); @@ -1495,7 +1525,8 @@ static void qxl_display_resize(struct DisplayState *ds, int w, int h) while (client) { if (client->state.mode == QXL_MODE_VGA) { printf("%s\n", __FUNCTION__); - qxl_reset(client); + qxl_destroy_primary_surface(client); + qxl_create_primary_surface(client); } client = client->vga_next; } @@ -1542,7 +1573,9 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) if (d->state.mode != QXL_MODE_VGA) { return; } + printf("%s\n", __FUNCTION__); + qxl_destroy_primary_surface(d); qxl_remove_vga_client(); d->state.mode = QXL_MODE_UNDEFINED; } @@ -1553,6 +1586,9 @@ int qxl_vga_touch(void) int ret = FALSE; while (d) { if (d->state.mode != QXL_MODE_VGA && (QXL_SHARED_VGA_MODE || !d->id)) { + if (d->state.mode == QXL_MODE_NATIVE) { + qxl_destroy_primary(d); + } qxl_reset(d); ret = TRUE; } @@ -1571,7 +1607,6 @@ static void qxl_save(QEMUFile* f, void* opaque) d->worker->save(d->worker); pci_device_save(&d->pci_dev, f); - qemu_put_be32(f, s->rom->mode); qemu_put_be32(f, s->num_free_res); if (s->last_release == NULL) @@ -1609,15 +1644,11 @@ static int qxl_load(QEMUFile* f,void* opaque,int version_id) return ret; } - if (d->state.mode != QXL_MODE_UNDEFINED) { - d->worker->detach(d->worker); - } if (s->mode == QXL_MODE_VGA) { qxl_remove_vga_client(); } - s->rom->mode = qemu_get_be32(f); s->num_free_res = qemu_get_be32(f); last_release_offset = qemu_get_be32(f); @@ -1653,11 +1684,6 @@ static int qxl_load(QEMUFile* f,void* opaque,int version_id) if (s->mode == QXL_MODE_VGA) { qxl_add_vga_client(); } - if (s->mode != QXL_MODE_UNDEFINED) { - d->worker->attach(d->worker); - d->worker->load(d->worker); - } - qxl_notify_mode_change(d); return 0; } @@ -1734,19 +1760,14 @@ void qxl_get_init_info(QXLDevRef dev_ref, QXLDevInitInfo *info) _qxl_get_init_info((PCIQXLDevice *)dev_ref, info); } -void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info) -{ - _qxl_get_info((PCIQXLDevice *)dev_ref, info); -} - -int qxl_get_command(QXLDevRef dev_ref, struct QXLCommand *cmd) +int qxl_get_command(QXLDevRef dev_ref, struct QXLCommandExt *cmd) { return _qxl_get_command((PCIQXLDevice *)dev_ref, cmd); } -void qxl_release_resource(QXLDevRef dev_ref, union QXLReleaseInfo *release_info) +void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfoExt release_info_ext) { - _qxl_release_resource((PCIQXLDevice *)dev_ref, release_info); + _qxl_release_resource((PCIQXLDevice *)dev_ref, &release_info_ext); } void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id) @@ -1759,7 +1780,7 @@ int qxl_req_cmd_notification(QXLDevRef dev_ref) return _qxl_req_cmd_notification((PCIQXLDevice *)dev_ref); } -int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommand *cmd) +int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommandExt *cmd) { return _qxl_get_cursor_command((PCIQXLDevice *)dev_ref, cmd); } @@ -1823,70 +1844,12 @@ static void interface_set_mm_time(QXLInterface *qxl, uint32_t mm_time) d->state.rom->mm_clock = mm_time; } -static QXLModeNotifier *register_mode_notifier(PCIQXLDevice *d, qxl_mode_change_notifier_t proc, - void *opaque) -{ - QXLModeNotifier *notifier; - - if (!proc) { - return NULL; - } - - if (!(notifier = (QXLModeNotifier *)malloc(sizeof(*notifier)))) { - printf("%s: malloc failed\n", __FUNCTION__); - exit(-1); - } - notifier->opaque = opaque; - notifier->proc = proc; - notifier->refs = 1; - notifier->next = d->mode_notifiers; - d->mode_notifiers = notifier; - return notifier; -} - -static void unregister_mode_notifier(PCIQXLDevice *d, QXLModeNotifier *notifier) -{ - QXLModeNotifier **now = &d->mode_notifiers; - for (;;) { - if (*now == notifier) { - notifier->proc = NULL; - release_mode_notifier(notifier); - return; - } - now = &(*now)->next; - } -} - -static VDObjectRef interface_register_mode_change(QXLInterface *qxl, qxl_mode_change_notifier_t notifier, void *opaque) -{ - PCIQXLDevice *d = ((Interface *)qxl)->d; - - if (!notifier) { - return 0; - } - return (VDObjectRef)register_mode_notifier(d, notifier, opaque); -} - -static void interface_unregister_mode_change(QXLInterface *qxl, VDObjectRef notifier) -{ - PCIQXLDevice *d = ((Interface *)qxl)->d; - if (!notifier) { - return; - } - unregister_mode_notifier(d, (QXLModeNotifier *)notifier); -} - static void interface_get_init_info(QXLInterface *qxl, QXLDevInitInfo *info) { _qxl_get_init_info(((Interface *)qxl)->d, info); } -static void interface_get_info(QXLInterface *qxl, QXLDevInfo *info) -{ - _qxl_get_info(((Interface *)qxl)->d, info); -} - -static int interface_get_command(QXLInterface *qxl, struct QXLCommand *cmd) +static int interface_get_command(QXLInterface *qxl, struct QXLCommandExt *cmd) { return _qxl_get_command(((Interface *)qxl)->d, cmd); } @@ -1901,12 +1864,12 @@ static int interface_has_command(QXLInterface *qxl) return _qxl_has_command(((Interface *)qxl)->d); } -static void interface_release_resource(QXLInterface *qxl, union QXLReleaseInfo *release_info) +static void interface_release_resource(QXLInterface *qxl, QXLReleaseInfoExt release_info_ext) { - _qxl_release_resource(((Interface *)qxl)->d, release_info); + _qxl_release_resource(((Interface *)qxl)->d, &release_info_ext); } -static int interface_get_cursor_command(QXLInterface *qxl, struct QXLCommand *cmd) +static int interface_get_cursor_command(QXLInterface *qxl, struct QXLCommandExt *cmd) { return _qxl_get_cursor_command(((Interface *)qxl)->d, cmd); } @@ -1963,11 +1926,8 @@ static void regitser_interface(PCIQXLDevice *d) interface->vd_interface.attache_worker = interface_attache_worker; interface->vd_interface.set_compression_level = interface_set_compression_level; interface->vd_interface.set_mm_time = interface_set_mm_time; - interface->vd_interface.register_mode_change = interface_register_mode_change; - interface->vd_interface.unregister_mode_change = interface_unregister_mode_change; interface->vd_interface.get_init_info = interface_get_init_info; - interface->vd_interface.get_info = interface_get_info; interface->vd_interface.get_command = interface_get_command; interface->vd_interface.req_cmd_notification = interface_req_cmd_notification; interface->vd_interface.has_command = interface_has_command; @@ -2252,6 +2212,14 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, } d->state.num_ranges = num_ranges + 1; + d->state.group_ids_flip[0] = 0; + d->state.group_ids_flip[1] = 1; + d->state.send_event_flip[0] = FALSE; + d->state.send_event_flip[1] = TRUE; + d->state.rings_flip[0] = &d->state.vga_ring; + d->state.rings_flip[1] = &d->state.ram->cmd_ring; + d->state.flip_counter = 0; + printf("%s: rom(%p, 0x%lx, 0x%x) ram(%p, 0x%lx, 0x%x) vram(%p, 0x%lx, 0x%x)\n", __FUNCTION__, d->state.rom, @@ -2293,6 +2261,7 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, qxl_reset_state(d); qxl_init_memslots(d); init_pipe_signaling(d); + #ifdef CONFIG_SPICE regitser_interface(d); @@ -2303,7 +2272,6 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, qxl_create_host_memslot(d); if (QXL_SHARED_VGA_MODE || !d->id) { qxl_enter_vga_mode(d); - d->worker->attach(d->worker); } qemu_register_reset(reset_handler, d); device_id++; diff --git a/qemu/hw/qxl_dev.h b/qemu/hw/qxl_dev.h index d49978fe..cba9e3e9 100644 --- a/qemu/hw/qxl_dev.h +++ b/qemu/hw/qxl_dev.h @@ -21,7 +21,7 @@ #define REDHAT_PCI_VENDOR_ID 0x1b36 #define QXL_DEVICE_ID 0x0100 /* 0x100-0x11f reserved for spice */ -#define QXL_REVISION 0x02 +#define QXL_REVISION 0x03 #define QXL_ROM_MAGIC (*(UINT32*)"QXRO") #define QXL_RAM_MAGIC (*(UINT32*)"QXRA") @@ -42,10 +42,14 @@ enum { QXL_IO_UPDATE_IRQ, QXL_IO_NOTIFY_OOM, QXL_IO_RESET, - QXL_IO_SET_MODE, QXL_IO_LOG, QXL_IO_MEMSLOT_ADD, QXL_IO_MEMSLOT_DEL, + QXL_IO_DETACH_PRIMARY, + QXL_IO_ATTACH_PRIMARY, + QXL_IO_CREATE_PRIMARY, + QXL_IO_DESTROY_PRIMARY, + QXL_IO_DESTROY_SURFACE_WAIT, QXL_IO_RANGE_SIZE }; @@ -56,12 +60,9 @@ typedef struct ATTR_PACKED QXLRom { UINT32 update_id; UINT32 compression_level; UINT32 log_level; - UINT32 mode; UINT32 modes_offset; - UINT32 num_io_pages; - UINT32 pages_offset; - UINT32 draw_area_offset; - UINT32 draw_area_size; + UINT32 num_pages; + UINT32 surface0_area_size; UINT32 ram_header_offset; UINT32 mm_clock; UINT64 flags; @@ -105,11 +106,30 @@ typedef struct ATTR_PACKED QXLCommand { UINT32 ped; } QXLCommand; +typedef struct ATTR_PACKED QXLCommandExt { + QXLCommand cmd; + uint32_t group_id; +} QXLCommandExt; + typedef struct ATTR_PACKED QXLMemSlot { UINT64 mem_start; UINT64 mem_end; } QXLMemSlot; +#define QXL_SURF_TYPE_PRIMARY 0 + +typedef struct ATTR_PACKED QXLSurfaceCreate { + UINT32 width; + UINT32 height; + INT32 stride; + UINT32 depth; + UINT32 position; + UINT32 mouse_mode; + UINT32 flags; + UINT32 type; + PHYSICAL mem; +} QXLSurfaceCreate; + RING_DECLARE(QXLCommandRing, QXLCommand, 32); RING_DECLARE(QXLCursorRing, QXLCommand, 32); @@ -130,6 +150,7 @@ typedef struct ATTR_PACKED QXLRam { QXLReleaseRing release_ring; Rect update_area; QXLMemSlot mem_slot; + QXLSurfaceCreate create_surface; UINT64 flags; } QXLRam; @@ -138,6 +159,11 @@ typedef union QXLReleaseInfo{ UINT64 next; // out } QXLReleaseInfo; +typedef struct QXLReleaseInfoExt { + QXLReleaseInfo *info; + UINT32 group_id; +} QXLReleaseInfoExt; + typedef struct ATTR_PACKED QXLDataChunk { UINT32 data_size; PHYSICAL prev_chunk; @@ -230,8 +256,8 @@ typedef struct ATTR_PACKED QXLDrawable { QXLReleaseInfo release_info; UINT8 effect; UINT8 type; - UINT16 bitmap_offset; - Rect bitmap_area; + UINT8 self_bitmap; + Rect self_bitmap_area; Rect bbox; Clip clip; UINT32 mm_time; @@ -307,7 +333,6 @@ typedef struct ATTR_PACKED QXLImage { }; } QXLImage; - #define VDI_PORT_DEVICE_ID 0x0105 #define VDI_PORT_REVISION 0x01 diff --git a/qemu/hw/qxl_interface.h b/qemu/hw/qxl_interface.h index 6de2d7d4..8d372191 100644 --- a/qemu/hw/qxl_interface.h +++ b/qemu/hw/qxl_interface.h @@ -33,12 +33,16 @@ typedef struct QXLDevInfo { } QXLDevInfo; typedef struct QXLDevInitInfo { + uint32_t num_memslots_groups; uint32_t num_memslots; uint8_t memslot_gen_bits; uint8_t memslot_id_bits; + uint32_t qxl_ram_size; + uint8_t internal_groupslot_id; } QXLDevInitInfo; typedef struct QXLDevMemSlot { + uint32_t slot_group_id; uint32_t slot_id; uint32_t generation; unsigned long virt_start; @@ -46,10 +50,21 @@ typedef struct QXLDevMemSlot { uint64_t addr_delta; } QXLDevMemSlot; +typedef struct QXLDevSurfaceCreate { + uint32_t width; + uint32_t height; + int32_t stride; + uint32_t depth; + uint32_t position; + uint32_t mouse_mode; + uint32_t flags; + uint32_t type; + uint64_t mem; + uint32_t group_id; +} QXLDevSurfaceCreate; + typedef struct QXLWorker QXLWorker; struct QXLWorker { - void (*attach)(QXLWorker *worker); - void (*detach)(QXLWorker *worker); void (*wakeup)(QXLWorker *worker); void (*oom)(QXLWorker *worker); void (*save)(QXLWorker *worker); @@ -58,20 +73,26 @@ struct QXLWorker { void (*stop)(QXLWorker *worker); void (*update_area)(QXLWorker *worker); void (*add_memslot)(QXLWorker *worker, QXLDevMemSlot *slot); - void (*del_memslot)(QXLWorker *worker, uint32_t slot_id); + void (*del_memslot)(QXLWorker *worker, uint32_t slot_group_id, uint32_t slot_id); void (*reset_memslots)(QXLWorker *worker); + void (*destroy_surfaces)(QXLWorker *worker); + void (*destroy_primary_surface)(QXLWorker *worker, uint32_t surface_id); + void (*create_primary_surface)(QXLWorker *worker, uint32_t surface_id, + QXLDevSurfaceCreate *surface); + void (*reset_image_cache)(QXLWorker *worker); + void (*reset_cursor)(QXLWorker *worker); + void (*destroy_surface_wait)(QXLWorker *worker, uint32_t surface_id); }; #endif typedef unsigned long QXLDevRef; void qxl_get_init_info(QXLDevRef dev_ref, QXLDevInitInfo *info); -void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info); -int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd); -void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info); +int qxl_get_command(QXLDevRef dev_ref, QXLCommandExt *cmd); +void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfoExt release_info); void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id); int qxl_req_cmd_notification(QXLDevRef dev_ref); -int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd); +int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommandExt *cmd); int qxl_req_cursor_notification(QXLDevRef dev_ref); int qxl_has_command(QXLDevRef dev_ref); const Rect *qxl_get_update_area(QXLDevRef dev_ref); diff --git a/qemu/hw/qxl_native_worker.c b/qemu/hw/qxl_native_worker.c index 044ac3d7..35664cf9 100644 --- a/qemu/hw/qxl_native_worker.c +++ b/qemu/hw/qxl_native_worker.c @@ -20,6 +20,11 @@ exit(-1); \ } +#define PANIC_ON(x) if ((x)) { \ + printf("%s: PANIC_ON %s failed\n", __FUNCTION__, #x); \ + exit(-1); \ +} + typedef struct MemSlot { int active; int generation; @@ -32,11 +37,11 @@ typedef struct QxlDispatcher { QXLWorker base; int id; QXLDevRef dev_ref; + uint32_t nmem_slots_groups; uint32_t nmem_slots; - MemSlot *mem_slots; + MemSlot **mem_slots; uint8_t generation_bits; uint8_t mem_slot_bits; - QXLDevInfo dev_info; } QxlDispatcher; static inline int get_memslot_id(QXLWorker *worker, unsigned long addr) @@ -61,18 +66,20 @@ static inline unsigned long __get_clean_virt(QXLWorker *worker, unsigned long ad return addr & (((unsigned long)(-1)) >> (dispatcher->mem_slot_bits + dispatcher->generation_bits)); } -static inline void validate_virt(QXLWorker *worker, unsigned long virt, int slot_id, uint32_t add_size) +static inline void validate_virt(QXLWorker *worker, unsigned long virt, int group_slot_id, + int slot_id, uint32_t add_size) { MemSlot *slot; QxlDispatcher *dispatcher = (QxlDispatcher *)worker; - slot = &dispatcher->mem_slots[slot_id]; + slot = &dispatcher->mem_slots[group_slot_id][slot_id]; if (virt < slot->virt_start_addr || (virt + add_size) > slot->virt_end_addr) { qxl_error("virtual address out of range 0x%lx 0x%lx", virt, slot->address_delta); } } -static inline unsigned long get_virt(QXLWorker *worker, unsigned long addr, uint32_t add_size) +static inline unsigned long get_virt(QXLWorker *worker, int group_slot_id, + unsigned long addr, uint32_t add_size) { uint32_t slot_id; int generation; @@ -80,12 +87,16 @@ static inline unsigned long get_virt(QXLWorker *worker, unsigned long addr, uint MemSlot *slot; QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + if (group_slot_id > dispatcher->nmem_slots_groups) { + qxl_error("group_slot_id too big"); + } + slot_id = get_memslot_id(worker, addr); if (slot_id > dispatcher->nmem_slots) { qxl_error("slot_id too big"); } - slot = &dispatcher->mem_slots[slot_id]; + slot = &dispatcher->mem_slots[group_slot_id][slot_id]; if (!slot->active) { qxl_error("mem_slot is not avaible %d 0x%lx", slot_id, addr); } @@ -98,7 +109,7 @@ static inline unsigned long get_virt(QXLWorker *worker, unsigned long addr, uint h_virt = __get_clean_virt(worker, addr); h_virt += slot->address_delta; - validate_virt(worker, h_virt, slot_id, add_size); + validate_virt(worker, h_virt, group_slot_id, slot_id, add_size); return h_virt; } @@ -106,28 +117,41 @@ static inline unsigned long get_virt(QXLWorker *worker, unsigned long addr, uint static void native_qxl_worker_wakeup(QXLWorker *worker) { QxlDispatcher *dispatcher = (QxlDispatcher *)worker; - QXLCommand cmd; + QXLCommandExt cmd_ext; + QXLReleaseInfoExt release_info_ext; qxl_printf(""); for (;;) { - if (qxl_get_command(dispatcher->dev_ref, &cmd)) { - switch (cmd.type) { + if (qxl_get_command(dispatcher->dev_ref, &cmd_ext)) { + switch (cmd_ext.cmd.type) { case QXL_CMD_DRAW: { - QXLDrawable *draw_cmd = (QXLDrawable *)get_virt(worker, cmd.data, sizeof(QXLDrawable)); - qxl_release_resource(dispatcher->dev_ref, &draw_cmd->release_info); + QXLDrawable *draw_cmd = (QXLDrawable *)get_virt(worker, cmd_ext.group_id, + cmd_ext.cmd.data, + sizeof(QXLDrawable)); + release_info_ext.info = &draw_cmd->release_info; + release_info_ext.group_id = cmd_ext.group_id; + qxl_release_resource(dispatcher->dev_ref, release_info_ext); break; } case QXL_CMD_UPDATE: { - QXLUpdateCmd *update_cmd = (QXLUpdateCmd *)get_virt(worker, cmd.data, sizeof(QXLUpdateCmd)); + QXLUpdateCmd *update_cmd = (QXLUpdateCmd *)get_virt(worker, cmd_ext.group_id, + cmd_ext.cmd.data, + sizeof(QXLUpdateCmd)); qxl_notify_update(dispatcher->dev_ref, update_cmd->update_id); - qxl_release_resource(dispatcher->dev_ref, &update_cmd->release_info); + release_info_ext.info = &update_cmd->release_info; + release_info_ext.group_id = cmd_ext.group_id; + qxl_release_resource(dispatcher->dev_ref, release_info_ext); break; } case QXL_CMD_MESSAGE: { - QXLMessage *message = (QXLMessage *)get_virt(worker, cmd.data, sizeof(QXLMessage)); + QXLMessage *message = (QXLMessage *)get_virt(worker, cmd_ext.group_id, + cmd_ext.cmd.data, + sizeof(QXLMessage)); qxl_printf("MESSAGE: %s", message->data); - qxl_release_resource(dispatcher->dev_ref, &message->release_info); + release_info_ext.info = &message->release_info; + release_info_ext.group_id = cmd_ext.group_id; + qxl_release_resource(dispatcher->dev_ref, release_info_ext); break; } default: @@ -140,11 +164,16 @@ static void native_qxl_worker_wakeup(QXLWorker *worker) } } for (;;) { - if (qxl_get_cursor_command(dispatcher->dev_ref, &cmd)) { - switch (cmd.type) { + if (qxl_get_cursor_command(dispatcher->dev_ref, &cmd_ext)) { + switch (cmd_ext.cmd.type) { case QXL_CMD_CURSOR: { - QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, cmd.data, sizeof(QXLCursorCmd)); - qxl_release_resource(dispatcher->dev_ref, &cursor_cmd->release_info); + QXLReleaseInfoExt release_info_ext; + QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, cmd_ext.group_id, + cmd_ext.cmd.data, + sizeof(QXLCursorCmd)); + release_info_ext.group_id = cmd_ext.group_id; + release_info_ext.info = &cursor_cmd->release_info; + qxl_release_resource(dispatcher->dev_ref, release_info_ext); break; } default: @@ -158,22 +187,37 @@ static void native_qxl_worker_wakeup(QXLWorker *worker) } } -static void native_qxl_worker_attach(QXLWorker *worker) +static void native_qxl_worerk_reset_memslots(QXLWorker *worker) { QxlDispatcher *dispatcher = (QxlDispatcher *)worker; - qxl_printf(""); + memset(dispatcher->mem_slots, 0, sizeof(MemSlot) * dispatcher->nmem_slots * + dispatcher->nmem_slots_groups); +} - qxl_get_info(dispatcher->dev_ref, &dispatcher->dev_info); +static void native_qxl_worker_destroy_surfaces(QXLWorker *worker) +{ +} - native_qxl_worker_wakeup(worker); +static void native_qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id, + QXLDevSurfaceCreate *surface) +{ } -static void native_qxl_worerk_reset_memslots(QXLWorker *worker) +static void native_qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id) { - QxlDispatcher *dispatcher = (QxlDispatcher *)worker; +} - memset(dispatcher->mem_slots, 0, sizeof(MemSlot) * dispatcher->nmem_slots); +static void native_qxl_worker_reset_cursor(QXLWorker *worker) +{ +} + +static void native_qxl_worker_reset_image_cache(QXLWorker *worker) +{ +} + +static void native_qxl_worker_destroy_surface_wait(QXLWorker *worker, uint32_t surface_id) +{ } static void native_qxl_worker_detach(QXLWorker *worker) @@ -196,25 +240,31 @@ static void native_qxl_worker_add_memslot(QXLWorker *worker, QXLDevMemSlot *dev_ qxl_printf(""); ASSERT(dispatcher->nmem_slots > dev_slot->slot_id); - ASSERT(!dispatcher->mem_slots[dev_slot->slot_id].active); - - dispatcher->mem_slots[dev_slot->slot_id].active = 1; - dispatcher->mem_slots[dev_slot->slot_id].address_delta = dev_slot->addr_delta; - dispatcher->mem_slots[dev_slot->slot_id].virt_start_addr = dev_slot->virt_start; - dispatcher->mem_slots[dev_slot->slot_id].virt_end_addr = dev_slot->virt_end; - dispatcher->mem_slots[dev_slot->slot_id].generation = dev_slot->generation; + ASSERT(!dispatcher->mem_slots[dev_slot->slot_group_id][dev_slot->slot_id].active); + + dispatcher->mem_slots[dev_slot->slot_group_id][dev_slot->slot_id].active = 1; + dispatcher->mem_slots[dev_slot->slot_group_id][dev_slot->slot_id].address_delta = + dev_slot->addr_delta; + dispatcher->mem_slots[dev_slot->slot_group_id][dev_slot->slot_id].virt_start_addr = + dev_slot->virt_start; + dispatcher->mem_slots[dev_slot->slot_group_id][dev_slot->slot_id].virt_end_addr = + dev_slot->virt_end; + dispatcher->mem_slots[dev_slot->slot_group_id][dev_slot->slot_id].generation = + dev_slot->generation; } -static void native_qxl_worker_del_memslot(QXLWorker *worker, uint32_t slot_id) -{ +static void native_qxl_worker_del_memslot(QXLWorker *worker, uint32_t slot_group_id, + uint32_t slot_id) { QxlDispatcher *dispatcher = (QxlDispatcher *)worker; qxl_printf(""); + ASSERT(dispatcher->nmem_slots > slot_id); - ASSERT(dispatcher->mem_slots[slot_id].active); + ASSERT(dispatcher->nmem_slots_groups > slot_group_id); + ASSERT(dispatcher->mem_slots[slot_group_id][slot_id].active); - dispatcher->mem_slots[slot_id].active = 0; + dispatcher->mem_slots[slot_group_id][slot_id].active = 0; } static void native_qxl_worker_oom(QXLWorker *worker) @@ -247,6 +297,7 @@ QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id) { QxlDispatcher *dispatcher; QXLDevInitInfo init; + uint32_t i; if (!(dispatcher = malloc(sizeof(QxlDispatcher)))) { qxl_error("malloc failed"); @@ -255,8 +306,6 @@ QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id) dispatcher->id = device_id; dispatcher->dev_ref = dev_ref; - dispatcher->base.attach = native_qxl_worker_attach; - dispatcher->base.detach = native_qxl_worker_detach; dispatcher->base.wakeup = native_qxl_worker_wakeup; dispatcher->base.oom = native_qxl_worker_oom; dispatcher->base.save = native_qxl_worker_save; @@ -267,12 +316,28 @@ QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id) dispatcher->base.add_memslot = native_qxl_worker_add_memslot; dispatcher->base.del_memslot = native_qxl_worker_del_memslot; dispatcher->base.reset_memslots = native_qxl_worerk_reset_memslots; + dispatcher->base.destroy_surfaces = native_qxl_worker_destroy_surfaces; + dispatcher->base.create_primary_surface = native_qxl_worker_create_primary; + dispatcher->base.destroy_primary_surface = native_qxl_worker_destroy_primary; + dispatcher->base.reset_image_cache = native_qxl_worker_reset_image_cache; + dispatcher->base.reset_cursor = native_qxl_worker_reset_cursor; + dispatcher->base.destroy_surface_wait = native_qxl_worker_destroy_surface_wait; qxl_get_init_info(dispatcher->dev_ref, &init); - dispatcher->mem_slots = (MemSlot *)malloc(sizeof(MemSlot) * init.num_memslots); - ASSERT(dispatcher->mem_slots); - memset(dispatcher->mem_slots, 0, sizeof(MemSlot) * init.num_memslots); + ASSERT(init.num_memslots > 0); + ASSERT(init.num_memslots_groups > 0); + dispatcher->mem_slots = (MemSlot **)malloc(sizeof(MemSlot *) * init.num_memslots_groups); + PANIC_ON(!dispatcher->mem_slots); + + for (i = 0; i < init.num_memslots_groups; ++i) { + dispatcher->mem_slots[i] = malloc(sizeof(MemSlot) * init.num_memslots); + PANIC_ON(!dispatcher->mem_slots[i]); + memset(dispatcher->mem_slots[i], 0, sizeof(MemSlot) * init.num_memslots); + } + + + dispatcher->nmem_slots_groups = init.num_memslots_groups; dispatcher->nmem_slots = init.num_memslots; dispatcher->mem_slot_bits = init.memslot_id_bits; dispatcher->generation_bits = init.memslot_gen_bits; diff --git a/qemu/hw/ring.h b/qemu/hw/ring.h index 9653f01b..43885dde 100644 --- a/qemu/hw/ring.h +++ b/qemu/hw/ring.h @@ -72,10 +72,19 @@ typedef struct ATTR_PACKED name { \ #define RING_PROD_ITEM(r) (&(r)->items[(r)->prod & RING_INDEX_MASK(r)].el) +#define RING_PROD_ITEM_SAFE(r, start, end, ret) { \ + UINT32 prod = (r)->prod & RING_INDEX_MASK(r); \ + typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ + if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + abort(); \ + } \ + ret = &m_item->el; \ +} + #define RING_PROD_WAIT(r, wait) \ if (((wait) = RING_IS_FULL(r))) { \ (r)->notify_on_cons = (r)->cons + 1; \ - mb(); \ + mb(); \ (wait) = RING_IS_FULL(r); \ } @@ -87,6 +96,15 @@ typedef struct ATTR_PACKED name { \ #define RING_CONS_ITEM(r) (&(r)->items[(r)->cons & RING_INDEX_MASK(r)].el) +#define RING_CONS_ITEM_SAFE(r, start, end, ret) { \ + UINT32 cons = (r)->cons & RING_INDEX_MASK(r); \ + typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ + if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + abort(); \ + } \ + ret = &m_item->el; \ +} + #define RING_CONS_WAIT(r, wait) \ if (((wait) = RING_IS_EMPTY(r))) { \ (r)->notify_on_prod = (r)->prod + 1; \ -- cgit v1.2.3