summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/display/cirrus_vga.c106
-rw-r--r--hw/display/cirrus_vga_rop.h191
-rw-r--r--hw/display/cirrus_vga_rop2.h125
-rw-r--r--include/hw/compat.h8
-rw-r--r--include/ui/console.h7
-rw-r--r--ui/console.c28
-rw-r--r--ui/vnc.c100
7 files changed, 259 insertions, 306 deletions
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index b9e7cb1df1..afc290ab91 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -178,11 +178,12 @@
 
 struct CirrusVGAState;
 typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
-                                     uint8_t * dst, const uint8_t * src,
+                                     uint32_t dstaddr, uint32_t srcaddr,
 				     int dstpitch, int srcpitch,
 				     int bltwidth, int bltheight);
 typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
-                              uint8_t *dst, int dst_pitch, int width, int height);
+                              uint32_t dstaddr, int dst_pitch,
+                              int width, int height);
 
 typedef struct CirrusVGAState {
     VGACommonState vga;
@@ -205,6 +206,7 @@ typedef struct CirrusVGAState {
     uint32_t cirrus_bank_base[2];
     uint32_t cirrus_bank_limit[2];
     uint8_t cirrus_hidden_palette[48];
+    bool enable_blitter;
     int cirrus_blt_pixelwidth;
     int cirrus_blt_width;
     int cirrus_blt_height;
@@ -320,18 +322,57 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
 }
 
 static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
-                                  uint8_t *dst,const uint8_t *src,
+                                  uint32_t dstaddr, uint32_t srcaddr,
                                   int dstpitch,int srcpitch,
                                   int bltwidth,int bltheight)
 {
 }
 
 static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
-                                   uint8_t *dst,
+                                   uint32_t dstaddr,
                                    int dstpitch, int bltwidth,int bltheight)
 {
 }
 
+static inline uint8_t cirrus_src(CirrusVGAState *s, uint32_t srcaddr)
+{
+    if (s->cirrus_srccounter) {
+        /* cputovideo */
+        return s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1)];
+    } else {
+        /* videotovideo */
+        return s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask];
+    }
+}
+
+static inline uint16_t cirrus_src16(CirrusVGAState *s, uint32_t srcaddr)
+{
+    uint16_t *src;
+
+    if (s->cirrus_srccounter) {
+        /* cputovideo */
+        src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~1];
+    } else {
+        /* videotovideo */
+        src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~1];
+    }
+    return *src;
+}
+
+static inline uint32_t cirrus_src32(CirrusVGAState *s, uint32_t srcaddr)
+{
+    uint32_t *src;
+
+    if (s->cirrus_srccounter) {
+        /* cputovideo */
+        src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~3];
+    } else {
+        /* videotovideo */
+        src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~3];
+    }
+    return *src;
+}
+
 #define ROP_NAME 0
 #define ROP_FN(d, s) 0
 #include "cirrus_vga_rop.h"
@@ -666,21 +707,18 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
     }
 
     for (y = 0; y < lines; y++) {
-	off_cur = off_begin;
-	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
+        off_cur = off_begin;
+        off_cur_end = ((off_cur + bytesperline - 1) & s->cirrus_addr_mask) + 1;
         assert(off_cur_end >= off_cur);
         memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
-	off_begin += off_pitch;
+        off_begin += off_pitch;
     }
 }
 
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s)
 {
     uint32_t patternsize;
-    uint8_t *dst;
-    uint8_t *src;
-
-    dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
+    bool videosrc = !s->cirrus_srccounter;
 
     if (videosrc) {
         switch (s->vga.get_bpp(&s->vga)) {
@@ -701,16 +739,14 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
         if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
             return 0;
         }
-        src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
-    } else {
-        src = s->cirrus_bltbuf;
     }
 
     if (blit_is_unsafe(s, true)) {
         return 0;
     }
 
-    (*s->cirrus_rop) (s, dst, src,
+    (*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
+                      videosrc ? s->cirrus_blt_srcaddr : 0,
                       s->cirrus_blt_dstpitch, 0,
                       s->cirrus_blt_width, s->cirrus_blt_height);
     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
@@ -729,7 +765,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
         return 0;
     }
     rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-    rop_func(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
+    rop_func(s, s->cirrus_blt_dstaddr,
              s->cirrus_blt_dstpitch,
              s->cirrus_blt_width, s->cirrus_blt_height);
     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
@@ -747,7 +783,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
 
 static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
 {
-    return cirrus_bitblt_common_patterncopy(s, true);
+    return cirrus_bitblt_common_patterncopy(s);
 }
 
 static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
@@ -796,21 +832,15 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
         }
     }
 
-    /* we have to flush all pending changes so that the copy
-       is generated at the appropriate moment in time */
-    if (notify)
-        graphic_hw_update(s->vga.con);
-
-    (*s->cirrus_rop) (s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
-                      s->vga.vram_ptr + s->cirrus_blt_srcaddr,
+    (*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
+                      s->cirrus_blt_srcaddr,
 		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
 		      s->cirrus_blt_width, s->cirrus_blt_height);
 
     if (notify) {
-        qemu_console_copy(s->vga.con,
-			  sx, sy, dx, dy,
-			  s->cirrus_blt_width / depth,
-			  s->cirrus_blt_height);
+        dpy_gfx_update(s->vga.con, dx, dy,
+                       s->cirrus_blt_width / depth,
+                       s->cirrus_blt_height);
     }
 
     /* we don't have to notify the display that this portion has
@@ -846,15 +876,15 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
 
     if (s->cirrus_srccounter > 0) {
         if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
-            cirrus_bitblt_common_patterncopy(s, false);
+            cirrus_bitblt_common_patterncopy(s);
         the_end:
             s->cirrus_srccounter = 0;
             cirrus_bitblt_reset(s);
         } else {
             /* at least one scan line */
             do {
-                (*s->cirrus_rop)(s, s->vga.vram_ptr + s->cirrus_blt_dstaddr,
-                                  s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
+                (*s->cirrus_rop)(s, s->cirrus_blt_dstaddr,
+                                 0, 0, 0, s->cirrus_blt_width, 1);
                 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
                                          s->cirrus_blt_width, 1);
                 s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
@@ -966,6 +996,10 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
 {
     uint8_t blt_rop;
 
+    if (!s->enable_blitter) {
+        goto bitblt_ignore;
+    }
+
     s->vga.gr[0x31] |= CIRRUS_BLT_BUSY;
 
     s->cirrus_blt_width = (s->vga.gr[0x20] | (s->vga.gr[0x21] << 8)) + 1;
@@ -3029,7 +3063,9 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
 
 static Property isa_cirrus_vga_properties[] = {
     DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
-                       cirrus_vga.vga.vram_size_mb, 8),
+                       cirrus_vga.vga.vram_size_mb, 4),
+    DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState,
+                       cirrus_vga.enable_blitter, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -3098,7 +3134,9 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp)
 
 static Property pci_vga_cirrus_properties[] = {
     DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
-                       cirrus_vga.vga.vram_size_mb, 8),
+                       cirrus_vga.vga.vram_size_mb, 4),
+    DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState,
+                     cirrus_vga.enable_blitter, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/display/cirrus_vga_rop.h b/hw/display/cirrus_vga_rop.h
index 0925a009fe..c61a677353 100644
--- a/hw/display/cirrus_vga_rop.h
+++ b/hw/display/cirrus_vga_rop.h
@@ -22,31 +22,65 @@
  * THE SOFTWARE.
  */
 
-static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
+static inline void glue(rop_8_, ROP_NAME)(CirrusVGAState *s,
+                                          uint32_t dstaddr, uint8_t src)
 {
+    uint8_t *dst = &s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask];
     *dst = ROP_FN(*dst, src);
 }
 
-static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
+static inline void glue(rop_tr_8_, ROP_NAME)(CirrusVGAState *s,
+                                             uint32_t dstaddr, uint8_t src,
+                                             uint8_t transp)
 {
+    uint8_t *dst = &s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask];
+    uint8_t pixel = ROP_FN(*dst, src);
+    if (pixel != transp) {
+        *dst = pixel;
+    }
+}
+
+static inline void glue(rop_16_, ROP_NAME)(CirrusVGAState *s,
+                                           uint32_t dstaddr, uint16_t src)
+{
+    uint16_t *dst = (uint16_t *)
+        (&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~1]);
     *dst = ROP_FN(*dst, src);
 }
 
-static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
+static inline void glue(rop_tr_16_, ROP_NAME)(CirrusVGAState *s,
+                                              uint32_t dstaddr, uint16_t src,
+                                              uint16_t transp)
 {
+    uint16_t *dst = (uint16_t *)
+        (&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~1]);
+    uint16_t pixel = ROP_FN(*dst, src);
+    if (pixel != transp) {
+        *dst = pixel;
+    }
+}
+
+static inline void glue(rop_32_, ROP_NAME)(CirrusVGAState *s,
+                                           uint32_t dstaddr, uint32_t src)
+{
+    uint32_t *dst = (uint32_t *)
+        (&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~3]);
     *dst = ROP_FN(*dst, src);
 }
 
-#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
-#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
-#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
+#define ROP_OP(st, d, s)           glue(rop_8_, ROP_NAME)(st, d, s)
+#define ROP_OP_TR(st, d, s, t)     glue(rop_tr_8_, ROP_NAME)(st, d, s, t)
+#define ROP_OP_16(st, d, s)        glue(rop_16_, ROP_NAME)(st, d, s)
+#define ROP_OP_TR_16(st, d, s, t)  glue(rop_tr_16_, ROP_NAME)(st, d, s, t)
+#define ROP_OP_32(st, d, s)        glue(rop_32_, ROP_NAME)(st, d, s)
 #undef ROP_FN
 
 static void
 glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
-                             uint8_t *dst,const uint8_t *src,
-                             int dstpitch,int srcpitch,
-                             int bltwidth,int bltheight)
+                                       uint32_t dstaddr,
+                                       uint32_t srcaddr,
+                                       int dstpitch, int srcpitch,
+                                       int bltwidth, int bltheight)
 {
     int x,y;
     dstpitch -= bltwidth;
@@ -58,134 +92,139 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
 
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-            ROP_OP(dst, *src);
-            dst++;
-            src++;
+            ROP_OP(s, dstaddr, cirrus_src(s, srcaddr));
+            dstaddr++;
+            srcaddr++;
         }
-        dst += dstpitch;
-        src += srcpitch;
+        dstaddr += dstpitch;
+        srcaddr += srcpitch;
     }
 }
 
 static void
 glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
-                                        uint8_t *dst,const uint8_t *src,
-                                        int dstpitch,int srcpitch,
-                                        int bltwidth,int bltheight)
+                                        uint32_t dstaddr,
+                                        uint32_t srcaddr,
+                                        int dstpitch, int srcpitch,
+                                        int bltwidth, int bltheight)
 {
     int x,y;
     dstpitch += bltwidth;
     srcpitch += bltwidth;
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-            ROP_OP(dst, *src);
-            dst--;
-            src--;
+            ROP_OP(s, dstaddr, cirrus_src(s, srcaddr));
+            dstaddr--;
+            srcaddr--;
         }
-        dst += dstpitch;
-        src += srcpitch;
+        dstaddr += dstpitch;
+        srcaddr += srcpitch;
     }
 }
 
 static void
 glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
-						       uint8_t *dst,const uint8_t *src,
-						       int dstpitch,int srcpitch,
-						       int bltwidth,int bltheight)
+                                                       uint32_t dstaddr,
+                                                       uint32_t srcaddr,
+                                                       int dstpitch,
+                                                       int srcpitch,
+                                                       int bltwidth,
+                                                       int bltheight)
 {
     int x,y;
-    uint8_t p;
+    uint8_t transp = s->vga.gr[0x34];
     dstpitch -= bltwidth;
     srcpitch -= bltwidth;
+
+    if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
+        return;
+    }
+
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-	    p = *dst;
-            ROP_OP(&p, *src);
-	    if (p != s->vga.gr[0x34]) *dst = p;
-            dst++;
-            src++;
+            ROP_OP_TR(s, dstaddr, cirrus_src(s, srcaddr), transp);
+            dstaddr++;
+            srcaddr++;
         }
-        dst += dstpitch;
-        src += srcpitch;
+        dstaddr += dstpitch;
+        srcaddr += srcpitch;
     }
 }
 
 static void
 glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
-							uint8_t *dst,const uint8_t *src,
-							int dstpitch,int srcpitch,
-							int bltwidth,int bltheight)
+                                                        uint32_t dstaddr,
+                                                        uint32_t srcaddr,
+                                                        int dstpitch,
+                                                        int srcpitch,
+                                                        int bltwidth,
+                                                        int bltheight)
 {
     int x,y;
-    uint8_t p;
+    uint8_t transp = s->vga.gr[0x34];
     dstpitch += bltwidth;
     srcpitch += bltwidth;
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-	    p = *dst;
-            ROP_OP(&p, *src);
-	    if (p != s->vga.gr[0x34]) *dst = p;
-            dst--;
-            src--;
+            ROP_OP_TR(s, dstaddr, cirrus_src(s, srcaddr), transp);
+            dstaddr--;
+            srcaddr--;
         }
-        dst += dstpitch;
-        src += srcpitch;
+        dstaddr += dstpitch;
+        srcaddr += srcpitch;
     }
 }
 
 static void
 glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
-							uint8_t *dst,const uint8_t *src,
-							int dstpitch,int srcpitch,
-							int bltwidth,int bltheight)
+                                                        uint32_t dstaddr,
+                                                        uint32_t srcaddr,
+                                                        int dstpitch,
+                                                        int srcpitch,
+                                                        int bltwidth,
+                                                        int bltheight)
 {
     int x,y;
-    uint8_t p1, p2;
+    uint16_t transp = s->vga.gr[0x34] | (uint16_t)s->vga.gr[0x35] << 8;
     dstpitch -= bltwidth;
     srcpitch -= bltwidth;
+
+    if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
+        return;
+    }
+
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x+=2) {
-	    p1 = *dst;
-	    p2 = *(dst+1);
-            ROP_OP(&p1, *src);
-            ROP_OP(&p2, *(src + 1));
-	    if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
-		*dst = p1;
-		*(dst+1) = p2;
-	    }
-            dst+=2;
-            src+=2;
+            ROP_OP_TR_16(s, dstaddr, cirrus_src16(s, srcaddr), transp);
+            dstaddr += 2;
+            srcaddr += 2;
         }
-        dst += dstpitch;
-        src += srcpitch;
+        dstaddr += dstpitch;
+        srcaddr += srcpitch;
     }
 }
 
 static void
 glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
-							 uint8_t *dst,const uint8_t *src,
-							 int dstpitch,int srcpitch,
-							 int bltwidth,int bltheight)
+                                                         uint32_t dstaddr,
+                                                         uint32_t srcaddr,
+                                                         int dstpitch,
+                                                         int srcpitch,
+                                                         int bltwidth,
+                                                         int bltheight)
 {
     int x,y;
-    uint8_t p1, p2;
+    uint16_t transp = s->vga.gr[0x34] | (uint16_t)s->vga.gr[0x35] << 8;
     dstpitch += bltwidth;
     srcpitch += bltwidth;
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x+=2) {
-	    p1 = *(dst-1);
-	    p2 = *dst;
-            ROP_OP(&p1, *(src - 1));
-            ROP_OP(&p2, *src);
-	    if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
-		*(dst-1) = p1;
-		*dst = p2;
-	    }
-            dst-=2;
-            src-=2;
+            ROP_OP_TR_16(s, dstaddr, cirrus_src16(s, srcaddr), transp);
+            dstaddr -= 2;
+            srcaddr -= 2;
         }
-        dst += dstpitch;
-        src += srcpitch;
+        dstaddr += dstpitch;
+        srcaddr += srcpitch;
     }
 }
 
diff --git a/hw/display/cirrus_vga_rop2.h b/hw/display/cirrus_vga_rop2.h
index d28bcc6f25..b86bcd6e09 100644
--- a/hw/display/cirrus_vga_rop2.h
+++ b/hw/display/cirrus_vga_rop2.h
@@ -23,30 +23,32 @@
  */
 
 #if DEPTH == 8
-#define PUTPIXEL()    ROP_OP(&d[0], col)
+#define PUTPIXEL(s, a, c)    ROP_OP(s, a, c)
 #elif DEPTH == 16
-#define PUTPIXEL()    ROP_OP_16((uint16_t *)&d[0], col)
+#define PUTPIXEL(s, a, c)    ROP_OP_16(s, a, c)
 #elif DEPTH == 24
-#define PUTPIXEL()    ROP_OP(&d[0], col);        \
-                      ROP_OP(&d[1], (col >> 8)); \
-                      ROP_OP(&d[2], (col >> 16))
+#define PUTPIXEL(s, a, c)    do {          \
+        ROP_OP(s, a,     c);               \
+        ROP_OP(s, a + 1, (col >> 8));      \
+        ROP_OP(s, a + 2, (col >> 16));     \
+    } while (0)
 #elif DEPTH == 32
-#define PUTPIXEL()    ROP_OP_32(((uint32_t *)&d[0]), col)
+#define PUTPIXEL(s, a, c)    ROP_OP_32(s, a, c)
 #else
 #error unsupported DEPTH
 #endif
 
 static void
 glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
+     (CirrusVGAState *s, uint32_t dstaddr,
+      uint32_t srcaddr,
       int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
-    uint8_t *d;
+    uint32_t addr;
     int x, y, pattern_y, pattern_pitch, pattern_x;
     unsigned int col;
-    const uint8_t *src1;
+    uint32_t src1addr;
 #if DEPTH == 24
     int skipleft = s->vga.gr[0x2f] & 0x1f;
 #else
@@ -63,42 +65,44 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
     pattern_y = s->cirrus_blt_srcaddr & 7;
     for(y = 0; y < bltheight; y++) {
         pattern_x = skipleft;
-        d = dst + skipleft;
-        src1 = src + pattern_y * pattern_pitch;
+        addr = dstaddr + skipleft;
+        src1addr = srcaddr + pattern_y * pattern_pitch;
         for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
 #if DEPTH == 8
-            col = src1[pattern_x];
+            col = cirrus_src(s, src1addr + pattern_x);
             pattern_x = (pattern_x + 1) & 7;
 #elif DEPTH == 16
-            col = ((uint16_t *)(src1 + pattern_x))[0];
+            col = cirrus_src16(s, src1addr + pattern_x);
             pattern_x = (pattern_x + 2) & 15;
 #elif DEPTH == 24
             {
-                const uint8_t *src2 = src1 + pattern_x * 3;
-                col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
+                uint32_t src2addr = src1addr + pattern_x * 3;
+                col = cirrus_src(s, src2addr) |
+                    (cirrus_src(s, src2addr + 1) << 8) |
+                    (cirrus_src(s, src2addr + 2) << 16);
                 pattern_x = (pattern_x + 1) & 7;
             }
 #else
-            col = ((uint32_t *)(src1 + pattern_x))[0];
+            col = cirrus_src32(s, src1addr + pattern_x);
             pattern_x = (pattern_x + 4) & 31;
 #endif
-            PUTPIXEL();
-            d += (DEPTH / 8);
+            PUTPIXEL(s, addr, col);
+            addr += (DEPTH / 8);
         }
         pattern_y = (pattern_y + 1) & 7;
-        dst += dstpitch;
+        dstaddr += dstpitch;
     }
 }
 
 /* NOTE: srcpitch is ignored */
 static void
 glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
+     (CirrusVGAState *s, uint32_t dstaddr,
+      uint32_t srcaddr,
       int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
-    uint8_t *d;
+    uint32_t addr;
     int x, y;
     unsigned bits, bits_xor;
     unsigned int col;
@@ -122,33 +126,33 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
 
     for(y = 0; y < bltheight; y++) {
         bitmask = 0x80 >> srcskipleft;
-        bits = *src++ ^ bits_xor;
-        d = dst + dstskipleft;
+        bits = cirrus_src(s, srcaddr++) ^ bits_xor;
+        addr = dstaddr + dstskipleft;
         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
             if ((bitmask & 0xff) == 0) {
                 bitmask = 0x80;
-                bits = *src++ ^ bits_xor;
+                bits = cirrus_src(s, srcaddr++) ^ bits_xor;
             }
             index = (bits & bitmask);
             if (index) {
-                PUTPIXEL();
+                PUTPIXEL(s, addr, col);
             }
-            d += (DEPTH / 8);
+            addr += (DEPTH / 8);
             bitmask >>= 1;
         }
-        dst += dstpitch;
+        dstaddr += dstpitch;
     }
 }
 
 static void
 glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
+     (CirrusVGAState *s, uint32_t dstaddr,
+      uint32_t srcaddr,
       int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint32_t colors[2];
-    uint8_t *d;
+    uint32_t addr;
     int x, y;
     unsigned bits;
     unsigned int col;
@@ -160,30 +164,30 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
     colors[1] = s->cirrus_blt_fgcol;
     for(y = 0; y < bltheight; y++) {
         bitmask = 0x80 >> srcskipleft;
-        bits = *src++;
-        d = dst + dstskipleft;
+        bits = cirrus_src(s, srcaddr++);
+        addr = dstaddr + dstskipleft;
         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
             if ((bitmask & 0xff) == 0) {
                 bitmask = 0x80;
-                bits = *src++;
+                bits = cirrus_src(s, srcaddr++);
             }
             col = colors[!!(bits & bitmask)];
-            PUTPIXEL();
-            d += (DEPTH / 8);
+            PUTPIXEL(s, addr, col);
+            addr += (DEPTH / 8);
             bitmask >>= 1;
         }
-        dst += dstpitch;
+        dstaddr += dstpitch;
     }
 }
 
 static void
 glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
+     (CirrusVGAState *s, uint32_t dstaddr,
+      uint32_t srcaddr,
       int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
-    uint8_t *d;
+    uint32_t addr;
     int x, y, bitpos, pattern_y;
     unsigned int bits, bits_xor;
     unsigned int col;
@@ -205,30 +209,30 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
     pattern_y = s->cirrus_blt_srcaddr & 7;
 
     for(y = 0; y < bltheight; y++) {
-        bits = src[pattern_y] ^ bits_xor;
+        bits = cirrus_src(s, srcaddr + pattern_y) ^ bits_xor;
         bitpos = 7 - srcskipleft;
-        d = dst + dstskipleft;
+        addr = dstaddr + dstskipleft;
         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
             if ((bits >> bitpos) & 1) {
-                PUTPIXEL();
+                PUTPIXEL(s, addr, col);
             }
-            d += (DEPTH / 8);
+            addr += (DEPTH / 8);
             bitpos = (bitpos - 1) & 7;
         }
         pattern_y = (pattern_y + 1) & 7;
-        dst += dstpitch;
+        dstaddr += dstpitch;
     }
 }
 
 static void
 glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
+     (CirrusVGAState *s, uint32_t dstaddr,
+      uint32_t srcaddr,
       int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint32_t colors[2];
-    uint8_t *d;
+    uint32_t addr;
     int x, y, bitpos, pattern_y;
     unsigned int bits;
     unsigned int col;
@@ -240,40 +244,39 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
     pattern_y = s->cirrus_blt_srcaddr & 7;
 
     for(y = 0; y < bltheight; y++) {
-        bits = src[pattern_y];
+        bits = cirrus_src(s, srcaddr + pattern_y);
         bitpos = 7 - srcskipleft;
-        d = dst + dstskipleft;
+        addr = dstaddr + dstskipleft;
         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
             col = colors[(bits >> bitpos) & 1];
-            PUTPIXEL();
-            d += (DEPTH / 8);
+            PUTPIXEL(s, addr, col);
+            addr += (DEPTH / 8);
             bitpos = (bitpos - 1) & 7;
         }
         pattern_y = (pattern_y + 1) & 7;
-        dst += dstpitch;
+        dstaddr += dstpitch;
     }
 }
 
 static void
 glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
      (CirrusVGAState *s,
-      uint8_t *dst, int dst_pitch,
+      uint32_t dstaddr, int dst_pitch,
       int width, int height)
 {
-    uint8_t *d, *d1;
+    uint32_t addr;
     uint32_t col;
     int x, y;
 
     col = s->cirrus_blt_fgcol;
 
-    d1 = dst;
     for(y = 0; y < height; y++) {
-        d = d1;
+        addr = dstaddr;
         for(x = 0; x < width; x += (DEPTH / 8)) {
-            PUTPIXEL();
-            d += (DEPTH / 8);
+            PUTPIXEL(s, addr, col);
+            addr += (DEPTH / 8);
         }
-        d1 += dst_pitch;
+        dstaddr += dst_pitch;
     }
 }
 
diff --git a/include/hw/compat.h b/include/hw/compat.h
index 90606f9fdb..fc8c3e0600 100644
--- a/include/hw/compat.h
+++ b/include/hw/compat.h
@@ -34,6 +34,14 @@
         .driver   = "virtio-pci",\
         .property = "x-pcie-pm-init",\
         .value    = "off",\
+    },{\
+        .driver   = "cirrus-vga",\
+        .property = "vgamem_mb",\
+        .value    = "8",\
+    },{\
+        .driver   = "isa-cirrus-vga",\
+        .property = "vgamem_mb",\
+        .value    = "8",\
     },
 
 #define HW_COMPAT_2_7 \
diff --git a/include/ui/console.h b/include/ui/console.h
index ac2895ca93..d759338816 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -189,9 +189,6 @@ typedef struct DisplayChangeListenerOps {
                            int x, int y, int w, int h);
     void (*dpy_gfx_switch)(DisplayChangeListener *dcl,
                            struct DisplaySurface *new_surface);
-    void (*dpy_gfx_copy)(DisplayChangeListener *dcl,
-                         int src_x, int src_y,
-                         int dst_x, int dst_y, int w, int h);
     bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl,
                                  pixman_format_code_t format);
 
@@ -277,8 +274,6 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
 void dpy_gfx_replace_surface(QemuConsole *con,
                              DisplaySurface *surface);
-void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
-                  int dst_x, int dst_y, int w, int h);
 void dpy_text_cursor(QemuConsole *con, int x, int y);
 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h);
 void dpy_text_resize(QemuConsole *con, int w, int h);
@@ -411,8 +406,6 @@ void qemu_console_set_window_id(QemuConsole *con, int window_id);
 
 void console_select(unsigned int index);
 void qemu_console_resize(QemuConsole *con, int width, int height);
-void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
-                       int dst_x, int dst_y, int w, int h);
 DisplaySurface *qemu_console_surface(QemuConsole *con);
 
 /* console-gl.c */
diff --git a/ui/console.c b/ui/console.c
index d1ff7504ec..4c70d8bfda 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1586,27 +1586,6 @@ static void dpy_refresh(DisplayState *s)
     }
 }
 
-void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
-                  int dst_x, int dst_y, int w, int h)
-{
-    DisplayState *s = con->ds;
-    DisplayChangeListener *dcl;
-
-    if (!qemu_console_is_visible(con)) {
-        return;
-    }
-    QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (con != (dcl->con ? dcl->con : active_console)) {
-            continue;
-        }
-        if (dcl->ops->dpy_gfx_copy) {
-            dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
-        } else { /* TODO */
-            dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
-        }
-    }
-}
-
 void dpy_text_cursor(QemuConsole *con, int x, int y)
 {
     DisplayState *s = con->ds;
@@ -2138,13 +2117,6 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
     dpy_gfx_replace_surface(s, surface);
 }
 
-void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
-                       int dst_x, int dst_y, int w, int h)
-{
-    assert(con->console_type == GRAPHIC_CONSOLE);
-    dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
-}
-
 DisplaySurface *qemu_console_surface(QemuConsole *console)
 {
     return console->surface;
diff --git a/ui/vnc.c b/ui/vnc.c
index 51f4b30959..8bfb1e0685 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -894,105 +894,6 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
     return n;
 }
 
-static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
-{
-    /* send bitblit op to the vnc client */
-    vnc_lock_output(vs);
-    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-    vnc_write_u8(vs, 0);
-    vnc_write_u16(vs, 1); /* number of rects */
-    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
-    vnc_write_u16(vs, src_x);
-    vnc_write_u16(vs, src_y);
-    vnc_unlock_output(vs);
-    vnc_flush(vs);
-}
-
-static void vnc_dpy_copy(DisplayChangeListener *dcl,
-                         int src_x, int src_y,
-                         int dst_x, int dst_y, int w, int h)
-{
-    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
-    VncState *vs, *vn;
-    uint8_t *src_row;
-    uint8_t *dst_row;
-    int i, x, y, pitch, inc, w_lim, s;
-    int cmp_bytes;
-
-    if (!vd->server) {
-        /* no client connected */
-        return;
-    }
-
-    vnc_refresh_server_surface(vd);
-    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
-        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-            vs->force_update = 1;
-            vnc_update_client(vs, 1, true);
-            /* vs might be free()ed here */
-        }
-    }
-
-    if (!vd->server) {
-        /* no client connected */
-        return;
-    }
-    /* do bitblit op on the local surface too */
-    pitch = vnc_server_fb_stride(vd);
-    src_row = vnc_server_fb_ptr(vd, src_x, src_y);
-    dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
-    y = dst_y;
-    inc = 1;
-    if (dst_y > src_y) {
-        /* copy backwards */
-        src_row += pitch * (h-1);
-        dst_row += pitch * (h-1);
-        pitch = -pitch;
-        y = dst_y + h - 1;
-        inc = -1;
-    }
-    w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
-    if (w_lim < 0) {
-        w_lim = w;
-    } else {
-        w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
-    }
-    for (i = 0; i < h; i++) {
-        for (x = 0; x <= w_lim;
-                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
-            if (x == w_lim) {
-                if ((s = w - w_lim) == 0)
-                    break;
-            } else if (!x) {
-                s = (VNC_DIRTY_PIXELS_PER_BIT -
-                    (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
-                s = MIN(s, w_lim);
-            } else {
-                s = VNC_DIRTY_PIXELS_PER_BIT;
-            }
-            cmp_bytes = s * VNC_SERVER_FB_BYTES;
-            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
-                continue;
-            memmove(dst_row, src_row, cmp_bytes);
-            QTAILQ_FOREACH(vs, &vd->clients, next) {
-                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-                    set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
-                            vs->dirty[y]);
-                }
-            }
-        }
-        src_row += pitch - w * VNC_SERVER_FB_BYTES;
-        dst_row += pitch - w * VNC_SERVER_FB_BYTES;
-        y += inc;
-    }
-
-    QTAILQ_FOREACH(vs, &vd->clients, next) {
-        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
-            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
-        }
-    }
-}
-
 static void vnc_mouse_set(DisplayChangeListener *dcl,
                           int x, int y, int visible)
 {
@@ -3120,7 +3021,6 @@ static gboolean vnc_listen_io(QIOChannel *ioc,
 static const DisplayChangeListenerOps dcl_ops = {
     .dpy_name             = "vnc",
     .dpy_refresh          = vnc_refresh,
-    .dpy_gfx_copy         = vnc_dpy_copy,
     .dpy_gfx_update       = vnc_dpy_update,
     .dpy_gfx_switch       = vnc_dpy_switch,
     .dpy_gfx_check_format = qemu_pixman_check_format,