>From b09152c01dc7c43f77015b183add3e1db36ccb88 Mon Sep 17 00:00:00 2001
From: Izik Eidus <iei...@redhat.com>
Date: Sat, 26 Dec 2009 07:39:45 +0200
Subject: [PATCH] qemu: add surface0 support to the qxl device

need in order to sync the qxl device with the server latest changes

Signed-off-by: Izik Eidus <iei...@redhat.com>
---
 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 5c3d36f..e314272 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 60210ef..890d521 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 = &notifier->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 d49978f..cba9e3e 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 6de2d7d..8d37219 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 044ac3d..35664cf 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 9653f01..43885dd 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;    \
-- 
1.6.5.2


------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
Spice-space-devel mailing list
Spice-space-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spice-space-devel

Reply via email to