[Spice-commits] server/Makefile.am server/red_memslots.c server/red_memslots.h server/red_worker.c

Alexander Larsson alexl at kemper.freedesktop.org
Fri Apr 9 07:54:01 PDT 2010


 server/Makefile.am    |    2 
 server/red_memslots.c |  210 ++++++++++++++++++++++++++
 server/red_memslots.h |   79 +++++++++
 server/red_worker.c   |  403 ++++++++++++++------------------------------------
 4 files changed, 405 insertions(+), 289 deletions(-)

New commits:
commit 34fb3f680618b8735322462bd692fb2923ea3027
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Apr 9 16:35:14 2010 +0200

    Split out the memslot stuff from red_worker.c to its own files
    
    This is required so that we can have code in other files that does address
    validation.

diff --git a/server/Makefile.am b/server/Makefile.am
index 5c4524a..f121168 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -74,6 +74,8 @@ libspice_server_la_SOURCES =			\
 	red_common.h				\
 	red_dispatcher.c			\
 	red_dispatcher.h			\
+	red_memslots.c				\
+	red_memslots.h				\
 	reds.c					\
 	reds.h					\
 	stat.h					\
diff --git a/server/red_memslots.c b/server/red_memslots.c
new file mode 100644
index 0000000..7175930
--- /dev/null
+++ b/server/red_memslots.c
@@ -0,0 +1,210 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009,2010 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "red_common.h"
+#include "red_memslots.h"
+
+static unsigned long __get_clean_virt(RedMemSlotInfo *info, unsigned long addr)
+{
+    return addr & info->memslot_clean_virt_mask;
+}
+
+static void print_memslots(RedMemSlotInfo *info)
+{
+    int i;
+    int x;
+
+    for (i = 0; i < info->num_memslots_groups; ++i) {
+        for (x = 0; x < info->num_memslots; ++x) {
+            if (!info->mem_slots[i][x].virt_start_addr &&
+                !info->mem_slots[i][x].virt_end_addr) {
+                continue;
+            }
+            printf("id %d, group %d, virt start %lx, virt end %lx, generation %u, delta %lx\n",
+                   x, i, info->mem_slots[i][x].virt_start_addr,
+                   info->mem_slots[i][x].virt_end_addr, info->mem_slots[i][x].generation,
+                   info->mem_slots[i][x].address_delta);
+            }
+    }
+}
+
+unsigned long get_virt_delta(RedMemSlotInfo *info, unsigned long addr, int group_id)
+{
+    MemSlot *slot;
+    int slot_id;
+    int generation;
+
+    if (group_id > info->num_memslots_groups) {
+        PANIC("group_id %d too big", group_id);
+    }
+
+    slot_id = get_memslot_id(info, addr);
+    if (slot_id > info->num_memslots) {
+        PANIC("slod_id %d too big", slot_id);
+    }
+
+    slot = &info->mem_slots[group_id][slot_id];
+
+    generation = get_generation(info, addr);
+    if (generation != slot->generation) {
+        PANIC("address generation is not valid");
+    }
+
+    return (slot->address_delta - (addr - __get_clean_virt(info, addr)));
+}
+
+void validate_virt(RedMemSlotInfo *info, unsigned long virt, int slot_id,
+                   uint32_t add_size, uint32_t group_id)
+{
+    MemSlot *slot;
+
+    slot = &info->mem_slots[group_id][slot_id];
+    if ((virt + add_size) < virt) {
+        PANIC("virtual address overlap");
+    }
+
+    if (virt < slot->virt_start_addr || (virt + add_size) > slot->virt_end_addr) {
+        print_memslots(info);
+        PANIC("virtual address out of range 0x%lx 0x%lx %d %d 0x%lx 0x%lx 0x%lx", virt,
+              slot->address_delta, slot_id, group_id, slot->virt_start_addr, slot->virt_end_addr,
+              virt + add_size);
+    }
+}
+
+unsigned long get_virt(RedMemSlotInfo *info, unsigned long addr, uint32_t add_size,
+                       int group_id)
+{
+    int slot_id;
+    int generation;
+    unsigned long h_virt;
+
+    MemSlot *slot;
+
+    if (group_id > info->num_memslots_groups) {
+        PANIC("group_id too big");
+    }
+
+    slot_id = get_memslot_id(info, addr);
+    if (slot_id > info->num_memslots) {
+        PANIC("slot_id too big");
+    }
+
+    slot = &info->mem_slots[group_id][slot_id];
+
+    generation = get_generation(info, addr);
+    if (generation != slot->generation) {
+        print_memslots(info);
+        PANIC("address generation is not valid, group_id %d, slot_id %d, gen %d, slot_gen %d\n",
+              group_id, slot_id, generation, slot->generation);
+    }
+
+    h_virt = __get_clean_virt(info, addr);
+    h_virt += slot->address_delta;
+
+    validate_virt(info, h_virt, slot_id, add_size, group_id);
+
+    return h_virt;
+}
+
+void *cb_get_virt(void *opaque, unsigned long addr,
+                  uint32_t add_size, uint32_t group_id)
+{
+    return (void *)get_virt((RedMemSlotInfo *)opaque, addr, add_size, group_id);
+}
+
+void cb_validate_virt(void *opaque,
+                      unsigned long virt, unsigned long from_addr,
+                      uint32_t add_size, uint32_t group_id)
+{
+    int slot_id = get_memslot_id((RedMemSlotInfo *)opaque, from_addr);
+    validate_virt((RedMemSlotInfo *)opaque, virt, slot_id, add_size, group_id);
+}
+
+void *validate_chunk (RedMemSlotInfo *info, QXLPHYSICAL data, uint32_t group_id, uint32_t *data_size_out, QXLPHYSICAL *next_out)
+{
+    QXLDataChunk *chunk;
+    uint32_t data_size;
+
+    chunk = (QXLDataChunk *)get_virt(info, data, sizeof(QXLDataChunk), group_id);
+    data_size = chunk->data_size;
+    validate_virt(info, (unsigned long)chunk->data, get_memslot_id(info, data),
+                  data_size, group_id);
+    *next_out = chunk->next_chunk;
+
+    return chunk->data;
+}
+
+void red_memslot_info_init(RedMemSlotInfo *info,
+                           uint32_t num_groups, uint32_t num_slots,
+                           uint8_t generation_bits,
+                           uint8_t id_bits,
+                           uint8_t internal_groupslot_id)
+{
+    uint32_t i;
+
+    ASSERT(num_slots > 0);
+    ASSERT(num_groups > 0);
+
+    info->num_memslots_groups = num_groups;
+    info->num_memslots = num_slots;
+    info->generation_bits = generation_bits;
+    info->mem_slot_bits = id_bits;
+    info->internal_groupslot_id = internal_groupslot_id;
+
+    info->mem_slots = spice_new(MemSlot *, num_groups);
+
+    for (i = 0; i < num_groups; ++i) {
+        info->mem_slots[i] = spice_new0(MemSlot, num_slots);
+    }
+
+    info->memslot_id_shift = 64 - info->mem_slot_bits;
+    info->memslot_gen_shift = 64 - (info->mem_slot_bits + info->generation_bits);
+    info->memslot_gen_mask = ~((unsigned long)-1 << info->generation_bits);
+    info->memslot_clean_virt_mask = (((unsigned long)(-1)) >>
+                                       (info->mem_slot_bits + info->generation_bits));
+}
+
+void red_memslot_info_add_slot(RedMemSlotInfo *info, uint32_t slot_group_id, uint32_t slot_id,
+                               uint64_t addr_delta, unsigned long virt_start, unsigned long virt_end,
+                               uint32_t generation)
+{
+    ASSERT(info->num_memslots_groups > slot_group_id);
+    ASSERT(info->num_memslots > slot_id);
+
+    info->mem_slots[slot_group_id][slot_id].address_delta = addr_delta;
+    info->mem_slots[slot_group_id][slot_id].virt_start_addr = virt_start;
+    info->mem_slots[slot_group_id][slot_id].virt_end_addr = virt_end;
+    info->mem_slots[slot_group_id][slot_id].generation = generation;
+}
+
+void red_memslot_info_del_slot(RedMemSlotInfo *info, uint32_t slot_group_id, uint32_t slot_id)
+{
+    ASSERT(info->num_memslots_groups > slot_group_id);
+    ASSERT(info->num_memslots > slot_id);
+
+    info->mem_slots[slot_group_id][slot_id].virt_start_addr = 0;
+    info->mem_slots[slot_group_id][slot_id].virt_end_addr = 0;
+}
+
+void red_memslot_info_reset(RedMemSlotInfo *info)
+{
+        uint32_t i;
+        for (i = 0; i < info->num_memslots_groups; ++i) {
+            memset(info->mem_slots[i], 0, sizeof(MemSlot) * info->num_memslots);
+        }
+}
diff --git a/server/red_memslots.h b/server/red_memslots.h
new file mode 100644
index 0000000..229e5cc
--- /dev/null
+++ b/server/red_memslots.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009,2010 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_REDMEMSLOTS
+#define _H_REDMEMSLOTS
+
+#include "red_common.h"
+
+#include <spice/qxl_dev.h>
+
+typedef struct MemSlot {
+    int generation;
+    unsigned long virt_start_addr;
+    unsigned long virt_end_addr;
+    long address_delta;
+} MemSlot;
+
+typedef struct RedMemSlotInfo {
+    MemSlot **mem_slots;
+    uint32_t num_memslots_groups;
+    uint32_t num_memslots;
+    uint8_t mem_slot_bits;
+    uint8_t generation_bits;
+    uint8_t memslot_id_shift;
+    uint8_t memslot_gen_shift;
+    uint8_t internal_groupslot_id;
+    unsigned long memslot_gen_mask;
+    unsigned long memslot_clean_virt_mask;
+} RedMemSlotInfo;
+
+static inline int get_memslot_id(RedMemSlotInfo *info, unsigned long addr)
+{
+    return addr >> info->memslot_id_shift;
+}
+
+static inline int get_generation(RedMemSlotInfo *info, unsigned long addr)
+{
+    return (addr >> info->memslot_gen_shift) & info->memslot_gen_mask;
+}
+
+unsigned long get_virt_delta(RedMemSlotInfo *info, unsigned long addr, int group_id);
+void validate_virt(RedMemSlotInfo *info, unsigned long virt, int slot_id,
+                   uint32_t add_size, uint32_t group_id);
+unsigned long get_virt(RedMemSlotInfo *info, unsigned long addr, uint32_t add_size,
+                       int group_id);
+
+void *validate_chunk (RedMemSlotInfo *info, QXLPHYSICAL data, uint32_t group_id, uint32_t *data_size_out, QXLPHYSICAL *next_out);
+void *cb_get_virt(void *opaque, unsigned long addr,
+                  uint32_t add_size, uint32_t group_id);
+void cb_validate_virt(void *opaque,
+                      unsigned long virt, unsigned long from_addr,
+                      uint32_t add_size, uint32_t group_id);
+void red_memslot_info_init(RedMemSlotInfo *info,
+                           uint32_t num_groups, uint32_t num_slots,
+                           uint8_t generation_bits,
+                           uint8_t id_bits,
+                           uint8_t internal_groupslot_id);
+void red_memslot_info_add_slot(RedMemSlotInfo *info, uint32_t slot_group_id, uint32_t slot_id,
+                               uint64_t addr_delta, unsigned long virt_start, unsigned long virt_end,
+                               uint32_t generation);
+void red_memslot_info_del_slot(RedMemSlotInfo *info, uint32_t slot_group_id, uint32_t slot_id);
+void red_memslot_info_reset(RedMemSlotInfo *info);
+
+#endif
diff --git a/server/red_worker.c b/server/red_worker.c
index 6fdc4fe..4078145 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -47,6 +47,7 @@
 #include "reds.h"
 #include "ring.h"
 #include "mjpeg_encoder.h"
+#include "red_memslots.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -907,13 +908,6 @@ typedef struct ItemTrace {
 
 #endif
 
-typedef struct MemSlot {
-    int generation;
-    unsigned long virt_start_addr;
-    unsigned long virt_end_addr;
-    long address_delta;
-} MemSlot;
-
 #define NUM_DRAWABLES 1000
 #define NUM_CURSORS 100
 
@@ -960,16 +954,7 @@ typedef struct RedWorker {
     _CursorItem cursor_items[NUM_CURSORS];
     _CursorItem *free_cursor_items;
 
-    MemSlot **mem_slots;
-    uint32_t num_memslots_groups;
-    uint32_t num_memslots;
-    uint8_t mem_slot_bits;
-    uint8_t generation_bits;
-    uint8_t memslot_id_shift;
-    uint8_t memslot_gen_shift;
-    uint8_t internal_groupslot_id;
-    unsigned long memslot_gen_mask;
-    unsigned long memslot_clean_virt_mask;
+    RedMemSlotInfo mem_slots;
 
     uint32_t preload_group_id;
 
@@ -1115,135 +1100,10 @@ static inline void validate_surface(RedWorker *worker, uint32_t surface_id)
     PANIC_ON(!worker->surfaces[surface_id].context.canvas);
 }
 
-static inline int get_memslot_id(RedWorker *worker, unsigned long addr)
-{
-    return addr >> worker->memslot_id_shift;
-}
-
-static inline int get_generation(RedWorker *worker, unsigned long addr)
-{
-
-    return (addr >> worker->memslot_gen_shift) & worker->memslot_gen_mask;
-}
-
-static inline unsigned long __get_clean_virt(RedWorker *worker, unsigned long addr)
-{
-    return addr & worker->memslot_clean_virt_mask;
-}
-
-static inline void print_memslots(RedWorker *worker)
-{
-    int i;
-    int x;
-
-    for (i = 0; i < worker->num_memslots_groups; ++i) {
-        for (x = 0; x < worker->num_memslots; ++x) {
-            if (!worker->mem_slots[i][x].virt_start_addr &&
-                !worker->mem_slots[i][x].virt_end_addr) {
-                continue;
-            }
-            printf("id %d, group %d, virt start %lx, virt end %lx, generation %u, delta %lx\n",
-                   x, i, worker->mem_slots[i][x].virt_start_addr,
-                   worker->mem_slots[i][x].virt_end_addr, worker->mem_slots[i][x].generation,
-                   worker->mem_slots[i][x].address_delta);
-            }
-    }
-}
-
-static inline unsigned long get_virt_delta(RedWorker *worker, unsigned long addr, int group_id)
-{
-    MemSlot *slot;
-    int slot_id;
-    int generation;
-
-    if (group_id > worker->num_memslots_groups) {
-        PANIC("group_id %d too big", group_id);
-    }
-
-    slot_id = get_memslot_id(worker, addr);
-    if (slot_id > worker->num_memslots) {
-        PANIC("slod_id %d too big", slot_id);
-    }
-
-    slot = &worker->mem_slots[group_id][slot_id];
-
-    generation = get_generation(worker, addr);
-    if (generation != slot->generation) {
-        PANIC("address generation is not valid");
-    }
-
-    return (slot->address_delta - (addr - __get_clean_virt(worker, addr)));
-}
-
-static inline void validate_virt(RedWorker *worker, unsigned long virt, int slot_id,
-                                 uint32_t add_size, uint32_t group_id)
-{
-    MemSlot *slot;
-
-    slot = &worker->mem_slots[group_id][slot_id];
-    if ((virt + add_size) < virt) {
-        PANIC("virtual address overlap");
-    }
-
-    if (virt < slot->virt_start_addr || (virt + add_size) > slot->virt_end_addr) {
-        print_memslots(worker);
-        PANIC("virtual address out of range 0x%lx 0x%lx %d %d 0x%lx 0x%lx 0x%lx", virt,
-              slot->address_delta, slot_id, group_id, slot->virt_start_addr, slot->virt_end_addr,
-              virt + add_size);
-    }
-}
-
-static inline unsigned long get_virt(RedWorker *worker, unsigned long addr, uint32_t add_size,
-                                     int group_id)
-{
-    int slot_id;
-    int generation;
-    unsigned long h_virt;
-
-    MemSlot *slot;
-
-    if (group_id > worker->num_memslots_groups) {
-        PANIC("group_id too big");
-    }
-
-    slot_id = get_memslot_id(worker, addr);
-    if (slot_id > worker->num_memslots) {
-        PANIC("slot_id too big");
-    }
-
-    slot = &worker->mem_slots[group_id][slot_id];
-
-    generation = get_generation(worker, addr);
-    if (generation != slot->generation) {
-        print_memslots(worker);
-        PANIC("address generation is not valid, group_id %d, slot_id %d, gen %d, slot_gen %d\n",
-              group_id, slot_id, generation, slot->generation);
-    }
-
-    h_virt = __get_clean_virt(worker, addr);
-    h_virt += slot->address_delta;
-
-    validate_virt(worker, h_virt, slot_id, add_size, group_id);
-
-    return h_virt;
-}
-
-static void *cb_get_virt(void *opaque, unsigned long addr, uint32_t add_size, uint32_t group_id)
-{
-    return (void *)get_virt((RedWorker *)opaque, addr, add_size, group_id);
-}
-
-static void cb_validate_virt(void *opaque, unsigned long virt, unsigned long from_addr,
-                             uint32_t add_size, uint32_t group_id)
-{
-    int slot_id = get_memslot_id((RedWorker *)opaque, from_addr);
-    validate_virt((RedWorker *)opaque, virt, slot_id, add_size, group_id);
-}
-
 static void *op_get_virt_preload_group(SpiceVirtMapping *mapping, unsigned long addr, uint32_t add_size)
 {
     RedWorker *worker = SPICE_CONTAINEROF(mapping, RedWorker, preload_group_virt_mapping);
-    return (void *)get_virt(worker, addr, add_size,
+    return (void *)get_virt(&worker->mem_slots, addr, add_size,
                             worker->preload_group_id);
 }
 
@@ -1251,8 +1111,8 @@ static void op_validate_virt_preload_group(SpiceVirtMapping *mapping, unsigned l
                                            unsigned long from_addr, uint32_t add_size)
 {
     RedWorker *worker = SPICE_CONTAINEROF(mapping, RedWorker, preload_group_virt_mapping);
-    int slot_id = get_memslot_id(worker, from_addr);
-    validate_virt(worker, virt, slot_id, add_size,
+    int slot_id = get_memslot_id(&worker->mem_slots, from_addr);
+    validate_virt(&worker->mem_slots, virt, slot_id, add_size,
                   worker->preload_group_id);
 }
 
@@ -2363,8 +2223,8 @@ static int is_equal_path(RedWorker *worker, SPICE_ADDRESS p1, SPICE_ADDRESS p2,
 
     ASSERT(p1 && p2);
 
-    path1 = (QXLPath *)get_virt(worker, p1, sizeof(QXLPath), group_id1);
-    path2 = (QXLPath *)get_virt(worker, p2, sizeof(QXLPath), group_id2);
+    path1 = (QXLPath *)get_virt(&worker->mem_slots, p1, sizeof(QXLPath), group_id1);
+    path2 = (QXLPath *)get_virt(&worker->mem_slots, p2, sizeof(QXLPath), group_id2);
 
     if ((size = path1->data_size) != path2->data_size) {
         return FALSE;
@@ -2390,7 +2250,7 @@ static int is_equal_path(RedWorker *worker, SPICE_ADDRESS p1, SPICE_ADDRESS p2,
         }
         if ((size1 -= now) == 0) {
             ASSERT(chunk1->next_chunk)
-            chunk1 = (QXLDataChunk *)get_virt(worker, chunk1->next_chunk, sizeof(QXLDataChunk),
+            chunk1 = (QXLDataChunk *)get_virt(&worker->mem_slots, chunk1->next_chunk, sizeof(QXLDataChunk),
                                               group_id1);
             size1 = chunk1->data_size;
             data1 = chunk1->data;
@@ -2400,7 +2260,7 @@ static int is_equal_path(RedWorker *worker, SPICE_ADDRESS p1, SPICE_ADDRESS p2,
 
         if ((size2 -= now) == 0) {
             ASSERT(chunk2->next_chunk)
-            chunk2 = (QXLDataChunk *)get_virt(worker, chunk2->next_chunk, sizeof(QXLDataChunk),
+            chunk2 = (QXLDataChunk *)get_virt(&worker->mem_slots, chunk2->next_chunk, sizeof(QXLDataChunk),
                                               group_id2);
             size2 = chunk2->data_size;
             data2 = chunk2->data;
@@ -2854,7 +2714,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
 #endif
     stream->refs = 1;
     stream->bit_rate = get_bit_rate(stream_width, stream_height);
-    QXLImage *qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap,
+    QXLImage *qxl_image = (QXLImage *)get_virt(&worker->mem_slots, drawable->qxl_drawable->u.copy.src_bitmap,
                                                sizeof(QXLImage), drawable->group_id);
     stream->top_down = !!(qxl_image->bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
     drawable->stream = stream;
@@ -2941,7 +2801,7 @@ static inline int __red_is_next_stream_frame(RedWorker *worker,
     }
 
     if (stream) {
-        QXLImage *qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap,
+        QXLImage *qxl_image = (QXLImage *)get_virt(&worker->mem_slots, qxl_drawable->u.copy.src_bitmap,
                                                    sizeof(QXLImage), candidate->group_id);
         if (stream->top_down != !!(qxl_image->bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
             return FALSE;
@@ -2996,7 +2856,7 @@ static inline int red_is_next_stream_frame(RedWorker *worker, Drawable *candidat
         return FALSE;
     }
 
-    qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage),
+    qxl_image = (QXLImage *)get_virt(&worker->mem_slots, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage),
                                      candidate->group_id);
 
     if (qxl_image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
@@ -3074,7 +2934,7 @@ static inline void red_update_copy_graduality(RedWorker* worker, Drawable *drawa
         return; // already set
     }
 
-    qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap,
+    qxl_image = (QXLImage *)get_virt(&worker->mem_slots, drawable->qxl_drawable->u.copy.src_bitmap,
                                      sizeof(QXLImage), drawable->group_id);
 
     if (!BITMAP_FMT_IS_RGB[qxl_image->bitmap.format] || _stride_is_extra(&qxl_image->bitmap) ||
@@ -3513,15 +3373,11 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa
 static void add_clip_rects(RedWorker *worker, QRegion *rgn, QXLPHYSICAL data, uint32_t group_id)
 {
     while (data) {
-        QXLDataChunk *chunk;
         SpiceRect *now;
         SpiceRect *end;
         uint32_t data_size;
-        chunk = (QXLDataChunk *)get_virt(worker, data, sizeof(QXLDataChunk), group_id);
-        data_size = chunk->data_size;
-        validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, data), data_size,
-                      group_id);
-        now = (SpiceRect *)chunk->data;
+
+        now = (SpiceRect *)validate_chunk(&worker->mem_slots, data, group_id, &data_size, &data);
         end = now + data_size / sizeof(SpiceRect);
 
         for (; now < end; now++) {
@@ -3534,7 +3390,6 @@ static void add_clip_rects(RedWorker *worker, QRegion *rgn, QXLPHYSICAL data, ui
 #endif
             region_add(rgn, r);
         }
-        data = chunk->next_chunk;
     }
 }
 
@@ -3624,7 +3479,7 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable,
         return;
     }
 
-    qxl_image = (QXLImage *)get_virt(worker, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage),
+    qxl_image = (QXLImage *)get_virt(&worker->mem_slots, qxl_drawable->u.copy.src_bitmap, sizeof(QXLImage),
                                      drawable->group_id);
     if (qxl_image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
         return;
@@ -3964,7 +3819,7 @@ static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface
         int32_t stride = surface->u.surface_create.stride;
         QXLReleaseInfoExt release_info_ext;
         
-        data = (uint8_t *)get_virt(worker, saved_data, height * abs(stride), group_id);
+        data = (uint8_t *)get_virt(&worker->mem_slots, saved_data, height * abs(stride), group_id);
         if (stride < 0) {
             data -= (int32_t)(stride * (height - 1));
         }
@@ -3995,10 +3850,10 @@ static void localize_path(RedWorker *worker, QXLPHYSICAL *in_path, uint32_t grou
     uint8_t *data;
     uint32_t data_size;
     QXLDataChunk *chunk;
-    int memslot_id = get_memslot_id(worker, *in_path);
+    int memslot_id = get_memslot_id(&worker->mem_slots, *in_path);
 
     ASSERT(in_path && *in_path);
-    path = (QXLPath *)get_virt(worker, *in_path, sizeof(QXLPath), group_id);
+    path = (QXLPath *)get_virt(&worker->mem_slots, *in_path, sizeof(QXLPath), group_id);
     data = spice_malloc_n_m(1, path->data_size, sizeof(uint32_t));
     *in_path = (QXLPHYSICAL)data;
     *(uint32_t *)data = path->data_size;
@@ -4006,10 +3861,10 @@ static void localize_path(RedWorker *worker, QXLPHYSICAL *in_path, uint32_t grou
     chunk = &path->chunk;
     do {
         data_size = chunk->data_size;
-        validate_virt(worker, (unsigned long)chunk->data, memslot_id, data_size, group_id);
+        validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
         memcpy(data, chunk->data, data_size);
         data += data_size;
-        chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(worker, chunk->next_chunk,
+        chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk,
                                                              sizeof(QXLDataChunk), group_id) : NULL;
     } while (chunk);
 }
@@ -4023,12 +3878,12 @@ static void unlocalize_path(QXLPHYSICAL *path)
 
 static void localize_str(RedWorker *worker, QXLPHYSICAL *in_str, uint32_t group_id)
 {
-    QXLString *qxl_str = (QXLString *)get_virt(worker, *in_str, sizeof(QXLString), group_id);
+    QXLString *qxl_str = (QXLString *)get_virt(&worker->mem_slots, *in_str, sizeof(QXLString), group_id);
     QXLDataChunk *chunk;
     SpiceString *str;
     uint8_t *dest;
     uint32_t data_size;
-    int memslot_id = get_memslot_id(worker, *in_str);
+    int memslot_id = get_memslot_id(&worker->mem_slots, *in_str);
 
     ASSERT(in_str);
     str = spice_malloc_n_m(1, qxl_str->data_size, sizeof(uint32_t));
@@ -4041,15 +3896,15 @@ static void localize_str(RedWorker *worker, QXLPHYSICAL *in_str, uint32_t group_
         QXLPHYSICAL next_chunk;
 
         data_size = chunk->data_size;
-        validate_virt(worker, (unsigned long)chunk->data, memslot_id, data_size, group_id);
+        validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
         memcpy(dest, chunk->data, data_size);
         if (!chunk->next_chunk) {
             return;
         }
         dest += data_size;
         next_chunk = chunk->next_chunk;
-        memslot_id = get_memslot_id(worker, next_chunk);
-        chunk = (QXLDataChunk *)get_virt(worker, next_chunk, sizeof(QXLDataChunk), group_id);
+        memslot_id = get_memslot_id(&worker->mem_slots, next_chunk);
+        chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, next_chunk, sizeof(QXLDataChunk), group_id);
     }
 }
 
@@ -4068,10 +3923,10 @@ static void localize_clip(RedWorker *worker, SpiceClip *clip, uint32_t group_id)
     case SPICE_CLIP_TYPE_RECTS: {
         QXLClipRects *clip_rects;
         QXLDataChunk *chunk;
-        int memslot_id = get_memslot_id(worker, clip->data);
+        int memslot_id = get_memslot_id(&worker->mem_slots, clip->data);
         uint8_t *data;
         uint32_t data_size;
-        clip_rects = (QXLClipRects *)get_virt(worker, clip->data, sizeof(QXLClipRects), group_id);
+        clip_rects = (QXLClipRects *)get_virt(&worker->mem_slots, clip->data, sizeof(QXLClipRects), group_id);
         chunk = &clip_rects->chunk;
         ASSERT(clip->data);
         data = spice_malloc_n_m(clip_rects->num_rects, sizeof(SpiceRect), sizeof(uint32_t));
@@ -4080,10 +3935,10 @@ static void localize_clip(RedWorker *worker, SpiceClip *clip, uint32_t group_id)
         data += sizeof(uint32_t);
         do {
             data_size = chunk->data_size;
-            validate_virt(worker, (unsigned long)chunk->data, memslot_id, data_size, group_id);
+            validate_virt(&worker->mem_slots, (unsigned long)chunk->data, memslot_id, data_size, group_id);
             memcpy(data, chunk->data, data_size);
             data += data_size;
-            chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(worker, chunk->next_chunk,
+            chunk = chunk->next_chunk ? (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk,
                                                                  sizeof(QXLDataChunk), group_id) :
                                          NULL;
         } while (chunk);
@@ -4280,7 +4135,7 @@ static void localize_bitmap(RedWorker *worker, QXLPHYSICAL *in_bitmap, uint32_t
     QXLImage *local_image;
 
     ASSERT(in_bitmap && *in_bitmap);
-    image = (QXLImage *)get_virt(worker, *in_bitmap, sizeof(QXLImage), group_id);
+    image = (QXLImage *)get_virt(&worker->mem_slots, *in_bitmap, sizeof(QXLImage), group_id);
     local_image = (QXLImage *)alloc_local_image(worker);
     *local_image = *image;
     *in_bitmap = (QXLPHYSICAL)local_image;
@@ -4307,7 +4162,7 @@ static void localize_bitmap(RedWorker *worker, QXLPHYSICAL *in_bitmap, uint32_t
     }
     case SPICE_IMAGE_TYPE_BITMAP:
         if (image->bitmap.flags & QXL_BITMAP_DIRECT) {
-            local_image->bitmap.data = (QXLPHYSICAL)get_virt(worker, image->bitmap.data,
+            local_image->bitmap.data = (QXLPHYSICAL)get_virt(&worker->mem_slots, image->bitmap.data,
                                                           image->bitmap.stride * image->bitmap.y,
                                                           group_id);
         } else {
@@ -4323,9 +4178,9 @@ static void localize_bitmap(RedWorker *worker, QXLPHYSICAL *in_bitmap, uint32_t
                 int cp_size;
 
                 ASSERT(src_data);
-                chunk = (QXLDataChunk *)get_virt(worker, src_data, sizeof(QXLDataChunk), group_id);
+                chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, src_data, sizeof(QXLDataChunk), group_id);
                 data_size = chunk->data_size;
-                validate_virt(worker, (unsigned long)chunk->data, get_memslot_id(worker, src_data),
+                validate_virt(&worker->mem_slots, (unsigned long)chunk->data, get_memslot_id(&worker->mem_slots, src_data),
                               data_size, group_id);
                 cp_size = MIN(data_size, size);
                 memcpy(data, chunk->data, cp_size);
@@ -4341,14 +4196,14 @@ static void localize_bitmap(RedWorker *worker, QXLPHYSICAL *in_bitmap, uint32_t
             SpicePalette *tmp_palette;
             SpicePalette *shadow_palette;
 
-            int slot_id = get_memslot_id(worker, local_image->bitmap.palette);
-            tmp_palette = (SpicePalette *)get_virt(worker, local_image->bitmap.palette,
+            int slot_id = get_memslot_id(&worker->mem_slots, local_image->bitmap.palette);
+            tmp_palette = (SpicePalette *)get_virt(&worker->mem_slots, local_image->bitmap.palette,
                                               sizeof(SpicePalette), group_id);
 
             num_ents = tmp_palette->num_ents;
             ents = tmp_palette->ents;
 
-            validate_virt(worker, (unsigned long)ents, slot_id, (num_ents * sizeof(uint32_t)),
+            validate_virt(&worker->mem_slots, (unsigned long)ents, slot_id, (num_ents * sizeof(uint32_t)),
                           group_id);
 
             shadow_palette = (SpicePalette *)spice_malloc_n_m(num_ents, sizeof(uint32_t),sizeof(SpicePalette) + sizeof(QXLPHYSICAL));
@@ -4430,7 +4285,7 @@ static void localize_attr(RedWorker *worker, SpiceLineAttr *attr, uint32_t group
         uint8_t *data;
 
         ASSERT(attr->style);
-        buf = (uint8_t *)get_virt(worker, attr->style, attr->style_nseg * sizeof(uint32_t),
+        buf = (uint8_t *)get_virt(&worker->mem_slots, attr->style, attr->style_nseg * sizeof(uint32_t),
                                   group_id);
         data = spice_malloc_n(attr->style_nseg, sizeof(uint32_t));
         memcpy(data, buf, attr->style_nseg * sizeof(uint32_t));
@@ -4910,7 +4765,7 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size)
         worker->repoll_cursor_ring = 0;
         switch (ext_cmd.cmd.type) {
         case QXL_CMD_CURSOR: {
-            QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, ext_cmd.cmd.data,
+            QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(&worker->mem_slots, ext_cmd.cmd.data,
                                                                 sizeof(QXLCursorCmd),
                                                                 ext_cmd.group_id);
             qxl_process_cursor(worker, cursor_cmd, ext_cmd.group_id);
@@ -4948,7 +4803,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
         worker->repoll_cmd_ring = 0;
         switch (ext_cmd.cmd.type) {
         case QXL_CMD_DRAW: {
-            QXLDrawable *drawable = (QXLDrawable *)get_virt(worker, ext_cmd.cmd.data,
+            QXLDrawable *drawable = (QXLDrawable *)get_virt(&worker->mem_slots, ext_cmd.cmd.data,
                                                             sizeof(QXLDrawable), ext_cmd.group_id);
             red_process_drawable(worker, drawable, ext_cmd.group_id);
             break;
@@ -4956,7 +4811,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
         case QXL_CMD_UPDATE: {
             int surface_id;
             QXLReleaseInfoExt release_info_ext;
-            QXLUpdateCmd *draw_cmd = (QXLUpdateCmd *)get_virt(worker, ext_cmd.cmd.data,
+            QXLUpdateCmd *draw_cmd = (QXLUpdateCmd *)get_virt(&worker->mem_slots, ext_cmd.cmd.data,
                                                               sizeof(QXLUpdateCmd),
                                                               ext_cmd.group_id);
             surface_id = draw_cmd->surface_id;
@@ -4970,7 +4825,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
         }
         case QXL_CMD_MESSAGE: {
             QXLReleaseInfoExt release_info_ext;
-            QXLMessage *message = (QXLMessage *)get_virt(worker, ext_cmd.cmd.data,
+            QXLMessage *message = (QXLMessage *)get_virt(&worker->mem_slots, ext_cmd.cmd.data,
                                                          sizeof(QXLMessage), ext_cmd.group_id);
             red_printf("MESSAGE: %s", message->data);
             release_info_ext.group_id = ext_cmd.group_id;
@@ -4979,7 +4834,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
             break;
         }
         case QXL_CMD_SURFACE: {
-            QXLSurfaceCmd *surface = (QXLSurfaceCmd *)get_virt(worker, ext_cmd.cmd.data,
+            QXLSurfaceCmd *surface = (QXLSurfaceCmd *)get_virt(&worker->mem_slots, ext_cmd.cmd.data,
                                                                sizeof(QXLSurfaceCmd), ext_cmd.group_id);
             red_process_surface(worker, surface, ext_cmd.group_id);
             break;
@@ -5088,8 +4943,8 @@ static void fill_path(DisplayChannel *display_channel, QXLPHYSICAL *in_path, uin
     int memslot_id;
     worker = channel->worker;
     ASSERT(in_path && *in_path);
-    memslot_id  = get_memslot_id(worker, *in_path);
-    QXLPath *path = (QXLPath *)get_virt(worker, *in_path, sizeof(QXLPath), group_id);
+    memslot_id  = get_memslot_id(&worker->mem_slots, *in_path);
+    QXLPath *path = (QXLPath *)get_virt(&worker->mem_slots, *in_path, sizeof(QXLPath), group_id);
     *in_path = channel->send_data.header.size;
     add_buf(channel, BUF_TYPE_RAW, &path->data_size, sizeof(uint32_t), 0, 0);
     add_buf(channel, BUF_TYPE_CHUNK, &path->chunk, path->data_size, memslot_id, group_id);
@@ -5102,8 +4957,8 @@ static void fill_str(DisplayChannel *display_channel, QXLPHYSICAL *in_str, uint3
     int memslot_id;
     worker = channel->worker;
     ASSERT(in_str && *in_str);
-    memslot_id  = get_memslot_id(worker, *in_str);
-    QXLString *str = (QXLString *)get_virt(worker, *in_str, sizeof(QXLString), group_id);
+    memslot_id  = get_memslot_id(&worker->mem_slots, *in_str);
+    QXLString *str = (QXLString *)get_virt(&worker->mem_slots, *in_str, sizeof(QXLString), group_id);
     *in_str = channel->send_data.header.size;
     add_buf(channel, BUF_TYPE_RAW, &str->length, sizeof(uint32_t), 0, 0);
     add_buf(channel, BUF_TYPE_CHUNK, &str->chunk, str->data_size, memslot_id, group_id);
@@ -5113,10 +4968,10 @@ static inline void fill_rects_clip(RedChannel *channel, QXLPHYSICAL *in_clip, ui
 {
     RedWorker *worker = channel->worker;
     QXLClipRects *clip;
-    int memslot_id = get_memslot_id(worker, *in_clip);
+    int memslot_id = get_memslot_id(&worker->mem_slots, *in_clip);
 
     ASSERT(in_clip && *in_clip);
-    clip = (QXLClipRects *)get_virt(worker, *in_clip, sizeof(QXLClipRects), group_id);
+    clip = (QXLClipRects *)get_virt(&worker->mem_slots, *in_clip, sizeof(QXLClipRects), group_id);
     *in_clip = channel->send_data.header.size;
     add_buf(channel, BUF_TYPE_RAW, &clip->num_rects, sizeof(uint32_t), 0, 0);
     add_buf(channel, BUF_TYPE_CHUNK, &clip->chunk, clip->num_rects * sizeof(SpiceRect), memslot_id,
@@ -5156,7 +5011,7 @@ static inline void fill_palette(DisplayChannel *display_channel, SPICE_ADDRESS *
     if (!(*io_palette)) {
         return;
     }
-    palette = (SpicePalette *)get_virt(worker, *io_palette, sizeof(SpicePalette), group_id);
+    palette = (SpicePalette *)get_virt(&worker->mem_slots, *io_palette, sizeof(SpicePalette), group_id);
     if (palette->unique) {
         if (red_palette_cache_find(display_channel, palette->unique)) {
             *flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
@@ -5794,20 +5649,20 @@ static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBi
         y = bitmap->y;
         switch (bitmap->format) {
         case SPICE_BITMAP_FMT_16BIT: {
-            uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, x * y *
+            uint8_t *lines = (uint8_t*)get_virt(&worker->mem_slots, bitmap->data, x * y *
                                                 sizeof(rgb16_pixel_t), group_id);
             compute_lines_gradual_score_rgb16((rgb16_pixel_t*)lines, x, y, &score, &num_samples);
             break;
         }
         case SPICE_BITMAP_FMT_24BIT: {
-            uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, x * y *
+            uint8_t *lines = (uint8_t*)get_virt(&worker->mem_slots, bitmap->data, x * y *
                                                 sizeof(rgb24_pixel_t), group_id);
             compute_lines_gradual_score_rgb24((rgb24_pixel_t*)lines, x, y, &score, &num_samples);
             break;
         }
         case SPICE_BITMAP_FMT_32BIT:
         case SPICE_BITMAP_FMT_RGBA: {
-            uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, x * y *
+            uint8_t *lines = (uint8_t*)get_virt(&worker->mem_slots, bitmap->data, x * y *
                                                 sizeof(rgb32_pixel_t), group_id);
             compute_lines_gradual_score_rgb32((rgb32_pixel_t*)lines, x, y, &score, &num_samples);
             break;
@@ -5824,29 +5679,29 @@ static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBi
         SPICE_ADDRESS relative_address = bitmap->data;
 
         while (relative_address) {
-            chunk = (QXLDataChunk *)get_virt(worker, relative_address, sizeof(QXLDataChunk),
+            chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, relative_address, sizeof(QXLDataChunk),
                                              group_id);
             num_lines = chunk->data_size / bitmap->stride;
             x = bitmap->x;
             switch (bitmap->format) {
             case SPICE_BITMAP_FMT_16BIT:
-                validate_virt(worker, (unsigned long)chunk->data,
-                              get_memslot_id(worker, relative_address),
+                validate_virt(&worker->mem_slots, (unsigned long)chunk->data,
+                              get_memslot_id(&worker->mem_slots, relative_address),
                               sizeof(rgb16_pixel_t) * x * num_lines, group_id);
                 compute_lines_gradual_score_rgb16((rgb16_pixel_t*)chunk->data, x, num_lines,
                                                   &chunk_score, &chunk_num_samples);
                 break;
             case SPICE_BITMAP_FMT_24BIT:
-                validate_virt(worker, (unsigned long)chunk->data,
-                              get_memslot_id(worker, relative_address),
+                validate_virt(&worker->mem_slots, (unsigned long)chunk->data,
+                              get_memslot_id(&worker->mem_slots, relative_address),
                               sizeof(rgb24_pixel_t) * x * num_lines, group_id);
                 compute_lines_gradual_score_rgb24((rgb24_pixel_t*)chunk->data, x, num_lines,
                                                   &chunk_score, &chunk_num_samples);
                 break;
             case SPICE_BITMAP_FMT_32BIT:
             case SPICE_BITMAP_FMT_RGBA:
-                validate_virt(worker, (unsigned long)chunk->data,
-                              get_memslot_id(worker, relative_address),
+                validate_virt(&worker->mem_slots, (unsigned long)chunk->data,
+                              get_memslot_id(&worker->mem_slots, relative_address),
                               sizeof(rgb32_pixel_t) *  x * num_lines, group_id);
                 compute_lines_gradual_score_rgb32((rgb32_pixel_t*)chunk->data, x, num_lines,
                                                   &chunk_score, &chunk_num_samples);
@@ -5961,13 +5816,13 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
 
     if ((src->flags & QXL_BITMAP_DIRECT)) {
         glz_data->usr.more_lines = glz_usr_no_more_lines;
-        lines = (uint8_t*)get_virt(worker, src->data, src->stride * src->y, drawable->group_id);
+        lines = (uint8_t*)get_virt(&worker->mem_slots, src->data, src->stride * src->y, drawable->group_id);
         num_lines = src->y;
     } else {
         glz_data->data.u.lines_data.enc_get_virt = cb_get_virt;
-        glz_data->data.u.lines_data.enc_get_virt_opaque = worker;
+        glz_data->data.u.lines_data.enc_get_virt_opaque = &worker->mem_slots;
         glz_data->data.u.lines_data.enc_validate_virt = cb_validate_virt;
-        glz_data->data.u.lines_data.enc_validate_virt_opaque = worker;
+        glz_data->data.u.lines_data.enc_validate_virt_opaque = &worker->mem_slots;
         glz_data->data.u.lines_data.stride = src->stride;
         glz_data->data.u.lines_data.next = src->data;
         glz_data->data.u.lines_data.group_id = drawable->group_id;
@@ -6033,14 +5888,14 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
     if ((src->flags & QXL_BITMAP_DIRECT)) {
         lz_data->usr.more_lines = lz_usr_no_more_lines;
         size = lz_encode(lz, type, src->x, src->y, (src->flags & QXL_BITMAP_TOP_DOWN),
-                         (uint8_t*)get_virt(worker, src->data, src->stride * src->y, group_id),
+                         (uint8_t*)get_virt(&worker->mem_slots, src->data, src->stride * src->y, group_id),
                          src->y, src->stride, (uint8_t*)lz_data->data.bufs_head->buf,
                          sizeof(lz_data->data.bufs_head->buf));
     } else {
         lz_data->data.u.lines_data.enc_get_virt = cb_get_virt;
-        lz_data->data.u.lines_data.enc_get_virt_opaque = worker;
+        lz_data->data.u.lines_data.enc_get_virt_opaque = &worker->mem_slots;
         lz_data->data.u.lines_data.enc_validate_virt = cb_validate_virt;
-        lz_data->data.u.lines_data.enc_validate_virt_opaque = worker;
+        lz_data->data.u.lines_data.enc_validate_virt_opaque = &worker->mem_slots;
         lz_data->data.u.lines_data.stride = src->stride;
         lz_data->data.u.lines_data.next = src->data;
         lz_data->data.u.lines_data.group_id = group_id;
@@ -6138,11 +5993,11 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm
         uint8_t *data;
 
         if (!(src->flags & QXL_BITMAP_TOP_DOWN)) {
-            data = (uint8_t*)get_virt(worker, src->data, src->stride * src->y, group_id) +
+            data = (uint8_t*)get_virt(&worker->mem_slots, src->data, src->stride * src->y, group_id) +
                    src->stride * (src->y - 1);
             stride = -src->stride;
         } else {
-            data = (uint8_t*)get_virt(worker, src->data, src->stride * src->y, group_id);
+            data = (uint8_t*)get_virt(&worker->mem_slots, src->data, src->stride * src->y, group_id);
             stride = src->stride;
         }
 
@@ -6179,9 +6034,9 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm
             return FALSE;
         }
         quic_data->data.u.lines_data.enc_get_virt = cb_get_virt;
-        quic_data->data.u.lines_data.enc_get_virt_opaque = worker;
+        quic_data->data.u.lines_data.enc_get_virt_opaque = &worker->mem_slots;
         quic_data->data.u.lines_data.enc_validate_virt = cb_validate_virt;
-        quic_data->data.u.lines_data.enc_validate_virt_opaque = worker;
+        quic_data->data.u.lines_data.enc_validate_virt_opaque = &worker->mem_slots;
         quic_data->data.u.lines_data.stride = src->stride;
         quic_data->data.u.lines_data.group_id = group_id;
 
@@ -6191,17 +6046,17 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, RedIm
             stride = src->stride;
         } else {
             SPICE_ADDRESS prev_addr = src->data;
-            QXLDataChunk *chunk = (QXLDataChunk *)get_virt(worker, src->data,
+            QXLDataChunk *chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, src->data,
                                                            sizeof(QXLDataChunk), group_id);
             while (chunk->next_chunk) {
                 prev_addr = chunk->next_chunk;
-                chunk = (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk),
+                chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk, sizeof(QXLDataChunk),
                                                  group_id);
                 ASSERT(chunk->prev_chunk);
             }
             quic_data->data.u.lines_data.next = (SPICE_ADDRESS)prev_addr -
-                                                get_virt_delta(worker,
-                                                               get_memslot_id(worker, src->data),
+                                                get_virt_delta(&worker->mem_slots,
+                                                               get_memslot_id(&worker->mem_slots, src->data),
                                                                group_id);
             quic_data->usr.more_lines = quic_usr_more_lines_revers;
             stride = -src->stride;
@@ -6364,7 +6219,7 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
         ASSERT(drawable->self_bitmap);
         qxl_image = (QXLImage *)drawable->self_bitmap;
     } else {
-        qxl_image = (QXLImage *)get_virt(worker, *in_bitmap, sizeof(QXLImage),
+        qxl_image = (QXLImage *)get_virt(&worker->mem_slots, *in_bitmap, sizeof(QXLImage),
                                          drawable->group_id);
     }
 
@@ -6376,7 +6231,7 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
     image->descriptor.width = qxl_image->descriptor.width;
     image->descriptor.height = qxl_image->descriptor.height;
 
-    memslot_id = get_memslot_id(worker, *in_bitmap);
+    memslot_id = get_memslot_id(&worker->mem_slots, *in_bitmap);
     *in_bitmap = channel->send_data.header.size;
     if ((qxl_image->descriptor.flags & QXL_IMAGE_CACHE)) {
         if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id,
@@ -6432,10 +6287,10 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D
                          drawable->group_id);
             image->bitmap.data = channel->send_data.header.size;
             if (qxl_image->bitmap.flags & QXL_BITMAP_DIRECT) {
-                data = (uint8_t *)get_virt(worker, image_data, stride * y, drawable->group_id);
+                data = (uint8_t *)get_virt(&worker->mem_slots, image_data, stride * y, drawable->group_id);
                 add_buf(channel, BUF_TYPE_RAW, data, y * stride, 0, 0);
             } else {
-                data = (uint8_t *)get_virt(worker, image_data, sizeof(QXLDataChunk),
+                data = (uint8_t *)get_virt(&worker->mem_slots, image_data, sizeof(QXLDataChunk),
                                            drawable->group_id);
                 add_buf(channel, BUF_TYPE_CHUNK, data, y * stride, memslot_id, drawable->group_id);
             }
@@ -6491,7 +6346,7 @@ static void fill_attr(DisplayChannel *display_channel, SpiceLineAttr *attr, uint
 {
     if (attr->style_nseg) {
         RedChannel *channel = &display_channel->base;
-        uint8_t *buf = (uint8_t *)get_virt(channel->worker, attr->style,
+        uint8_t *buf = (uint8_t *)get_virt(&channel->worker->mem_slots, attr->style,
                                            attr->style_nseg * sizeof(uint32_t), group_id);
         ASSERT(attr->style);
         attr->style = channel->send_data.header.size;
@@ -6513,7 +6368,7 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
         QXLCursor *qxl_cursor;
 
         cursor_cmd = cursor->qxl_cursor;
-        qxl_cursor = (QXLCursor *)get_virt(channel->worker, cursor_cmd->u.set.shape,
+        qxl_cursor = (QXLCursor *)get_virt(&channel->worker->mem_slots, cursor_cmd->u.set.shape,
                                            sizeof(QXLCursor), cursor->group_id);
         red_cursor->flags = 0;
         red_cursor->header = qxl_cursor->header;
@@ -6530,7 +6385,7 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
 
         if (qxl_cursor->data_size) {
             add_buf(channel, BUF_TYPE_CHUNK, &qxl_cursor->chunk, qxl_cursor->data_size,
-                    get_memslot_id(channel->worker, cursor_cmd->u.set.shape), cursor->group_id);
+                    get_memslot_id(&channel->worker->mem_slots, cursor_cmd->u.set.shape), cursor->group_id);
         }
     } else {
         LocalCursor *local_cursor;
@@ -6734,7 +6589,7 @@ static inline uint32_t __fill_iovec(RedWorker *worker, BufDescriptor *buf, int s
             data_size -= skip_now;
 
             if (data_size) {
-                validate_virt(worker, (unsigned long)chunk->data, buf->slot_id, data_size,
+                validate_virt(&worker->mem_slots, (unsigned long)chunk->data, buf->slot_id, data_size,
                               buf->group_id);
                 size += data_size;
                 vec[*vec_index].iov_base = chunk->data + skip_now;
@@ -6742,7 +6597,7 @@ static inline uint32_t __fill_iovec(RedWorker *worker, BufDescriptor *buf, int s
                 (*vec_index)++;
             }
             chunk = chunk->next_chunk ?
-                    (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk),
+                    (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk, sizeof(QXLDataChunk),
                                              buf->group_id) :
                     NULL;
         } while (chunk && *vec_index < MAX_SEND_VEC);
@@ -6930,10 +6785,10 @@ static inline uint8_t *red_get_image_line(RedWorker *worker, QXLDataChunk **chun
     uint8_t *ret;
     uint32_t data_size;
 
-    validate_virt(worker, (unsigned long)*chunk, memslot_id, sizeof(QXLDataChunk),
+    validate_virt(&worker->mem_slots, (unsigned long)*chunk, memslot_id, sizeof(QXLDataChunk),
                   group_id);
     data_size = (*chunk)->data_size;
-    validate_virt(worker, (unsigned long)(*chunk)->data, memslot_id, data_size, group_id);
+    validate_virt(&worker->mem_slots, (unsigned long)(*chunk)->data, memslot_id, data_size, group_id);
 
     if (data_size == *offset) {
         if ((*chunk)->next_chunk == 0) {
@@ -7119,7 +6974,7 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
 
     channel = &display_channel->base;
     worker = channel->worker;
-    qxl_image = (QXLImage *)get_virt(worker,  drawable->qxl_drawable->u.copy.src_bitmap,
+    qxl_image = (QXLImage *)get_virt(&worker->mem_slots,  drawable->qxl_drawable->u.copy.src_bitmap,
                                      sizeof(QXLImage), drawable->group_id);
 
     if (qxl_image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP ||
@@ -7142,8 +6997,8 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     case SPICE_BITMAP_FMT_32BIT:
         if (!red_rgb32bpp_to_24(worker, &drawable->qxl_drawable->u.copy.src_area,
                                 &qxl_image->bitmap, frame, frame_stride,
-                                get_virt_delta(worker, data, drawable->group_id),
-                                get_memslot_id(worker, data),
+                                get_virt_delta(&worker->mem_slots, data, drawable->group_id),
+                                get_memslot_id(&worker->mem_slots, data),
                                 stream - worker->streams_buf, stream, drawable->group_id)) {
             return FALSE;
         }
@@ -7151,8 +7006,8 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     case SPICE_BITMAP_FMT_16BIT:
         if (!red_rgb16bpp_to_24(worker, &drawable->qxl_drawable->u.copy.src_area,
                                 &qxl_image->bitmap, frame, frame_stride,
-                                get_virt_delta(worker, data, drawable->group_id),
-                                get_memslot_id(worker, data),
+                                get_virt_delta(&worker->mem_slots, data, drawable->group_id),
+                                get_memslot_id(&worker->mem_slots, data),
                                 stream - worker->streams_buf, stream, drawable->group_id)) {
             return FALSE;
         }
@@ -7160,8 +7015,8 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     case SPICE_BITMAP_FMT_24BIT:
         if (!red_rgb24bpp_to_24(worker, &drawable->qxl_drawable->u.copy.src_area,
                                 &qxl_image->bitmap, frame, frame_stride,
-                                get_virt_delta(worker, data, drawable->group_id),
-                                get_memslot_id(worker, data),
+                                get_virt_delta(&worker->mem_slots, data, drawable->group_id),
+                                get_memslot_id(&worker->mem_slots, data),
                                 stream - worker->streams_buf, stream, drawable->group_id)) {
             return FALSE;
         }
@@ -7395,7 +7250,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     compress_send_data_t comp_send_data;
 
     if (red_quic_compress_image(display_channel, red_image, &bitmap, &comp_send_data,
-                                worker->internal_groupslot_id)) {
+                                worker->mem_slots.internal_groupslot_id)) {
         add_buf(channel, BUF_TYPE_RAW, red_image, comp_send_data.raw_size, 0, 0);
         add_buf(channel, BUF_TYPE_COMPRESS_BUF, comp_send_data.comp_buf,
                 comp_send_data.comp_buf_size, 0, 0);
@@ -8950,7 +8805,7 @@ static void red_cursor_flush(RedWorker *worker)
 
     cursor_cmd = worker->cursor->qxl_cursor;
     ASSERT(cursor_cmd->type == QXL_CURSOR_SET);
-    qxl_cursor = (QXLCursor *)get_virt(worker, cursor_cmd->u.set.shape, sizeof(QXLCursor),
+    qxl_cursor = (QXLCursor *)get_virt(&worker->mem_slots, cursor_cmd->u.set.shape, sizeof(QXLCursor),
                                        worker->cursor->group_id);
 
     local = _new_local_cursor(&qxl_cursor->header, qxl_cursor->data_size,
@@ -8967,8 +8822,8 @@ static void red_cursor_flush(RedWorker *worker)
         data_size -= chunk->data_size;
         dest += chunk->data_size;
         chunk = chunk->next_chunk ?
-                (QXLDataChunk *)get_virt(worker, chunk->next_chunk, sizeof(QXLDataChunk),
-                                         worker->internal_groupslot_id) : NULL;
+                (QXLDataChunk *)get_virt(&worker->mem_slots, chunk->next_chunk, sizeof(QXLDataChunk),
+                                         worker->mem_slots.internal_groupslot_id) : NULL;
     }
     red_set_cursor(worker, &local->base);
     red_release_cursor(worker, &local->base);
@@ -9057,13 +8912,9 @@ static inline void handle_dev_add_memslot(RedWorker *worker)
 
     receive_data(worker->channel, &dev_slot, sizeof(QXLDevMemSlot));
 
-    ASSERT(worker->num_memslots_groups > dev_slot.slot_group_id);
-    ASSERT(worker->num_memslots > dev_slot.slot_id);
-    worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].address_delta = dev_slot.addr_delta;
-    worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].virt_start_addr =
-                                                                                dev_slot.virt_start;
-    worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].virt_end_addr = dev_slot.virt_end;
-    worker->mem_slots[dev_slot.slot_group_id][dev_slot.slot_id].generation = dev_slot.generation;
+    red_memslot_info_add_slot(&worker->mem_slots, dev_slot.slot_group_id, dev_slot.slot_id,
+                              dev_slot.addr_delta, dev_slot.virt_start, dev_slot.virt_end,
+                              dev_slot.generation);
 
     message = RED_WORKER_MESSAGE_READY;
     write_message(worker->channel, &message);
@@ -9077,11 +8928,7 @@ static inline void handle_dev_del_memslot(RedWorker *worker)
     receive_data(worker->channel, &slot_group_id, sizeof(uint32_t));
     receive_data(worker->channel, &slot_id, sizeof(uint32_t));
 
-    ASSERT(worker->num_memslots_groups > slot_group_id);
-    ASSERT(worker->num_memslots > slot_id);
-
-    worker->mem_slots[slot_group_id][slot_id].virt_start_addr = 0;
-    worker->mem_slots[slot_group_id][slot_id].virt_end_addr = 0;
+    red_memslot_info_del_slot(&worker->mem_slots, slot_group_id, slot_id);
 }
 
 static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
@@ -9182,7 +9029,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     PANIC_ON(((uint64_t)abs(surface.stride) * (uint64_t)surface.height) !=
              abs(surface.stride) * surface.height);
 
-    line_0 = (uint8_t*)get_virt(worker, surface.mem, surface.height * abs(surface.stride),
+    line_0 = (uint8_t*)get_virt(&worker->mem_slots, surface.mem, surface.height * abs(surface.stride),
                                 surface.group_id);
     if (surface.stride < 0) {
         line_0 -= (int32_t)(surface.stride * (surface.height -1));
@@ -9243,25 +9090,6 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     write_message(worker->channel, &message);
 }
 
-static void inline red_create_mem_slots(RedWorker *worker)
-{
-    uint32_t i;
-
-    ASSERT(worker->num_memslots > 0);
-    ASSERT(worker->num_memslots_groups > 0);
-    worker->mem_slots = spice_new(MemSlot *, worker->num_memslots_groups);
-
-    for (i = 0; i <  worker->num_memslots_groups; ++i) {
-        worker->mem_slots[i] = spice_new0(MemSlot, worker->num_memslots);
-    }
-
-    worker->memslot_id_shift = 64 - worker->mem_slot_bits;
-    worker->memslot_gen_shift = 64 - (worker->mem_slot_bits + worker->generation_bits);
-    worker->memslot_gen_mask = ~((unsigned long)-1 << worker->generation_bits);
-    worker->memslot_clean_virt_mask = (((unsigned long)(-1)) >>
-                                       (worker->mem_slot_bits + worker->generation_bits));
-}
-
 static void handle_dev_input(EventListener *listener, uint32_t events)
 {
     RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
@@ -9470,13 +9298,9 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_DEL_MEMSLOT:
         handle_dev_del_memslot(worker);
         break;
-    case RED_WORKER_MESSAGE_RESET_MEMSLOTS: {
-        uint32_t i;
-        for (i = 0; i <  worker->num_memslots_groups; ++i) {
-            memset(worker->mem_slots[i], 0, sizeof(MemSlot) * worker->num_memslots);
-        }
+    case RED_WORKER_MESSAGE_RESET_MEMSLOTS:
+        red_memslot_info_reset(&worker->mem_slots);
         break;
-    }
     default:
         red_error("message error");
     }
@@ -9537,14 +9361,15 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
         red_error("add channel failed, %s", strerror(errno));
     }
 
-    worker->num_memslots_groups = init_data->num_memslots_groups;
-    worker->num_memslots = init_data->num_memslots;
-    worker->generation_bits = init_data->memslot_gen_bits;
-    worker->mem_slot_bits = init_data->memslot_id_bits;
-    worker->internal_groupslot_id = init_data->internal_groupslot_id;
+    red_memslot_info_init(&worker->mem_slots,
+                          init_data->num_memslots_groups,
+                          init_data->num_memslots,
+                          init_data->memslot_gen_bits,
+                          init_data->memslot_id_bits,
+                          init_data->internal_groupslot_id);
+
     PANIC_ON(init_data->n_surfaces > NUM_SURFACES);
     worker->n_surfaces = init_data->n_surfaces;
-    red_create_mem_slots(worker);
 
     worker->preload_group_virt_mapping.ops = &preload_group_virt_mapping_ops;
 
@@ -9704,7 +9529,7 @@ static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_i
         if (!bitmap->palette) {
             return; // dont dump masks.
         }
-        plt = (SpicePalette *)get_virt(worker, bitmap->palette, sizeof(SpicePalette), group_id);
+        plt = (SpicePalette *)get_virt(&worker->mem_slots, bitmap->palette, sizeof(SpicePalette), group_id);
     }
     row_size = (((bitmap->x * n_pixel_bits) + 31) / 32) * 4;
     bitmap_data_offset = header_size;
@@ -9760,7 +9585,7 @@ static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_i
     }
     /* writing the data */
     if ((bitmap->flags & QXL_BITMAP_DIRECT)) {
-        uint8_t *lines = (uint8_t*)get_virt(worker, bitmap->data, bitmap->stride * bitmap->y,
+        uint8_t *lines = (uint8_t*)get_virt(&worker->mem_slots, bitmap->data, bitmap->stride * bitmap->y,
                                             group_id);
         int i;
         for (i = 0; i < bitmap->y; i++) {
@@ -9773,9 +9598,9 @@ static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_i
 
         while (relative_address) {
             int i;
-            chunk = (QXLDataChunk *)get_virt(worker, relative_address, sizeof(QXLDataChunk),
+            chunk = (QXLDataChunk *)get_virt(&worker->mem_slots, relative_address, sizeof(QXLDataChunk),
                                              group_id);
-            validate_virt(worker, chunk->data, get_memslot_id(worker, relative_address),
+            validate_virt(&worker->mem_slots, chunk->data, get_memslot_id(&worker->mem_slots, relative_address),
                           chunk->data_size, group_id);
             num_lines = chunk->data_size / bitmap->stride;
             for (i = 0; i < num_lines; i++) {


More information about the Spice-commits mailing list