Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 10

kvm-83-270.el5_11.src.rpm

From 0f07d0e2101e8778d695e324c66115f708cd4905 Mon Sep 17 00:00:00 2001
From: Yaniv Kamay <yaniv@qumranet.com>
Date: Sun, 21 Dec 2008 11:44:23 +0200
Subject: [PATCH 05/54] qxl: import base qxl files from qdesktop repo

RH-Type: improvement(qxl)
RH-Upstream-status: pending
---
 qemu/hw/draw.h          |  389 ++++++++++++++
 qemu/hw/qxl.c           | 1327 +++++++++++++++++++++++++++++++++++++++++++++++
 qemu/hw/qxl_dev.h       |  302 +++++++++++
 qemu/hw/qxl_interface.h |   60 +++
 qemu/hw/ring.h          |  104 ++++
 5 files changed, 2182 insertions(+), 0 deletions(-)
 create mode 100644 qemu/hw/draw.h
 create mode 100644 qemu/hw/qxl.c
 create mode 100644 qemu/hw/qxl_dev.h
 create mode 100644 qemu/hw/qxl_interface.h
 create mode 100644 qemu/hw/ring.h

diff --git a/qemu/hw/draw.h b/qemu/hw/draw.h
new file mode 100644
index 0000000..be12fa5
--- /dev/null
+++ b/qemu/hw/draw.h
@@ -0,0 +1,389 @@
+#ifndef _H_DRAW
+#define _H_DRAW
+
+#ifndef _WIN32
+#include <stdint.h>
+#endif
+
+#ifdef __GNUC__
+#define ATTR_PACKED __attribute__ ((__packed__))
+typedef uint64_t UINT64;
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t UINT8;
+
+typedef int16_t INT16;
+typedef int32_t INT32;
+#else
+#include <basetsd.h>
+#pragma pack(push)
+#pragma pack(1)
+#define ATTR_PACKED
+#pragma warning(disable:4200)
+#endif
+
+#ifdef _WIN32_WCE
+#include <stdint.h>
+typedef uint64_t UINT64;
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t UINT8;
+
+typedef int16_t INT16;
+typedef int32_t INT32;
+#endif
+
+#define GET_ADDRESS(addr) ((void *)(unsigned long)(addr))
+#define SET_ADDRESS(addr, val) ((addr) = (unsigned long)(val))
+
+typedef INT32 FIXED28_4;
+typedef UINT64 ADDRESS;
+
+enum {
+    PATH_BEGIN = (1 << 0),
+    PATH_END = (1 << 1),
+    PATH_CLOSE = (1 << 3),
+    PATH_BEZIER = (1 << 4),
+};
+
+enum {
+    LINE_ATTR_STARTGAP = (1 << 2),
+    LINE_ATTR_STYLED = (1 << 3),
+};
+
+typedef struct ATTR_PACKED PointFix {
+    FIXED28_4 x;
+    FIXED28_4 y;
+} PointFix;
+
+typedef struct ATTR_PACKED Point {
+    INT32 x;
+    INT32 y;
+} Point;
+
+typedef struct ATTR_PACKED Point16 {
+    INT16 x;
+    INT16 y;
+} Point16;
+
+typedef struct ATTR_PACKED Rect {
+    INT32 top;
+    INT32 left;
+    INT32 bottom;
+    INT32 right;
+} Rect;
+
+typedef struct ATTR_PACKED PathSeg {
+    UINT32 flags;
+    UINT32 count;
+    UINT8 data[0];
+} PathSeg;
+
+enum ClipType {
+    CLIP_TYPE_NONE,
+    CLIP_TYPE_RECTS,
+    CLIP_TYPE_PATH,
+};
+
+typedef struct ATTR_PACKED Clip {
+    UINT32 type;
+    ADDRESS data;
+} Clip;
+
+enum ROPDescriptor {
+    ROPD_INVERS_SRC = (1 << 0),
+    ROPD_INVERS_BRUSH = (1 << 1),
+    ROPD_INVERS_DEST = (1 << 2),
+    ROPD_OP_PUT = (1 << 3),
+    ROPD_OP_OR = (1 << 4),
+    ROPD_OP_AND = (1 << 5),
+    ROPD_OP_XOR = (1 << 6),
+    ROPD_OP_BLACKNESS = (1 << 7),
+    ROPD_OP_WHITENESS = (1 << 8),
+    ROPD_OP_INVERS = (1 << 9),
+    ROPD_INVERS_RES = (1 <<10),
+};
+
+typedef struct ATTR_PACKED Pattern {
+    ADDRESS pat;
+    Point pos;
+} Pattern; 
+
+enum {
+    BRUSH_TYPE_NONE,
+    BRUSH_TYPE_SOLID,
+    BRUSH_TYPE_PATTERN,
+};
+
+typedef struct ATTR_PACKED Brush {
+    UINT32 type;
+    union {
+        UINT32 color;
+        Pattern pattern;
+    } u;
+} Brush;
+
+enum {
+    MASK_INVERS = (1 << 0),
+};
+
+typedef struct ATTR_PACKED QMask {
+    UINT8 flags;
+    Point pos;
+    ADDRESS bitmap;
+} QMask;
+
+typedef struct ATTR_PACKED Fill {
+    Brush brush;
+    UINT16 rop_decriptor;
+    QMask mask;
+} Fill;
+
+typedef struct ATTR_PACKED Palette {
+    UINT64 unique;
+    UINT16 num_ents;
+    UINT32 ents[0];
+} Palette;
+
+enum {
+    IMAGE_TYPE_BITMAP,
+    IMAGE_TYPE_QUIC,
+    IMAGE_TYPE_LZ_PLT,
+    IMAGE_TYPE_LZ_RGB,
+    IMAGE_TYPE_PNG,
+    IMAGE_TYPE_FROM_CACHE,
+};
+
+enum {
+    IMAGE_CACHE_ME = (1 << 0),
+};
+
+typedef struct ATTR_PACKED ImageDescriptor {
+    UINT64 id;
+    UINT8 type;
+    UINT8 flags;
+    UINT32 width;
+    UINT32 height;
+} ImageDescriptor;
+
+enum {
+    BITMAP_FMT_INVALID,
+    BITMAP_FMT_1BIT_LE,
+    BITMAP_FMT_1BIT_BE,
+    BITMAP_FMT_4BIT_LE,
+    BITMAP_FMT_4BIT_BE,
+    BITMAP_FMT_8BIT,
+    BITMAP_FMT_16BIT,
+    BITMAP_FMT_24BIT,
+    BITMAP_FMT_32BIT,
+    BITMAP_FMT_RGBA,
+};
+
+enum {
+    BITMAP_PAL_CACHE_ME = (1 << 0),
+    BITMAP_PAL_FROM_CACHE = (1 << 1),
+    BITMAP_TOP_DOWN = (1 << 2),
+};
+
+typedef struct ATTR_PACKED Bitmap {
+    UINT8 format;
+    UINT8 flags;
+    UINT32 x;
+    UINT32 y;
+    UINT32 stride;
+    ADDRESS palette;
+    ADDRESS data; //data[0] ?
+} Bitmap;
+
+typedef struct ATTR_PACKED BitmapImage {
+    ImageDescriptor descriptor;
+    Bitmap bitmap;
+} BitmapImage;
+
+typedef struct ATTR_PACKED PNGData {
+    UINT32 data_size;
+    UINT8 data[0];
+} PNGData, QUICData, LZ_RGBData;
+
+typedef struct ATTR_PACKED PNGImage {
+    ImageDescriptor descriptor;
+    PNGData png;
+} PNGImage;
+
+typedef struct ATTR_PACKED QUICImage {
+    ImageDescriptor descriptor;
+    QUICData quic;
+} QUICImage;
+
+typedef struct ATTR_PACKED LZ_RGBImage {
+    ImageDescriptor descriptor;
+    LZ_RGBData lz_rgb;
+} LZ_RGBImage;
+
+typedef struct ATTR_PACKED LZ_PLTData {
+    UINT8 flags;
+    UINT32 data_size;
+    ADDRESS palette;
+    UINT8 data[0];
+} LZ_PLTData;
+
+typedef struct ATTR_PACKED LZ_PLTImage {
+    ImageDescriptor descriptor;
+    LZ_PLTData lz_plt;
+} LZ_PLTImage;
+
+typedef struct ATTR_PACKED LZImage {
+    ImageDescriptor descriptor;
+    union {
+        LZ_RGBData	lz_rgb;
+        LZ_PLTData	lz_plt;
+    };
+} LZImage;
+
+enum {
+    IMAGE_SCALE_INTERPOLATE,
+    IMAGE_SCALE_NEAREST,
+};
+
+typedef struct ATTR_PACKED Opaque {
+    ADDRESS src_bitmap;
+    Rect src_area;
+    Brush brush;
+    UINT16 rop_decriptor;
+    UINT8 scale_mode;
+    QMask mask;
+} Opaque;
+
+typedef struct ATTR_PACKED Copy {
+    ADDRESS src_bitmap;
+    Rect src_area;
+    UINT16 rop_decriptor;
+    UINT8 scale_mode;
+    QMask mask;
+} Copy, Blend;
+
+typedef struct ATTR_PACKED Transparent {
+    ADDRESS src_bitmap;
+    Rect src_area;
+    UINT32 src_color;
+    UINT32 true_color;
+} Transparent;
+
+typedef struct ATTR_PACKED AlphaBlnd {
+    UINT8 alpha;
+    ADDRESS src_bitmap;
+    Rect src_area;
+} AlphaBlnd;
+
+typedef struct ATTR_PACKED Rop3 {
+    ADDRESS src_bitmap;
+    Rect src_area;
+    Brush brush;
+    UINT8 rop3;
+    UINT8 scale_mode;
+    QMask mask;
+} Rop3;
+
+typedef struct ATTR_PACKED Blackness {
+    QMask mask;
+} Blackness, Invers, Whiteness;
+
+enum {
+    LINE_SCALABLE = (1 << 0),
+    LINE_STYLED = (1 << 3), 
+    LINE_START_WITH_GAP = (1 << 2),
+};
+
+enum {
+    LINE_CAP_ROUND,
+    LINE_CAP_SQUARE,
+    LINE_CAP_BUTT,
+};
+
+enum {
+    LINE_JOIN_ROUND,
+    LINE_JOIN_BEVEL,
+    LINE_JOIN_MITER,
+};
+
+typedef struct ATTR_PACKED LineAttr {
+    UINT8 flags;
+    UINT8 join_style;
+    UINT8 end_style;
+    UINT8 style_nseg;
+    FIXED28_4 width;
+    FIXED28_4 miter_limit;
+    ADDRESS style; //data[0] ?
+} LineAttr;
+
+typedef struct ATTR_PACKED Stroke {
+    ADDRESS path;
+    LineAttr attr;
+    Brush brush;
+    UINT16 fore_mode;
+    UINT16 back_mode;
+} Stroke;
+
+typedef struct ATTR_PACKED RasterGlyph {
+    Point render_pos;
+    Point glyph_origin;
+    UINT16 width;
+    UINT16 height;
+    UINT8 data[0];
+} RasterGlyph;
+
+typedef struct ATTR_PACKED VectotGlyph {
+    Point render_pos;
+    UINT32 data_size;
+    UINT8 data[0]; //PathSeg[]
+} VectotGlyph;
+
+enum {
+    STRING_RASTER_A1 = 1 << 0,
+    STRING_RASTER_A4 = 1 << 1,
+    STRING_RASTER_A8 = 1 << 2,
+    STRING_RASTER_TOP_DOWN = 1 << 3,
+};
+
+typedef struct ATTR_PACKED String {
+    UINT16 length;
+    UINT16 flags;
+    UINT8 data[0];
+} String;
+
+typedef struct ATTR_PACKED Text {
+    ADDRESS str;
+    Rect back_area;
+    Brush fore_brush;
+    Brush back_brush;
+    UINT16 fore_mode;
+    UINT16 back_mode;
+} Text;
+
+enum {
+    CURSOR_TYPE_ALPHA,
+    CURSOR_TYPE_MONO,
+    CURSOR_TYPE_COLOR4,
+    CURSOR_TYPE_COLOR8,
+    CURSOR_TYPE_COLOR16,
+    CURSOR_TYPE_COLOR24,
+    CURSOR_TYPE_COLOR32,
+};
+
+typedef struct ATTR_PACKED CursorHeader {
+    UINT64 unique;
+    UINT16 type;
+    UINT16 width;
+    UINT16 height;
+    UINT16 hot_spot_x;
+    UINT16 hot_spot_y;
+} CursorHeader;
+
+
+#ifndef __GNUC__
+#pragma pack(pop)
+#endif
+
+#undef ATTR_PACKED
+
+#endif
diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c
new file mode 100644
index 0000000..e37def9
--- /dev/null
+++ b/qemu/hw/qxl.c
@@ -0,0 +1,1327 @@
+#include <pthread.h>
+#include <signal.h>
+
+#include "qemu-common.h"
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "console.h"
+#include "vga_int.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+
+#include "qxl_dev.h"
+#include "qxl_interface.h"
+
+#include "qemu-kvm.h"
+
+#define KVM_MEM_ALIAS_QXL_RAM 0
+#define KVM_MEM_ALIAS_QXL_VRAM 1
+#define KVM_MEM_ALIAS_QXL_ROM 2
+
+
+//#define QXL_IO_MEM
+
+#define QXL_RAM_SIZE (32 * 1024 * 1024)
+#define QXL_DEFAULT_COMPRESSION_LEVEL 2
+#define QXL_SHARED_VGA_MODE FALSE
+#define QXL_SAVE_VERSION 3
+
+
+#define ASSERT(x) if (!(x)) { 					\
+	printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); 	\
+	exit(-1);						\
+}
+
+#undef ALIGN
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+#define TRUE 1
+#define FALSE 0
+
+#define QXL_DEV_NAME "qxl"
+
+#define PCI_CLASS_DISPLAY 0x03
+#define PCI_DISPLAY_SUBCLASS_VGA 0x00
+#define PCI_DISPLAY_VGA_PROGIF 0x00
+#define PCI_DISPLAY_SUBCLASS_OTHER 0x80
+#define PCI_DISPLAY_OTHER_PROGIF 0x80
+
+typedef struct __attribute__ ((__packed__)) PCIConf_s /*little-endian*/ {
+    uint16_t vendor_ID;
+    uint16_t device_ID;
+    uint16_t command;
+    uint16_t status;
+    uint8_t revision;
+    uint8_t class_prog_if;
+    uint8_t class_sub;
+    uint8_t class_base;
+    uint8_t chache_line_size;
+    uint8_t latency;
+    uint8_t header;
+    uint8_t builti_selftest;
+    uint32_t base_address[6];
+    uint32_t cardbus_cis_pointer;
+    uint16_t subsystem_vendor_ID;
+    uint16_t subsystem_ID;
+    uint32_t expansion_rom_address;
+    uint32_t reserved[2];
+    uint8_t irq_line;
+    uint8_t interrupt_pin;
+    uint8_t min_grant;
+    uint8_t max_letency;
+} PCIConf;
+
+enum {
+    QXL_MODE_UNDEFINED,
+    QXL_MODE_VGA,
+    QXL_MODE_NATIVE,
+};
+
+typedef struct QXLState {
+    uint32_t io_base;
+    QXLRom *rom;
+    QXLModes *modes;
+    uint32_t rom_offset;
+    uint32_t rom_size;
+
+    uint8_t *ram_start;
+    QXLRam *ram;
+    uint32_t ram_offset;
+    uint32_t ram_size;
+    uint64_t ram_phys_addr;
+
+    uint8_t *vram;
+    unsigned long vram_offset;
+    uint32_t vram_size;
+#ifdef QXL_IO_MEM
+    int qxl_io_memory;
+#endif
+    int num_free_res;
+    QXLReleaseInfo *last_release;
+    QXLWorkerRef worker;
+    void *worker_data;
+    int worker_data_size;
+    int mode;
+    QXLCommandRing vga_ring;
+    uint32_t bits_unique;
+    int running;
+} QXLState;
+
+typedef struct PCIQXLDevice {
+    PCIDevice pci_dev;
+    QXLState state;
+    int id;
+    DisplayState ds;
+    struct PCIQXLDevice *dev_next;
+    struct PCIQXLDevice *vga_next;
+    int pipe_fd[2];
+} PCIQXLDevice;
+
+static PCIQXLDevice *dev_list = NULL;
+static pthread_t main_thread;
+static int compression_level = QXL_DEFAULT_COMPRESSION_LEVEL;
+
+#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
+
+#define QXL_MODE(x_res, y_res, bits, orientation) \
+    {0, x_res, y_res, bits, (x_res) * (bits) / 8, \
+     PIXEL_SIZE * (x_res), PIXEL_SIZE * (y_res), orientation}
+
+#define QXL_MODE_16_32(x_res, y_res, orientation) \
+    QXL_MODE(x_res, y_res, 16, orientation), QXL_MODE(x_res, y_res, 32, orientation)
+
+#define QXL_MODE_EX(x_res, y_res) \
+    QXL_MODE_16_32(x_res, y_res, 0), QXL_MODE_16_32(y_res, x_res, 1), \
+    QXL_MODE_16_32(x_res, y_res, 2), QXL_MODE_16_32(y_res, x_res, 3)
+
+//#define QXL_HIRES_MODES
+
+QXLMode qxl_modes[] = {
+    QXL_MODE_EX(640, 480),
+    QXL_MODE_EX(800, 600), 
+    QXL_MODE_EX(832, 624), 
+    QXL_MODE_EX(1024, 768),
+    QXL_MODE_EX(1152, 864),
+    QXL_MODE_EX(1152, 870),
+    QXL_MODE_EX(1280, 720),
+    QXL_MODE_EX(1280, 768),
+    QXL_MODE_EX(1280, 800),
+    QXL_MODE_EX(1280, 960),
+    QXL_MODE_EX(1280, 1024),
+    QXL_MODE_EX(1360, 768),
+    QXL_MODE_EX(1366, 768),
+    QXL_MODE_EX(1400, 1050),
+    QXL_MODE_EX(1440, 900),
+    QXL_MODE_EX(1600, 900),
+    QXL_MODE_EX(1600, 1200),
+    QXL_MODE_EX(1680, 1050),
+    QXL_MODE_EX(1920, 1080),
+#ifdef QXL_HIRES_MODES
+    QXL_MODE_EX(1920, 1200),
+    QXL_MODE_EX(1920, 1440),
+    QXL_MODE_EX(2048, 1536),
+    QXL_MODE_EX(2560, 1600),
+    QXL_MODE_EX(2560, 2048),
+    QXL_MODE_EX(2800, 2100),
+    QXL_MODE_EX(3200, 2400),
+#endif
+};
+
+typedef struct QXLVga {
+    struct DisplayState *ds;
+    PCIQXLDevice *clients;
+    int active_clients;
+    QEMUTimer *timer;
+} QXLVga;
+
+static void qxl_exit_vga_mode(PCIQXLDevice *d);
+static void qxl_reset_state(PCIQXLDevice *d);
+
+static QXLVga qxl_vga;
+
+static QXLModeChangeNotifier qxl_mode_change_notifier = NULL;
+
+inline void atomic_or(uint32_t *var, uint32_t add)
+{
+   __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory");
+}
+
+inline uint32_t atomic_exchange(uint32_t val, uint32_t *ptr)
+{
+   __asm__ __volatile__("xchgl %0, %1" : "+q"(val), "+m" (*ptr) : : "memory");
+   return val;
+}
+
+static void qxl_init_modes()
+{
+    int i;
+
+    for (i = 0; i < sizeof(qxl_modes) / sizeof(QXLMode); i++) {
+        qxl_modes[i].id = i;
+    }
+}
+
+static UINT32 qxl_max_x_res()
+{
+    UINT32 res = 0;
+    int i;
+
+    for (i = 0; i < sizeof(qxl_modes) / sizeof(QXLMode); i++) {
+        res = MAX(qxl_modes[i].x_res, res);
+    }
+    return res;
+}
+
+static UINT32 qxl_max_y_res()
+{
+    UINT32 res = 0;
+    int i;
+
+    for (i = 0; i < sizeof(qxl_modes) / sizeof(QXLMode); i++) {
+        res = MAX(qxl_modes[i].y_res, res);
+    }
+    return res;
+}
+
+static int irq_level(PCIQXLDevice *d)
+{
+    return !!(d->state.ram->int_pending & d->state.ram->int_mask);
+
+}
+
+void qxl_update_irq()
+{
+    PCIQXLDevice *d = dev_list;
+    while (d) {
+        qemu_set_irq(d->pci_dev.irq[0], irq_level(d));
+        d = d->dev_next;
+    }
+}
+
+void qxl_set_compression_level(int new_compression_level)
+{
+    PCIQXLDevice *d = dev_list;
+
+    compression_level = new_compression_level;
+    while (d) {
+        d->state.rom->compression_level = compression_level;
+        d = d->dev_next;
+    }
+}
+
+void do_set_qxl_log_level(int log_level)
+{
+    PCIQXLDevice *d = dev_list;
+    while (d) {
+        d->state.rom->log_level = log_level;
+        d = d->dev_next;
+    }
+}
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+{
+    ASSERT(d->state.running);
+    mb();
+    if ((d->state.ram->int_pending & events) == events) {
+        return;
+    }
+    atomic_or(&d->state.ram->int_pending, events);
+    if (pthread_self() == main_thread) {
+        qemu_set_irq(d->pci_dev.irq[0], irq_level(d));
+    } else {
+        //dummy write in order to wake up the main thread
+        //to update the irq line
+        write(d->pipe_fd[1], d, 1);
+    }
+}
+
+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;
+}
+
+void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    QXLState *state = &d->state;
+    QXLMode *mode;
+
+    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->phys_start = 0;
+        info->phys_end = ~info->phys_start;
+        info->phys_delta = 0;
+        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->phys_start = (unsigned long)state->ram_start + state->rom->pages_offset;
+    info->phys_end = (unsigned long)state->ram_start + state->ram_size;
+    info->phys_delta = (long)state->ram_start - state->ram_phys_addr;
+    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;
+}
+
+int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    QXLCommandRing *ring = qxl_active_ring(d);
+    int notify;
+
+    if (RING_IS_EMPTY(ring)) {
+        return FALSE;
+    }
+    *cmd = *RING_CONS_ITEM(ring);
+    RING_POP(ring, notify);
+    if (d->state.mode != QXL_MODE_VGA && notify) {
+        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
+    }
+    return TRUE;
+}
+
+int qxl_has_command(QXLDevRef dev_ref)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    QXLCommandRing *ring = qxl_active_ring(d);
+    return !RING_IS_EMPTY(ring);
+}
+
+int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    QXLCursorRing *ring;
+    int notify;
+
+    if (d->state.mode == QXL_MODE_VGA) {
+        return 0;
+    }
+
+    ring = &d->state.ram->cursor_ring;
+
+    if (RING_IS_EMPTY(ring)) {
+        return 0;
+    }
+    *cmd = *RING_CONS_ITEM(ring);
+    RING_POP(ring, notify);
+    if (d->state.mode != QXL_MODE_VGA && notify) {
+        qxl_send_events(d, QXL_INTERRUPT_CURSOR);
+    }
+    return 1;
+}
+
+const Rect *qxl_get_update_area(QXLDevRef dev_ref)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    return &d->state.ram->update_area;
+}
+
+int qxl_req_cmd_notification(QXLDevRef dev_ref)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    int wait;
+
+    RING_CONS_WAIT(qxl_active_ring(d), wait);
+    return wait;
+}
+
+int qxl_req_cursor_notification(QXLDevRef dev_ref)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    int wait;
+
+    if (d->state.mode == QXL_MODE_VGA) {
+        return 1;
+    }
+
+    RING_CONS_WAIT(&d->state.ram->cursor_ring, wait);
+    return wait;
+}
+
+#define QXL_FREE_BUNCH_SIZE 10
+
+static inline void qxl_push_free_res(PCIQXLDevice *d)
+{
+    QXLState *state = &d->state;
+    QXLReleaseRing *ring = &state->ram->release_ring;
+
+    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;
+
+        RING_PUSH(ring, notify);
+        if (notify) {
+            qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
+        }
+        *RING_PROD_ITEM(ring) = 0;
+        state->num_free_res = 0;
+        state->last_release = NULL;
+    }
+}
+
+void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    UINT64 id = release_info->id;
+    QXLState *state = &d->state;
+    QXLReleaseRing *ring;
+    UINT64 *item;
+
+    if (state->mode == QXL_MODE_VGA) {
+        free((void *)id);
+        return;
+    }
+    ring = &state->ram->release_ring;
+    item = RING_PROD_ITEM(ring);
+    if (*item == 0) {
+        release_info->next = 0;
+        *item = id;
+        state->last_release = release_info;
+    } else {
+        state->last_release->next = release_info->id;
+        release_info->next = 0;
+        state->last_release = release_info;
+    }   
+    
+    state->num_free_res++;
+
+    qxl_push_free_res(d);
+}
+
+void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    QXLState *state = &d->state;
+
+    free(state->worker_data);
+    state->worker_data = data;
+    state->worker_data_size = size;
+}
+
+void *qxl_get_save_data(QXLDevRef dev_ref)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    QXLState *state = &d->state;
+
+    return state->worker_data;
+
+}
+
+int qxl_flush_resources(QXLDevRef dev_ref)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+    int ret;
+
+    if (d->state.mode == QXL_MODE_VGA) {
+        return 0;
+    }
+    ret = d->state.num_free_res; 
+    if (ret) {
+        qxl_push_free_res(d);
+    }
+    return ret;
+}
+
+void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
+
+    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)
+{
+    QXLCommandRing *ring;
+
+    if (d->state.mode == QXL_MODE_UNDEFINED) {
+        return;
+    }
+
+    qxl_worker_detach(d->state.worker);
+    if (d->state.mode != QXL_MODE_VGA) {
+        RING_INIT(&d->state.ram->cmd_ring);
+        RING_INIT(&d->state.ram->cursor_ring);
+        return;
+    }
+    
+    ring = &d->state.vga_ring;
+        
+    while (!RING_IS_EMPTY(ring)) {
+        QXLDrawable *drawable;
+        QXLCommand *cmd;
+        int notify;
+        
+        cmd = RING_CONS_ITEM(ring);
+        RING_POP(ring, notify);
+        ASSERT(cmd->type == QXL_CMD_DRAW);
+        drawable = (QXLDrawable *)cmd->data;
+        free(drawable);
+    }
+}
+
+static void qxl_notify_mode_change()
+{
+    PCIQXLDevice *d = dev_list;
+    int qxl_mode_native_counter = 0;
+    int mode = 0;
+
+    if (!qxl_mode_change_notifier){
+        return;
+    }
+    if (qxl_vga.active_clients > 0) {
+        qxl_mode_change_notifier(FALSE, 0, 0);
+        return;
+    }
+    while (d && qxl_mode_native_counter < 2) {
+        if (d->state.mode == QXL_MODE_NATIVE && ++qxl_mode_native_counter == 1) {
+            mode = d->state.rom->mode;
+        }
+        d = d->dev_next;
+    }
+    if (qxl_mode_native_counter == 1) {
+        qxl_mode_change_notifier(TRUE, qxl_modes[mode].x_res, qxl_modes[mode].y_res);
+    } else {
+        qxl_mode_change_notifier(FALSE, 0, 0);
+    }
+}
+
+void qxl_register_mode_change(QXLModeChangeNotifier notifier){
+    qxl_mode_change_notifier = notifier;
+    qxl_notify_mode_change();
+}
+
+void qxl_set_mm_time(uint32_t stamp)
+{
+    PCIQXLDevice *d = dev_list;
+    while (d) {
+        d->state.rom->mm_clock = stamp;
+        d = d->dev_next;
+    }
+}
+
+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();
+    qxl_worker_attach(d->state.worker);
+}
+
+void *vga_context = NULL;
+
+void qxl_set_vga_context(void *context)
+{
+    vga_context = context;
+}
+
+static void qxl_add_vga_client()
+{
+    if (qxl_vga.active_clients++ == 0) {
+        qemu_mod_timer(qxl_vga.timer, qemu_get_clock(rt_clock));
+    }
+}
+
+static void qxl_remove_vga_client()
+{
+    qxl_vga.active_clients--;
+}
+
+static void qxl_enter_vga_mode(PCIQXLDevice *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;
+    qxl_notify_mode_change();
+    qxl_add_vga_client();
+    vga_on_qxl_enter_vga(vga_context);
+}
+
+/* reset the state (assuming the worker is detached) */
+static void qxl_reset_state(PCIQXLDevice *d)
+{
+    QXLRam *ram = d->state.ram;
+    QXLRom *rom = d->state.rom;
+
+    ASSERT(RING_IS_EMPTY(&ram->cmd_ring));
+    ASSERT(RING_IS_EMPTY(&ram->cursor_ring));
+    ASSERT(RING_IS_EMPTY(&d->state.vga_ring));
+    ram->magic = QXL_RAM_MAGIC;
+    ram->int_pending = 0;
+    ram->int_mask = 0;
+    rom->update_id = 0;
+    RING_INIT(&ram->cmd_ring);
+    RING_INIT(&ram->cursor_ring);
+    RING_INIT(&d->state.vga_ring);
+    RING_INIT(&ram->release_ring);
+    *RING_PROD_ITEM(&ram->release_ring) = 0;
+    d->state.num_free_res = 0;
+    d->state.last_release = NULL;
+}
+
+/* reset: detach, reset_state, re-attach */
+static void qxl_reset(PCIQXLDevice *d)
+{
+    printf("%s\n", __FUNCTION__);
+    qxl_detach(d);
+    qxl_reset_state(d);
+    if (QXL_SHARED_VGA_MODE || !d->id) {
+        qxl_enter_vga_mode(d);
+        qxl_worker_attach(d->state.worker);
+    } else {
+        d->state.mode = QXL_MODE_UNDEFINED;
+        qxl_notify_mode_change();
+    }
+}
+
+static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)opaque;
+    uint32_t io_port = addr - d->state.io_base;
+#ifdef DEBUG_QXL
+    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) {
+        printf("%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
+        return;
+    }
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA:
+        qxl_worker_update_area(d->state.worker);
+        break;
+    case QXL_IO_NOTIFY_CMD:
+        qxl_worker_wakeup(d->state.worker);
+        break;
+    case QXL_IO_NOTIFY_CURSOR:
+        qxl_worker_wakeup(d->state.worker);
+        break;
+    case QXL_IO_UPDATE_IRQ:
+        qemu_set_irq(d->pci_dev.irq[0], irq_level(d));
+        break;
+    case QXL_IO_NOTIFY_OOM:
+        //todo: add counter
+        if (!RING_IS_EMPTY(&d->state.ram->release_ring)) {
+            break;
+        }
+        pthread_yield();
+        if (!RING_IS_EMPTY(&d->state.ram->release_ring)) {
+            break;
+        }
+        qxl_worker_oom(d->state.worker);
+        break;
+    case QXL_IO_LOG:
+        printf("%u: %s", d->id, d->state.ram->log_buf);
+        break;
+    case QXL_IO_RESET:
+        printf("%u: QXL_IO_RESET\n", d->id);
+        qxl_reset(d);
+        break;
+    case QXL_IO_SET_MODE:
+        printf("%u: QXL_IO_SET_MODE\n", d->id);
+        qxl_set_mode(d, val);
+        break;
+    default:
+        printf("%s: unexpected addr 0x%x val 0x%x\n", __FUNCTION__, addr, val);
+    }
+}
+
+static uint32_t ioport_read(void *opaque, uint32_t addr)
+{
+    printf("%s: unexpected\n", __FUNCTION__);
+    return 0xff;
+}
+
+
+static void ioport_map(PCIDevice *pci_dev, int region_num, 
+                       uint32_t addr, uint32_t size, int type)
+{
+    QXLState *s = &((PCIQXLDevice *)pci_dev)->state;
+
+    printf("%s: base 0x%x size 0x%x\n", __FUNCTION__, addr, size);
+    s->io_base = addr;
+    register_ioport_write(addr, size, 1, ioport_write, pci_dev);
+    register_ioport_read(addr, size, 1, ioport_read, pci_dev);
+}
+
+static void rom_map(PCIDevice *d, int region_num,
+                       uint32_t addr, uint32_t size, int type)
+{
+    QXLState *s = &((PCIQXLDevice *)d)->state;
+
+    printf("%s: addr 0x%x size 0x%x\n", __FUNCTION__, addr, size);
+
+    ASSERT((addr & (size - 1)) == 0);
+    ASSERT(size ==  s->rom_size);
+
+    cpu_register_physical_memory(addr, size, s->rom_offset | IO_MEM_ROM);
+    if (kvm_enabled() && kvm_create_memory_alias(kvm_context,
+                                               addr,
+                                               size,
+                                               s->rom_offset)) {
+        printf("%s: create memory alias failed\n", __FUNCTION__);
+        exit(-1);
+    }
+}
+
+static void ram_map(PCIDevice *d, int region_num,
+                     uint32_t addr, uint32_t size, int type)
+{
+    QXLState *s = &((PCIQXLDevice *)d)->state;
+
+    printf("%s: addr 0x%x size 0x%x\n", __FUNCTION__, addr, size);
+
+    ASSERT((addr & (size - 1)) == 0);
+    ASSERT((addr & ~TARGET_PAGE_MASK) == 0);
+    ASSERT(size ==  s->ram_size);
+    ASSERT((size & ~TARGET_PAGE_MASK) == 0);
+    s->ram_phys_addr = addr;
+    cpu_register_physical_memory(addr, size, s->ram_offset | IO_MEM_RAM);
+    if (kvm_enabled() && kvm_create_memory_alias(kvm_context,
+                                               addr,
+                                               size,
+                                               s->ram_offset)) {
+        printf("%s: create memory alias failed\n", __FUNCTION__);
+        exit(-1);
+    }
+}
+
+static void vram_map(PCIDevice *d, int region_num,
+                     uint32_t addr, uint32_t size, int type)
+{
+    QXLState *s = &((PCIQXLDevice *)d)->state;
+
+    printf("%s: addr 0x%x size 0x%x\n", __FUNCTION__, addr, size);
+
+    ASSERT((addr & (size - 1)) == 0);
+    ASSERT((addr & ~TARGET_PAGE_MASK) == 0);
+    ASSERT(size ==  s->vram_size);
+    ASSERT((size & ~TARGET_PAGE_MASK) == 0);
+#ifdef QXL_IO_MEM
+    cpu_register_physical_memory(addr, size, s->qxl_io_memory);
+#else
+    cpu_register_physical_memory(addr, size, s->vram_offset | IO_MEM_RAM);
+#endif
+    if (kvm_enabled() && kvm_create_memory_alias(kvm_context,
+                                               addr,
+                                               size,
+                                               s->vram_offset)) {
+        printf("%s: create memory alias failed\n", __FUNCTION__);
+        exit(-1);
+    }
+}
+
+
+#ifdef QXL_IO_MEM
+
+static void qxl_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    printf("%s: addr 0x%lx value 0x%x\n", __FUNCTION__, addr, value);
+}
+
+static void qxl_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    printf("%s: addr 0x%lx value 0x%x\n", __FUNCTION__, addr, value);
+}
+
+static void qxl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    printf("%s: addr 0x%lx value 0x%x\n", __FUNCTION__, addr, value);
+}
+
+
+static uint32_t qxl_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    printf("%s: addr 0x%lx\n", __FUNCTION__, addr);
+    return 0x000000FF;
+}
+
+static uint32_t qxl_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    printf("%s: addr 0x%lx\n", __FUNCTION__, addr);
+    return 0x0000FFFF;
+}
+
+static uint32_t qxl_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    printf("%s: addr 0x%lx\n", __FUNCTION__, addr);
+    return 0xFFFFFFFF;
+}
+
+
+static CPUReadMemoryFunc *qxl_mem_read[3] = {
+    qxl_mem_readb,
+    qxl_mem_readw,
+    qxl_mem_readl,
+};
+
+static CPUWriteMemoryFunc *qxl_mem_write[3] = {
+    qxl_mem_writeb,
+    qxl_mem_writew,
+    qxl_mem_writel,
+};
+#endif
+
+static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size,
+                             uint32_t *max_fb)
+{
+    QXLRom *rom = (QXLRom *)buf;
+    QXLModes *modes = (QXLModes *)(rom + 1);
+    QXLState *s = &d->state;
+    int i;
+
+    rom->magic = QXL_ROM_MAGIC;
+    rom->id = d->id;
+    rom->mode = 0;
+    rom->modes_offset = sizeof(QXLRom);
+    rom->draw_area_size =qxl_max_x_res() * sizeof(uint32_t) * qxl_max_y_res();
+    rom->compression_level = compression_level;
+    rom->log_level = 0;
+
+    *max_fb = 0;
+    modes->n_modes = sizeof(qxl_modes) / sizeof(QXLMode);
+
+    for (i = 0; i < modes->n_modes; i++) {
+        *max_fb =  MAX(qxl_modes[i].y_res * qxl_modes[i].stride, *max_fb);
+        modes->modes[i] = qxl_modes[i];
+    }
+    s->rom = rom;
+    s->modes = modes;
+    return (uint32_t)((uint8_t *)&modes->modes[i] - buf);
+}
+
+static void init_qxl_ram(QXLState *s, uint8_t *buf)
+{
+    uint32_t draw_area_size;
+    uint32_t ram_header_size;
+
+    s->ram_start = buf;
+
+    draw_area_size = s->rom->draw_area_size;
+    ram_header_size = ALIGN(sizeof(*s->ram), 8);
+    ASSERT(ram_header_size + draw_area_size < QXL_RAM_SIZE);
+
+    s->rom->ram_header_offset = QXL_RAM_SIZE - ram_header_size;
+    s->ram = (QXLRam *)(buf + s->rom->ram_header_offset);
+    s->ram->magic = QXL_RAM_MAGIC;
+    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;
+
+    s->rom->draw_area_offset = s->rom->ram_header_offset - draw_area_size;
+    s->rom->pages_offset = 0;
+    s->rom->num_io_pages = (QXL_RAM_SIZE - (draw_area_size + ram_header_size)) >> TARGET_PAGE_BITS;
+    ASSERT((s->rom->num_io_pages << TARGET_PAGE_BITS) >= VGA_RAM_SIZE);
+    printf("%s: npages %u\n", __FUNCTION__, s->rom->num_io_pages);
+}
+
+inline uint32_t msb_mask(uint32_t val)
+{
+    uint32_t mask;
+
+    do {
+        mask = ~(val - 1) & val;
+        val &= ~mask;
+    } while (mask < val);
+
+    return mask;
+}
+
+static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int h)
+{
+    PCIQXLDevice *client;
+
+    client = qxl_vga.clients;
+    while (client) {
+        if (client->state.mode == QXL_MODE_VGA && client->state.running) {
+            QXLDrawable *drawable;
+            QXLImage *image;
+            QXLCommandRing *ring;
+            QXLCommand *cmd;
+            int wait;
+            int notify;
+
+            drawable = (QXLDrawable *)malloc(sizeof(*drawable) + sizeof(*image));
+            ASSERT(drawable);
+            image = (QXLImage *)(drawable + 1);
+            drawable->bbox.left = x;
+            drawable->bbox.right = x + w;
+            drawable->bbox.top = y;
+            drawable->bbox.bottom = y + h;
+            drawable->clip.type = CLIP_TYPE_NONE;
+            drawable->clip.data = 0;
+            drawable->effect = QXL_EFFECT_OPAQUE;
+            drawable->release_info.id = (UINT64)drawable;
+            drawable->bitmap_offset = 0;
+            drawable->type = QXL_DRAW_COPY;
+
+            drawable->u.copy.rop_decriptor =  ROPD_OP_PUT;
+            drawable->u.copy.src_bitmap = (PHYSICAL)image;
+            drawable->u.copy.src_area.left = drawable->u.copy.src_area.top = 0;
+            drawable->u.copy.src_area.right = w;
+            drawable->u.copy.src_area.bottom = h;
+            drawable->u.copy.scale_mode = 0;
+            memset(&drawable->u.copy.mask, 0, sizeof(QMask));
+
+            image->descriptor.type = IMAGE_TYPE_BITMAP;
+            image->descriptor.flags = 0;
+            QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ++client->state.bits_unique);
+            image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN | QXL_BITMAP_UNSTABLE;
+            image->bitmap.format = BITMAP_FMT_32BIT;
+            image->bitmap.stride = ds->linesize;
+            image->descriptor.width = image->bitmap.x = w;
+            image->descriptor.height = image->bitmap.y = h;
+            image->bitmap.data = (PHYSICAL)(ds->data + y * ds->linesize + x * 4);
+            image->bitmap.palette = 0;
+
+            ring = &client->state.vga_ring;
+            for (;;) {    
+                RING_PROD_WAIT(ring, wait);
+                if (wait) {
+                    printf("%s: wait\n", __FUNCTION__);
+                    usleep(10000);
+                    continue;
+                }
+                break;
+            }
+
+            cmd = RING_PROD_ITEM(ring);
+            cmd->type = QXL_CMD_DRAW;
+            cmd->data = (PHYSICAL)drawable;
+            RING_PUSH(ring, notify);
+            if (notify) {
+                qxl_worker_wakeup(client->state.worker);
+            }
+        }
+        client = client->vga_next;
+    }
+}
+
+static void qxl_display_resize(struct DisplayState *ds, int w, int h)
+{
+    PCIQXLDevice *client; 
+    uint8_t *data = ds->data;
+    size_t buf_size;
+
+    ds->linesize = w * 4;
+    buf_size = ds->linesize * (h + 1);
+    ds->data = malloc(buf_size);
+    memset(ds->data, 0, buf_size);
+    ds->depth = 32;
+    ds->width = w;
+    ds->height = h;
+
+    client = qxl_vga.clients;
+    while (client) {
+        if (client->state.mode == QXL_MODE_VGA) {
+            printf("%s\n", __FUNCTION__);
+            qxl_reset(client);
+        }
+        client = client->vga_next;
+    }
+    free(data);
+}
+
+static void qxl_display_refresh(struct DisplayState *ds)
+{
+    if (qxl_vga.active_clients) {
+        vga_hw_update();
+    }
+}
+
+#define DISPLAY_REFRESH_INTERVAL 30
+
+static void display_update(void *opaque)
+{
+    if (!qxl_vga.active_clients) {
+        return;
+    }
+    qxl_display_refresh(qxl_vga.ds);
+    qemu_mod_timer(qxl_vga.timer, qemu_get_clock(rt_clock) + DISPLAY_REFRESH_INTERVAL);
+}
+
+void qxl_init_display(DisplayState *ds)
+{
+    ASSERT(ds->data == NULL);
+    memset(&qxl_vga, 0, sizeof(qxl_vga));
+    qxl_vga.ds = ds;
+    ds->dpy_update = qxl_display_update;
+    ds->dpy_resize = qxl_display_resize;
+    ds->dpy_refresh = qxl_display_refresh;
+    qxl_display_resize(ds, 640, 400);
+
+    qxl_vga.timer = qemu_new_timer(rt_clock, display_update, NULL);
+    qemu_mod_timer(qxl_vga.timer, qemu_get_clock(rt_clock));
+}
+
+static void qxl_exit_vga_mode(PCIQXLDevice *d)
+{
+    if (d->state.mode != QXL_MODE_VGA) {
+        return;
+    }
+    printf("%s\n", __FUNCTION__);
+    qxl_remove_vga_client();
+    d->state.mode = QXL_MODE_UNDEFINED;
+    vga_on_qxl_exit_vga(vga_context);
+}
+
+int qxl_vga_touch(void)
+{
+    PCIQXLDevice *d = qxl_vga.clients;
+    int ret = FALSE;
+    while (d) {
+        if (d->state.mode != QXL_MODE_VGA && (QXL_SHARED_VGA_MODE || !d->id)) {
+            qxl_reset(d);
+            ret = TRUE;
+        }
+        d = d->vga_next;
+    }
+    return ret;
+}
+
+static void qxl_save(QEMUFile* f, void* opaque)
+{
+    PCIQXLDevice* d=(PCIQXLDevice*)opaque;
+    QXLState*     s=&d->state;
+    uint32_t      last_release_offset;
+
+    qxl_worker_save(d->state.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)
+        last_release_offset = 0;
+    else
+        last_release_offset = (uint8_t *)s->last_release - phys_ram_base;
+    printf("QXL SAVE -- last_release_offset=%u \n", last_release_offset);
+    ASSERT(last_release_offset < phys_ram_size);
+    qemu_put_be32(f, last_release_offset);
+
+    qemu_put_be32(f, s->mode);
+    qemu_put_be32(f, s->bits_unique);
+
+    qemu_put_buffer(f, s->ram_start, s->ram_size);
+
+    qemu_put_be32(f, s->worker_data_size);
+    if (s->worker_data_size) {
+        qemu_put_buffer(f, s->worker_data, s->worker_data_size);
+    }
+}
+
+static int qxl_load(QEMUFile* f,void* opaque,int version_id)
+{
+    PCIQXLDevice* d = (PCIQXLDevice*)opaque;
+    QXLState*     s = &d->state;
+    uint32_t      last_release_offset;
+    int           ret;
+
+    if (version_id != QXL_SAVE_VERSION)
+        return -EINVAL;
+
+    ret = pci_device_load(&d->pci_dev, f);
+    if (ret) {
+       printf("%s: error=%d\n", __FUNCTION__, ret);
+       return ret;
+    }
+
+    if (d->state.mode != QXL_MODE_UNDEFINED) {
+        qxl_worker_detach(d->state.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);
+    if (last_release_offset >= phys_ram_size) {
+        fprintf(stderr, "QXL LOAD: last_release_offset=%u too big\n",
+               last_release_offset);
+        exit(-1);
+    }
+    if (last_release_offset == 0)
+        s->last_release = NULL;
+    else
+        s->last_release = (QXLReleaseInfo *)(phys_ram_base + last_release_offset);
+    s->mode = qemu_get_be32(f);
+    s->bits_unique = qemu_get_be32(f);
+
+    qemu_get_buffer(f, s->ram_start, s->ram_size);
+
+    free(s->worker_data);
+    s->worker_data = NULL;
+    s->worker_data_size = qemu_get_be32(f);
+    if (s->worker_data_size) {
+        if (!(s->worker_data = malloc(s->worker_data_size))) {
+            fprintf(stderr, "QXL LOAD: alloc worker data failed %u\n", s->worker_data_size);
+            exit(-1);
+        }
+        qemu_get_buffer(f, s->worker_data, s->worker_data_size);
+    }
+
+    if (version_id == 2) {
+        qemu_get_byte(f);
+    }
+
+    if (s->mode == QXL_MODE_VGA) {
+        qxl_add_vga_client();
+    }
+    if (s->mode != QXL_MODE_UNDEFINED) {
+        qxl_worker_attach(d->state.worker);
+        qxl_worker_load(d->state.worker);
+    }
+    qxl_notify_mode_change();
+    return 0;
+}
+
+static void qxl_pipe_read(void *opaque)
+{
+    PCIQXLDevice *d = opaque;
+    int len;
+    char dummy;
+
+    while (1) {
+        len = read(d->pipe_fd[0], &dummy, sizeof(dummy));
+        if (len == -1 && errno == EAGAIN)
+            break;
+        if (len != sizeof(dummy)) {
+            printf("%s:error reading pipe_fd, len=%d\n", __FUNCTION__, len);
+            break;
+        }
+    }
+    qxl_update_irq();
+}
+
+static void qxl_vm_change_state_handler(void *opaque, int running)
+{
+    PCIQXLDevice* d=(PCIQXLDevice*)opaque;
+
+    printf("QXL: %s: running=%d\n", __FUNCTION__, running);
+
+    if (running) {
+        d->state.running = TRUE;
+        qemu_set_fd_handler(d->pipe_fd[0], qxl_pipe_read, NULL, d);
+        qxl_worker_start(d->state.worker);
+        qemu_set_irq(d->pci_dev.irq[0], irq_level(d));
+        if (qxl_vga.active_clients) {
+            qemu_mod_timer(qxl_vga.timer, qemu_get_clock(rt_clock));
+        }
+    } else {
+        qemu_del_timer(qxl_vga.timer);
+        qxl_worker_stop(d->state.worker);
+        qemu_set_fd_handler(d->pipe_fd[0], NULL, NULL, d);
+        d->state.running = FALSE;
+    }
+}
+
+void init_pipe_signaling(PCIQXLDevice *d)
+{
+   if (pipe(d->pipe_fd) < 0) {
+       printf("%s:pipe creation failed\n", __FUNCTION__);
+       return;
+   }
+   fcntl(d->pipe_fd[0], F_SETFL, O_NONBLOCK | O_ASYNC);
+   fcntl(d->pipe_fd[1], F_SETFL, O_NONBLOCK);
+   fcntl(d->pipe_fd[0], F_SETOWN, getpid());
+}
+
+static void reset_handler(void *opaque)
+{
+    PCIQXLDevice *d = (PCIQXLDevice *)opaque;
+    if (!QXL_SHARED_VGA_MODE && d->id > 0) {
+        qxl_reset(d);
+    }
+}
+
+static int channel_id = 0;
+
+void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, 
+              uint32_t vram_size)
+{
+    PCIQXLDevice *d;
+    PCIConf *pci_conf;
+    uint32_t rom_size;
+    uint32_t max_fb;
+
+    d = (PCIQXLDevice*)pci_register_device(bus, QXL_DEV_NAME,
+                                           sizeof(PCIQXLDevice), -1, NULL,
+                                           NULL);
+
+    d->id = channel_id;
+    d->state.mode = QXL_MODE_UNDEFINED;
+    if (!channel_id) {
+        qxl_init_modes();
+    }
+
+    register_savevm(QXL_DEV_NAME, channel_id, QXL_SAVE_VERSION, qxl_save, qxl_load, d);
+    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, d);
+
+    pci_conf = (PCIConf *)d->pci_dev.config;
+
+    pci_conf->vendor_ID = QUMRANET_PCI_VENDOR_ID;
+    pci_conf->device_ID = QXL_DEVICE_ID;
+    pci_conf->revision = QXL_REVISION;
+    pci_conf->class_base = PCI_CLASS_DISPLAY;
+    if (QXL_SHARED_VGA_MODE || !d->id) {
+        pci_conf->class_sub = PCI_DISPLAY_SUBCLASS_VGA;
+        pci_conf->class_prog_if = PCI_DISPLAY_VGA_PROGIF;
+    } else {
+        pci_conf->class_sub = PCI_DISPLAY_SUBCLASS_OTHER;
+        pci_conf->class_prog_if = PCI_DISPLAY_OTHER_PROGIF;
+    }
+    pci_conf->interrupt_pin = 1;
+
+    memset(vram, 0xff, vram_size);
+
+    ASSERT(vram_size > QXL_RAM_SIZE);
+    rom_size = init_qxl_rom(d, vram + QXL_RAM_SIZE , vram_size - QXL_RAM_SIZE, &max_fb);
+    rom_size = MAX(rom_size, TARGET_PAGE_SIZE);  
+    rom_size = msb_mask(rom_size * 2 - 1);
+    d->state.rom_offset = vram_offset + QXL_RAM_SIZE;
+    d->state.rom_size = rom_size;
+
+    ASSERT(QXL_RAM_SIZE + rom_size < vram_size);
+    init_qxl_ram(&d->state, vram);
+    d->state.ram_offset = vram_offset;
+    d->state.ram_size = QXL_RAM_SIZE;
+
+    d->state.vram = vram + rom_size + QXL_RAM_SIZE;
+    d->state.vram_offset = vram_offset + rom_size + QXL_RAM_SIZE;
+    d->state.vram_size = msb_mask(vram_size - (QXL_RAM_SIZE + rom_size));
+
+    printf("%s: rom(%p, 0x%x, 0x%x) ram(%p, 0x%x, 0x%x) vram(%p, 0x%lx, 0x%x)\n",
+           __FUNCTION__,
+           d->state.rom,
+           d->state.rom_offset,
+           d->state.rom_size,
+           d->state.ram_start,
+           d->state.ram_offset,
+           d->state.ram_size,
+           d->state.vram,
+           d->state.vram_offset,
+           d->state.vram_size);
+   
+    if (d->state.vram_size < max_fb) {
+        printf("%s: bad vram size, vram %u rom %u max_fb %u\n",
+               __FUNCTION__, vram_size, rom_size, max_fb);
+        exit(-1);
+    }
+
+    pci_register_io_region(&d->pci_dev, QXL_IO_RANGE_INDEX,
+                           msb_mask(QXL_IO_RANGE_SIZE * 2 - 1),
+                           PCI_ADDRESS_SPACE_IO, ioport_map);
+
+    pci_register_io_region(&d->pci_dev, QXL_ROM_RANGE_INDEX,
+                           d->state.rom_size, PCI_ADDRESS_SPACE_MEM,
+                           rom_map);
+
+    pci_register_io_region(&d->pci_dev, QXL_RAM_RANGE_INDEX,
+                           d->state.ram_size, PCI_ADDRESS_SPACE_MEM,
+                           ram_map);
+#ifdef QXL_IO_MEM
+    d->state.qxl_io_memory = cpu_register_io_memory(0, qxl_mem_read, 
+                                                    qxl_mem_write, NULL);
+    ASSERT(d->state.qxl_io_memory > 0);
+    pci_register_io_region(&d->pci_dev, QXL_VRAM_RANGE_INDEX, d->state.vram_size,
+                           PCI_ADDRESS_SPACE_MEM_PREFETCH, vram_map);
+#else
+    pci_register_io_region(&d->pci_dev, QXL_VRAM_RANGE_INDEX, d->state.vram_size,
+                           PCI_ADDRESS_SPACE_MEM_PREFETCH, vram_map);
+#endif
+    d->state.worker = qxl_worker_init((QXLDevRef) d, channel_id++);
+    d->dev_next = dev_list;
+    dev_list = d;
+    d->vga_next = qxl_vga.clients;
+    qxl_vga.clients = d;
+    main_thread = pthread_self();
+    qxl_reset_state(d);
+    if (QXL_SHARED_VGA_MODE || !d->id) {
+        qxl_enter_vga_mode(d);
+        qxl_worker_attach(d->state.worker);
+    } 
+    init_pipe_signaling(d);
+    qemu_register_reset(reset_handler, d);
+}
+
diff --git a/qemu/hw/qxl_dev.h b/qemu/hw/qxl_dev.h
new file mode 100644
index 0000000..b2bde19
--- /dev/null
+++ b/qemu/hw/qxl_dev.h
@@ -0,0 +1,302 @@
+#ifndef _H_QXL_DEV
+#define _H_QXL_DEV
+
+#include "ring.h"
+#include "draw.h"
+
+#ifdef __GNUC__
+#ifdef __i386__
+#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#else
+//mfence
+#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%rsp)": : :"memory")
+#endif
+#define ATTR_PACKED __attribute__ ((__packed__))
+#else
+#pragma pack(push)
+#pragma pack(1)
+#define ATTR_PACKED
+#define mb() __asm {lock add [esp], 0}
+#endif
+
+#define QUMRANET_PCI_VENDOR_ID 0x1af4
+#define QXL_DEVICE_ID 0x0100 /* 0x100-0x1ff reserved for spice */
+#define QXL_REVISION 0x11
+
+#define QXL_ROM_MAGIC (*(UINT32*)"QXRO")
+#define QXL_RAM_MAGIC (*(UINT32*)"QXRA")
+
+enum {
+    QXL_RAM_RANGE_INDEX,
+    QXL_VRAM_RANGE_INDEX,
+    QXL_ROM_RANGE_INDEX,
+    QXL_IO_RANGE_INDEX,
+
+    QXL_PCI_RANGES
+};
+
+enum {
+    QXL_IO_NOTIFY_CMD,
+    QXL_IO_NOTIFY_CURSOR,
+    QXL_IO_UPDATE_AREA,
+    QXL_IO_UPDATE_IRQ,
+    QXL_IO_NOTIFY_OOM,
+    QXL_IO_RESET,
+    QXL_IO_SET_MODE,
+    QXL_IO_LOG,
+
+    QXL_IO_RANGE_SIZE
+};
+
+typedef struct ATTR_PACKED QXLRom {
+    UINT32 magic;
+    UINT32 id;
+    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 ram_header_offset;
+    UINT32 mm_clock;
+} QXLRom;
+
+typedef struct ATTR_PACKED QXLMode {
+    UINT32 id;
+    UINT32 x_res;
+    UINT32 y_res;
+    UINT32 bits;
+    UINT32 stride;
+    UINT32 x_mili;
+    UINT32 y_mili;
+    UINT32 orientation;
+} QXLMode;
+
+typedef struct ATTR_PACKED QXLModes {
+    UINT32 n_modes;
+    QXLMode modes[0];
+} QXLModes;
+
+typedef UINT64 PHYSICAL;
+typedef UINT32 QXLFIXED; //fixed 28.4
+
+enum QXLCmdType {
+    QXL_CMD_NOP,
+    QXL_CMD_DRAW,
+    QXL_CMD_UPDATE,
+    QXL_CMD_CURSOR,
+    QXL_CMD_MESSAGE,
+};
+
+typedef struct ATTR_PACKED QXLCommand {
+    PHYSICAL data;
+    UINT32 type;
+    UINT32 ped;
+} QXLCommand;
+
+
+RING_DECLARE(QXLCommandRing, QXLCommand, 32);
+RING_DECLARE(QXLCursorRing, QXLCommand, 32);
+
+RING_DECLARE(QXLReleaseRing, UINT64, 8);
+
+#define QXL_LOG_BUF_SIZE 4096
+
+#define QXL_INTERRUPT_DISPLAY (1 << 0)
+#define QXL_INTERRUPT_CURSOR (1 << 1)
+
+typedef struct ATTR_PACKED QXLRam {
+    UINT32 magic;
+    UINT32 int_pending;
+    UINT32 int_mask;
+    UINT8 log_buf[QXL_LOG_BUF_SIZE];   
+    QXLCommandRing cmd_ring;
+    QXLCursorRing cursor_ring;
+    QXLReleaseRing release_ring;
+    Rect update_area;
+} QXLRam;
+
+typedef union QXLReleaseInfo{
+    UINT64 id;      // in
+    UINT64 next;    // out
+} QXLReleaseInfo;
+
+typedef struct  ATTR_PACKED QXLDataChunk {
+    UINT32 data_size;
+    PHYSICAL prev_chunk;
+    PHYSICAL next_chunk;
+    UINT8 data[0];
+} QXLDataChunk;
+
+typedef struct ATTR_PACKED QXLMessage {
+    QXLReleaseInfo release_info;
+    UINT8 data[0];
+} QXLMessage;
+
+typedef struct ATTR_PACKED QXLUpdateCmd {
+    QXLReleaseInfo release_info;
+    Rect area;
+    UINT32 update_id;
+} QXLUpdateCmd;
+
+typedef struct ATTR_PACKED QXLCursor {
+    CursorHeader header;
+    UINT32 data_size;
+    QXLDataChunk chunk;
+} QXLCursor;
+
+enum {
+    QXL_CURSOR_SET,
+    QXL_CURSOR_MOVE,
+    QXL_CURSOR_HIDE,
+    QXL_CURSOR_TRAIL,
+};
+
+#define QXL_CURSUR_DEVICE_DATA_SIZE 128
+
+typedef struct ATTR_PACKED QXLCursorCmd {
+    QXLReleaseInfo release_info;
+    UINT8 type;
+    union {
+        struct ATTR_PACKED {
+            Point16 position;
+            UINT8 visible;
+            PHYSICAL shape;
+        } set;
+        struct ATTR_PACKED {
+            UINT16 length;
+            UINT16 frequency;
+        } trail;
+        Point16 position;
+    } u;
+    UINT8 device_data[QXL_CURSUR_DEVICE_DATA_SIZE]; //todo: dynamic size from rom
+} QXLCursorCmd;
+
+enum {
+    QXL_DRAW_NOP,
+    QXL_DRAW_FILL,
+    QXL_DRAW_OPAQUE,
+    QXL_DRAW_COPY,
+    QXL_COPY_BITS,
+    QXL_DRAW_BLEND,
+    QXL_DRAW_BLACKNESS,
+    QXL_DRAW_WHITENESS,
+    QXL_DRAW_INVERS,
+    QXL_DRAW_ROP3,
+    QXL_DRAW_STROKE,
+    QXL_DRAW_TEXT,
+    QXL_DRAW_TRANSPARENT,
+    QXL_DRAW_ALPHA_BLEND,
+};
+
+typedef struct ATTR_PACKED QXLString{
+    UINT32 data_size;
+    UINT16 length;
+    UINT16 flags;
+    QXLDataChunk chunk;
+} QXLString;
+
+typedef struct ATTR_PACKED QXLCopyBits {
+    Point src_pos;
+} QXLCopyBits;
+
+#define QXL_EFFECT_BLEND 0
+#define QXL_EFFECT_OPAQUE 1
+#define QXL_EFFECT_REVERT_ON_DUP 2
+#define QXL_EFFECT_BLACKNESS_ON_DUP 3
+#define QXL_EFFECT_WHITENESS_ON_DUP 4
+#define QXL_EFFECT_NOP_ON_DUP 5
+#define QXL_EFFECT_NOP 6
+#define QXL_EFFECT_OPAQUE_BRUSH 7
+
+typedef struct ATTR_PACKED QXLDrawable {
+    QXLReleaseInfo release_info;
+    UINT8 effect;
+    UINT8 type;
+    UINT16 bitmap_offset;
+    Rect bitmap_area;
+    Rect bbox;
+    Clip clip;
+    UINT32 mm_time;
+    union {
+        Fill fill;
+        Opaque opaque;
+        Copy copy;
+        Transparent transparent;
+        AlphaBlnd alpha_blend;
+        QXLCopyBits copy_bits;
+        Blend blend;
+        Rop3 rop3;
+        Stroke stroke;
+        Text text;
+        Blackness blackness;
+        Invers invers;
+        Whiteness whiteness;
+    } u;
+} QXLDrawable;
+
+typedef struct ATTR_PACKED QXLClipRects{
+    UINT32 num_rects;
+    QXLDataChunk chunk;
+} QXLClipRects;
+
+enum {
+    QXL_PATH_BEGIN = (1 << 0),
+    QXL_PATH_END = (1 << 1),
+    QXL_PATH_CLOSE = (1 << 3),
+    QXL_PATH_BEZIER = (1 << 4), 
+};
+
+typedef struct ATTR_PACKED QXLPath {
+    UINT32 data_size;
+    QXLDataChunk chunk;
+} QXLPath;
+
+enum {
+    QXL_IMAGE_GROUP_DRIVER,
+    QXL_IMAGE_GROUP_DEVICE,
+    QXL_IMAGE_GROUP_RED,
+    QXL_IMAGE_GROUP_DRIVER_DONT_CACHE,
+};
+
+typedef struct ATTR_PACKED QXLImageID{
+    UINT32 group;
+    UINT32 unique;
+} QXLImageID;
+
+enum {
+    QXL_IMAGE_CACHE = (1 << 0),
+};
+
+enum {
+    QXL_BITMAP_DIRECT = (1 << 0),
+    QXL_BITMAP_UNSTABLE = (1 << 1),
+    QXL_BITMAP_TOP_DOWN = (1 << 2), // == BITMAP_TOP_DOWN
+};
+
+#define QXL_SET_IMAGE_ID(image, _group, _unique) {              \
+    UINT64* id_ptr = &(image)->descriptor.id;                   \
+    QXLImageID *image_id = (QXLImageID *)id_ptr;                \
+    image_id->group = _group;                                   \
+    image_id->unique = _unique;                                 \
+}
+
+typedef struct ATTR_PACKED QXLImage {
+    ImageDescriptor descriptor;
+    union { // variable length
+        Bitmap bitmap;
+        PNGData png;
+        QUICData quic;
+    };    
+} QXLImage;
+
+#ifndef __GNUC__
+#pragma pack(pop)
+#endif
+
+#undef ATTR_PACKED
+
+#endif
diff --git a/qemu/hw/qxl_interface.h b/qemu/hw/qxl_interface.h
new file mode 100644
index 0000000..19ee2f9
--- /dev/null
+++ b/qemu/hw/qxl_interface.h
@@ -0,0 +1,60 @@
+#ifndef _H_QXL_INTERFACE
+#define _H_QXL_INTERFACE
+
+#include <stdint.h>
+
+union QXLReleaseInfo;
+struct QXLCommand;
+
+typedef unsigned long QXLWorkerRef;
+typedef unsigned long QXLDevRef;
+
+typedef struct DrawArea{
+    uint8_t *buf;
+    uint32_t size;
+    uint8_t *line_0;
+    uint32_t width;
+    uint32_t heigth;
+    int stride;
+} DrawArea;
+
+typedef struct QXLDevInfo {
+    long phys_delta;
+    unsigned long phys_start;
+    unsigned long phys_end;
+
+    uint32_t x_res;
+    uint32_t y_res;
+    uint32_t bits;
+
+    DrawArea draw_area;
+
+} QXLDevInfo;
+
+void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info);
+int qxl_get_command(QXLDevRef dev_ref, struct QXLCommand *cmd);
+int qxl_has_command(QXLDevRef dev_ref);
+int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommand *cmd);
+const struct Rect *qxl_get_update_area(QXLDevRef dev_ref);
+int qxl_req_cmd_notification(QXLDevRef dev_ref);
+int qxl_req_cursor_notification(QXLDevRef dev_ref);
+void qxl_release_resource(QXLDevRef dev_ref, union QXLReleaseInfo *release_info);
+int qxl_flush_resources(QXLDevRef dev_ref);
+void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id);
+void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size);
+void *qxl_get_save_data(QXLDevRef dev_ref);
+
+
+QXLWorkerRef qxl_worker_init(QXLDevRef dev_ref, int channel_id);
+void qxl_worker_attach(QXLWorkerRef worker_ref);
+void qxl_worker_detach(QXLWorkerRef worker_ref);
+void qxl_worker_wakeup(QXLWorkerRef worker_ref);
+void qxl_worker_oom(QXLWorkerRef worker_ref);
+void qxl_worker_save(QXLWorkerRef worker_ref);
+void qxl_worker_load(QXLWorkerRef worker_ref);
+void qxl_worker_start(QXLWorkerRef worker_ref);
+void qxl_worker_stop(QXLWorkerRef worker_ref);
+void qxl_worker_update_area(QXLWorkerRef worker_ref);
+
+#endif
+
diff --git a/qemu/hw/ring.h b/qemu/hw/ring.h
new file mode 100644
index 0000000..9653f01
--- /dev/null
+++ b/qemu/hw/ring.h
@@ -0,0 +1,104 @@
+#ifndef _H_RING_
+#define _H_RING_
+
+
+#define MSB_MASK4(x)        \
+    (((x) & 0x8) ? 0x8 :    \
+     ((x) & 0x4) ? 0x4 :    \
+     ((x) & 0x2) ? 0x2 :    \
+     ((x) & 0x1) ? 0x1 : 0)
+
+#define MSB_MASK8(x) \
+     (((x) & 0xf0) ? MSB_MASK4((x) >> 4) << 4 : MSB_MASK4(x))
+
+#define MSB_MASK16(x) \
+    (((x) & 0xff00) ? MSB_MASK8((x) >> 8) << 8 : MSB_MASK8(x))
+
+#define MSB_MASK(x) \
+    (((x) & 0xffff0000) ? MSB_MASK16((x) >> 16) << 16 : MSB_MASK16(x))
+
+#define POWER2_ALIGN(x) MSB_MASK((x) * 2 - 1)
+
+
+#define _TOSHIFT_4(x) \
+     (((x) & 0x8) ? 3 :    \
+      ((x) & 0x4) ? 2 :    \
+      ((x) & 0x2) ? 1 : 0)
+
+#define _TOSHIFT_8(x) \
+    (((x) & 0xf0) ? _TOSHIFT_4((x) >> 4) + 4 : _TOSHIFT_4(x))
+
+#define _TOSHIFT_16(x) \
+    (((x) & 0xff00) ? _TOSHIFT_8((x) >> 8) + 8 : _TOSHIFT_8(x))
+
+#define PAWER2_TO_SHIFT(x) \
+    (((x) & 0xffff0000) ? _TOSHIFT_16((x) >> 16) + 16 : _TOSHIFT_16(x))
+
+
+
+#define RING_DECLARE(name, el_type, size)               \
+typedef struct ATTR_PACKED name##_ring_el {             \
+    union {                                             \
+        el_type el;                                     \
+        UINT8 data[POWER2_ALIGN(sizeof(el_type))];      \
+    } ;                                                 \
+} name##_ring_el;                                       \
+                                                        \
+typedef struct ATTR_PACKED name {                       \
+    UINT32 num_items;                                   \
+    UINT32 prod;                                        \
+    UINT32 notify_on_prod;                              \
+    UINT32 cons;                                        \
+    UINT32 notify_on_cons;                              \
+    name##_ring_el items[POWER2_ALIGN(size)];           \
+} name;
+
+
+#define RING_INIT(r)                                                \
+    (r)->num_items = sizeof((r)->items) >>                          \
+                        PAWER2_TO_SHIFT(sizeof((r)->items[0]));     \
+    (r)->prod = (r)->cons = 0;                                      \
+    (r)->notify_on_prod = 1;                                        \
+    (r)->notify_on_cons = 0;
+
+
+#define RING_INDEX_MASK(r) ((r)->num_items - 1)
+
+#define RING_IS_PACKED(r) (sizeof((r)->items[0]) == sizeof((r)->items[0]).el)
+
+#define RING_IS_EMPTY(r) ((r)->cons == (r)->prod)
+
+#define RING_IS_FULL(r) (((r)->prod - (r)->cons) == (r)->num_items)
+
+#define RING_PROD_ITEM(r) (&(r)->items[(r)->prod & RING_INDEX_MASK(r)].el)
+
+#define RING_PROD_WAIT(r, wait)                 \
+    if (((wait) = RING_IS_FULL(r))) {           \
+        (r)->notify_on_cons = (r)->cons + 1;    \
+        mb();	                                \
+        (wait) = RING_IS_FULL(r);               \
+    }
+
+#define RING_PUSH(r, notify)                    \
+    (r)->prod++;                                \
+    mb();                                       \
+    (notify) = (r)->prod == (r)->notify_on_prod;
+
+
+#define RING_CONS_ITEM(r) (&(r)->items[(r)->cons & RING_INDEX_MASK(r)].el)
+
+#define RING_CONS_WAIT(r, wait)                 \
+    if (((wait) = RING_IS_EMPTY(r))) {          \
+        (r)->notify_on_prod = (r)->prod + 1;    \
+        mb();                                   \
+        (wait) = RING_IS_EMPTY(r);              \
+    }
+
+#define RING_POP(r, notify)                         \
+    (r)->cons++;                                    \
+    mb();                                           \
+    (notify) = (r)->cons == (r)->notify_on_cons;
+
+
+
+#endif
-- 
1.6.1