]> xenbits.xensource.com Git - people/pauldu/demu.git/commitdiff
Basic VRAM scraping console. No keyboard or mouse as yet.
authorPaul Durrant <paul.durrant@citrix.com>
Mon, 10 Feb 2014 10:57:25 +0000 (10:57 +0000)
committerPaul Durrant <paul.durrant@citrix.com>
Mon, 10 Feb 2014 10:57:25 +0000 (10:57 +0000)
This is still totally unoptimized. VRAM is emulates and there is no
dirty memory tracking so it's all very very slow. I've also not trimmed out
all the unnecessary pixel format translation abstraction code.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
15 files changed:
Makefile
debug.h
demu.c
demu.h
device.c
device.h
mapcache.c
mapcache.h
pci.c
pci.h
surface.c [new file with mode: 0644]
surface.h [new file with mode: 0644]
template.h [new file with mode: 0644]
vga.h
vgabios-stdvga.bin [new file with mode: 0644]

index b690768c9101b57f8cb4e49553156462b515f9a7..016f3fe4a997c9ea00490694d76d6e3dee712f9d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ TARGET = demu
 OBJS :=        device.o \
        pci.o \
        mapcache.o \
+       surface.o \
        demu.o
 
 CFLAGS  = -I$(shell pwd)/include
@@ -15,7 +16,7 @@ ifeq ($(shell uname),Linux)
 LDLIBS := -lutil -lrt
 endif
 
-LDLIBS += -lxenctrl -lvncserver
+LDLIBS += -lxenctrl -lvncserver  -lnsl -lpthread -lz -ljpeg -lresolv -L/lib/x86_64-linux-gnu -lgcrypt -lgnutls
 
 # Get gcc to generate the dependencies for us.
 CFLAGS   += -Wp,-MD,$(@D)/.$(@F).d
diff --git a/debug.h b/debug.h
index 816d778a912b9c0783891ced0d34b4c1e843b8fb..f6300c468790852ad5cb6d7973b77bd2427c4daf 100644 (file)
--- a/debug.h
+++ b/debug.h
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
diff --git a/demu.c b/demu.c
index dc148757ee6be104298c579f276ef91f3564eda2..246326a6ecce38a4dd88ba5c569c316616416d4c 100644 (file)
--- a/demu.c
+++ b/demu.c
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
 #include "mapcache.h"
 #include "device.h"
 #include "pci.h"
+#include "surface.h"
 #include "demu.h"
 
 #define mb() asm volatile ("" : : : "memory")
 
+#define __min(_x, _y) (((_x) <= (_y)) ? (_x) : (_y))
+#define __max(_x, _y) (((_x) > (_y)) ? (_x) : (_y))
+
+#define DEMU_VRAM_SIZE  0x01000000
+#define DEMU_ROM_FILE   "vgabios-stdvga.bin"
+
 enum {
     DEMU_OPT_DOMAIN,
     DEMU_OPT_DEVICE,
+    DEMU_OPT_ROM,
     DEMU_NR_OPTS
     };
 
 static struct option demu_option[] = {
     {"domain", 1, NULL, 0},
     {"device", 1, NULL, 0},
+    {"rom", 1, NULL, 0},
     {NULL, 0, NULL, 0}
 };
 
 static const char *demu_option_text[] = {
     "<domid>",
     "<device>",
+    "<rom image>",
     NULL
 };
 
@@ -119,6 +129,8 @@ typedef enum {
     DEMU_SEQ_PORTS_BOUND,
     DEMU_SEQ_BUF_PORT_BOUND,
     DEMU_SEQ_VNC_INITIALIZED,
+    DEMU_SEQ_DEVICE_INITIALIZED,
+    DEMU_SEQ_SURFACE_INITIALIZED,
     DEMU_SEQ_INITIALIZED,
     DEMU_NR_SEQS
 } demu_seq_t;
@@ -145,6 +157,9 @@ typedef struct demu_state {
     buffered_iopage_t   *buffered_iopage;
     evtchn_port_t       buf_ioreq_port;
     evtchn_port_t       buf_ioreq_local_port;
+    uint32_t            width;
+    uint32_t            height;
+    uint32_t            depth;
     uint8_t             *default_framebuffer;
     uint8_t             *framebuffer;
     rfbScreenInfoPtr    screen;
@@ -256,7 +271,6 @@ demu_deregister_space(demu_space_t **headp, uint64_t start)
         }
         spacep = &(space->next);
     }
-    assert(FALSE);
 }
 
 int
@@ -395,16 +409,16 @@ demu_deregister_memory_space(uint64_t start)
         (_val) = 0;                                                 \
         for (_i = 0; _i < (_count); _i++)                           \
         {                                                           \
-            (_val) |= (uint32_t)(_fn)((_priv), (_addr)) << _shift;  \
+            (_val) |= (uint64_t)(_fn)((_priv), (_addr)) << _shift;  \
             _shift += 8 * (_size);                                  \
             (_addr) += (_size);                                     \
         }                                                           \
     } while (FALSE)
 
-static uint32_t
+uint64_t
 demu_io_read(demu_space_t *space, uint64_t addr, uint64_t size)
 {
-    uint32_t    val = 0;
+    uint64_t    val = ~0ull;
 
     switch (size) {
     case 1:
@@ -415,7 +429,7 @@ demu_io_read(demu_space_t *space, uint64_t addr, uint64_t size)
         if (space->ops->readw == NULL)
             DEMU_IO_READ(space->ops->readb, space->priv, addr, 1, 2, val);
         else
-            val = space->ops->readw(space->priv, addr);
+            DEMU_IO_READ(space->ops->readw, space->priv, addr, 2, 1, val);
         break;
 
     case 4:
@@ -425,12 +439,23 @@ demu_io_read(demu_space_t *space, uint64_t addr, uint64_t size)
             else
                 DEMU_IO_READ(space->ops->readw, space->priv, addr, 2, 2, val);
         } else {
-            val = space->ops->readl(space->priv, addr);
+            DEMU_IO_READ(space->ops->readl, space->priv, addr, 4, 1, val);
+        }
+        break;
+
+    case 8:
+        if (space->ops->readl == NULL) {
+            if (space->ops->readw == NULL)
+                DEMU_IO_READ(space->ops->readb, space->priv, addr, 1, 8, val);
+            else
+                DEMU_IO_READ(space->ops->readw, space->priv, addr, 2, 4, val);
+        } else {
+            DEMU_IO_READ(space->ops->readl, space->priv, addr, 4, 2, val);
         }
         break;
 
     default:
-        assert(FALSE);
+        break;
     }
 
     return val;
@@ -438,8 +463,8 @@ demu_io_read(demu_space_t *space, uint64_t addr, uint64_t size)
 
 #define DEMU_IO_WRITE(_fn, _priv, _addr, _size, _count, _val)   \
     do {                                                        \
-        int                    _i = 0;                             \
-        unsigned int   _shift = 0;                             \
+        int             _i = 0;                                 \
+        unsigned int    _shift = 0;                             \
                                                                 \
         for (_i = 0; _i < (_count); _i++)                       \
         {                                                       \
@@ -449,8 +474,8 @@ demu_io_read(demu_space_t *space, uint64_t addr, uint64_t size)
         }                                                       \
     } while (FALSE)
 
-static void
-demu_io_write(demu_space_t *space, uint64_t addr, uint64_t size, uint32_t val)
+void
+demu_io_write(demu_space_t *space, uint64_t addr, uint64_t size, uint64_t val)
 {
     switch (size) {
     case 1:
@@ -461,7 +486,7 @@ demu_io_write(demu_space_t *space, uint64_t addr, uint64_t size, uint32_t val)
         if (space->ops->writew == NULL)
             DEMU_IO_WRITE(space->ops->writeb, space->priv, addr, 1, 2, val);
         else
-            space->ops->writew(space->priv, addr, val);
+            DEMU_IO_WRITE(space->ops->writew, space->priv, addr, 2, 1, val);
         break;
 
     case 4:
@@ -471,26 +496,53 @@ demu_io_write(demu_space_t *space, uint64_t addr, uint64_t size, uint32_t val)
             else
                 DEMU_IO_WRITE(space->ops->writew, space->priv, addr, 2, 2, val);
         } else {
-            space->ops->writel(space->priv, addr, val);
+            DEMU_IO_WRITE(space->ops->writel, space->priv, addr, 4, 1, val);
+        }
+        break;
+
+    case 8:
+        if (space->ops->writel == NULL) {
+            if (space->ops->writew == NULL)
+                DEMU_IO_WRITE(space->ops->writeb, space->priv, addr, 1, 8, val);
+            else
+                DEMU_IO_WRITE(space->ops->writew, space->priv, addr, 2, 4, val);
+        } else {
+            DEMU_IO_WRITE(space->ops->writel, space->priv, addr, 4, 2, val);
         }
         break;
 
     default:
-        assert(FALSE);
+        break;
     }
 }
 
 static inline void
 __copy_to_guest_memory(uint64_t addr, uint64_t size, uint8_t *src)
 {
-    uint8_t *dst = mapcache_lookup(addr);
+    xen_pfn_t       pfn = addr >> TARGET_PAGE_SHIFT;
+    uint64_t        offset = addr & (TARGET_PAGE_SIZE - 1);
 
-    assert(((addr + size - 1) >> TARGET_PAGE_SHIFT) == (addr >> TARGET_PAGE_SHIFT));
+    while (size != 0) {
+        uint8_t     *dst;
+        uint64_t    chunk;
 
-    if (dst == NULL)
-        goto fail1;
+        chunk = __min(size, TARGET_PAGE_SIZE - offset);
+
+        dst = mapcache_lookup(pfn);
+        if (dst == NULL)
+            goto fail1;
+
+        dst += offset;
+
+        memcpy(dst, src, chunk);
+
+        src += chunk;
+        size -= chunk;
+
+        pfn++;
+        offset = 0;
+    }
 
-    memcpy(dst, src, size);
     return;
 
 fail1:
@@ -500,14 +552,30 @@ fail1:
 static inline void
 __copy_from_guest_memory(uint64_t addr, uint64_t size, uint8_t *dst)
 {
-    uint8_t *src = mapcache_lookup(addr);
+    xen_pfn_t       pfn = addr >> TARGET_PAGE_SHIFT;
+    uint64_t        offset = addr & (TARGET_PAGE_SIZE - 1);
 
-    assert(((addr + size - 1) >> TARGET_PAGE_SHIFT) == (addr >> TARGET_PAGE_SHIFT));
+    while (size != 0) {
+        uint8_t     *src;
+        uint64_t    chunk;
 
-    if (src == NULL)
-        goto fail1;
+        chunk = __min(size, TARGET_PAGE_SIZE - offset);
+
+        src = mapcache_lookup(pfn);
+        if (src == NULL)
+            goto fail1;
+
+        src += offset;
+
+        memcpy(dst, src, chunk);
+
+        dst += chunk;
+        size -= chunk;
+
+        pfn++;
+        offset = 0;
+    }
 
-    memcpy(dst, src, size);
     return;
 
 fail1:
@@ -524,13 +592,13 @@ demu_handle_io(demu_space_t *space, ioreq_t *ioreq, int is_mmio)
 
     if (ioreq->dir == IOREQ_READ) {
         if (!ioreq->data_is_ptr) {
-            ioreq->data = (uint64_t)demu_io_read(space, ioreq->addr, ioreq->size);
+            ioreq->data = demu_io_read(space, ioreq->addr, ioreq->size);
         } else {
             int i, sign;
 
             sign = ioreq->df ? -1 : 1;
             for (i = 0; i < ioreq->count; i++) {
-                uint32_t    data;
+                uint64_t    data;
                 
                 data = demu_io_read(space, ioreq->addr, ioreq->size);
 
@@ -543,13 +611,13 @@ demu_handle_io(demu_space_t *space, ioreq_t *ioreq, int is_mmio)
         }
     } else if (ioreq->dir == IOREQ_WRITE) {
         if (!ioreq->data_is_ptr) {
-            demu_io_write(space, ioreq->addr, ioreq->size, (uint32_t)ioreq->data);
+            demu_io_write(space, ioreq->addr, ioreq->size, ioreq->data);
         } else {
             int i, sign;
 
             sign = ioreq->df ? -1 : 1;
             for (i = 0; i < ioreq->count; i++) {
-                uint32_t    data;
+                uint64_t    data;
 
                 __copy_from_guest_memory(ioreq->data + (sign * i * ioreq->size),
                                          ioreq->size, (uint8_t *)&data);
@@ -567,7 +635,7 @@ demu_handle_io(demu_space_t *space, ioreq_t *ioreq, int is_mmio)
 fail1:
     DBG("fail1\n");
 }
+
 static void
 demu_handle_ioreq(ioreq_t *ioreq)
 {
@@ -605,7 +673,7 @@ demu_handle_ioreq(ioreq_t *ioreq)
         break;
 
     default:
-        assert(FALSE);
+        DBG("UNKNOWN (%02x)", ioreq->type);
         break;
     }
 }
@@ -633,7 +701,7 @@ static enum rfbNewClientAction demu_vnc_add_client(rfbClientPtr client)
 }
 
 void
-demu_vnc_new_framebuffer(uint32_t width, uint32_t height, uint32_t depth)
+demu_new_framebuffer(uint32_t width, uint32_t height, uint32_t depth)
 {
     rfbScreenInfoPtr    screen = demu_state.screen;
 
@@ -648,6 +716,10 @@ demu_vnc_new_framebuffer(uint32_t width, uint32_t height, uint32_t depth)
             DEMU_VNC_DEFAULT_HEIGHT,
             DEMU_VNC_DEFAULT_DEPTH);
 
+        demu_state.width = DEMU_VNC_DEFAULT_WIDTH;
+        demu_state.height = DEMU_VNC_DEFAULT_HEIGHT;
+        demu_state.width = DEMU_VNC_DEFAULT_DEPTH;
+
         rfbNewFramebuffer(screen,
                           (char *)demu_state.default_framebuffer,
                           DEMU_VNC_DEFAULT_WIDTH,
@@ -657,6 +729,10 @@ demu_vnc_new_framebuffer(uint32_t width, uint32_t height, uint32_t depth)
     } else {
         DBG("%dx%dx%d\n", width, height, depth);
 
+        demu_state.width = width;
+        demu_state.height = height;
+        demu_state.width = depth;
+
         rfbNewFramebuffer(screen,
                           (char *)demu_state.framebuffer,
                           width,
@@ -667,11 +743,20 @@ demu_vnc_new_framebuffer(uint32_t width, uint32_t height, uint32_t depth)
 }
 
 uint8_t *
-demu_vnc_get_framebuffer(void)
+demu_get_framebuffer(void)
 {
     return demu_state.framebuffer;
 }   
 
+void
+demu_update_framebuffer(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
+{
+    rfbScreenInfoPtr    screen = demu_state.screen; 
+
+    rfbMarkRectAsModified(screen, x * 160, y, (x + width) * 160, y + height);
+    //rfbMarkRectAsModified(screen, 0, 0, demu_state.width * 160, demu_state.height);
+}   
+
 static int
 demu_vnc_initialize(void)
 {
@@ -800,6 +885,14 @@ demu_seq_next(void)
         DBG(">VNC_INITIALIZED\n");
         break;
 
+    case DEMU_SEQ_DEVICE_INITIALIZED:
+        DBG(">DEVICE_INITIALIZED\n");
+        break;
+
+    case DEMU_SEQ_SURFACE_INITIALIZED:
+        DBG(">SURFACE_INITIALIZED\n");
+        break;
+
     case DEMU_SEQ_INITIALIZED:
         DBG(">INITIALIZED\n");
         break;
@@ -815,6 +908,19 @@ demu_teardown(void)
 {
     if (demu_state.seq == DEMU_SEQ_INITIALIZED) {
         DBG("<INITIALIZED\n");
+
+        demu_state.seq = DEMU_SEQ_SURFACE_INITIALIZED;
+    }
+
+    if (demu_state.seq == DEMU_SEQ_SURFACE_INITIALIZED) {
+        DBG("<SURFACE_INITIALIZED\n");
+        surface_teardown();
+
+        demu_state.seq = DEMU_SEQ_DEVICE_INITIALIZED;
+    }
+
+    if (demu_state.seq == DEMU_SEQ_DEVICE_INITIALIZED) {
+        DBG("<DEVICE_INITIALIZED\n");
         device_teardown();
 
         demu_state.seq = DEMU_SEQ_VNC_INITIALIZED;
@@ -933,7 +1039,7 @@ demu_sigusr1(int num)
 }
 
 static int
-demu_initialize(domid_t domid, unsigned int bus, unsigned int device, unsigned int function)
+demu_initialize(domid_t domid, unsigned int bus, unsigned int device, unsigned int function, char *rom)
 {
     int             rc;
     xc_dominfo_t    dominfo;
@@ -1034,15 +1140,28 @@ demu_initialize(domid_t domid, unsigned int bus, unsigned int device, unsigned i
 
     demu_seq_next();
 
-    rc = device_initialize(bus, device, function, 0x01000000);
+    rc = device_initialize(bus, device, function,
+                           DEMU_VRAM_SIZE,
+                           (rom) ? rom : DEMU_ROM_FILE);
     if (rc < 0)
         goto fail12;
 
     demu_seq_next();
 
+    rc = surface_initialize();
+    if (rc < 0)
+        goto fail13;
+
+    demu_seq_next();
+
+    demu_seq_next();
+
     assert(demu_state.seq == DEMU_SEQ_INITIALIZED);
     return 0;
 
+fail13:
+    DBG("fail13\n");
+
 fail12:
     DBG("fail12\n");
 
@@ -1192,6 +1311,7 @@ main(int argc, char **argv, char **envp)
 {
     char            *domain_str;
     char            *device_str;
+    char            *rom_str;
     int             index;
     char            *end;
     domid_t         domid;
@@ -1204,6 +1324,7 @@ main(int argc, char **argv, char **envp)
 
     domain_str = NULL;
     device_str = NULL;
+    rom_str = NULL;
 
     for (;;) {
         char    c;
@@ -1224,6 +1345,10 @@ main(int argc, char **argv, char **envp)
             device_str = optarg;
             break;
 
+        case DEMU_OPT_ROM:
+            rom_str = optarg;
+            break;
+
         default:
             assert(FALSE);
             break;
@@ -1273,7 +1398,7 @@ main(int argc, char **argv, char **envp)
 
     sigprocmask(SIG_BLOCK, &block, NULL);
 
-    rc = demu_initialize(domid, 0, device, 0);
+    rc = demu_initialize(domid, 0, device, 0, rom_str);
     if (rc < 0) {
         demu_teardown();
         exit(1);
@@ -1288,24 +1413,26 @@ main(int argc, char **argv, char **envp)
         int             nfds;
         struct timeval  tv;
 
+        FD_ZERO(&rfds);
         FD_ZERO(&wfds);
         FD_ZERO(&xfds);
 
-        rfds = demu_state.screen->allFds;
         FD_SET(efd, &rfds);
 
         tv.tv_sec = 0;
         tv.tv_usec = demu_state.screen->deferUpdateTime * 1000;
 
-        nfds = max(demu_state.screen->maxFd, efd) + 1;
+        nfds = efd + 1;
         rc = select(nfds, &rfds, &wfds, &xfds, &tv);
 
         if (rc > 0) {
             if (FD_ISSET(efd, &rfds))
                 demu_poll_iopages();
+        }
 
-            if (rfbIsActive(demu_state.screen))
-                rfbProcessEvents(demu_state.screen, 0);
+        if (rfbIsActive(demu_state.screen)) {
+            surface_refresh();
+            rfbProcessEvents(demu_state.screen, 1000);
         }
 
         if (rc < 0 && errno != EINTR)
diff --git a/demu.h b/demu.h
index 451ac541eefbb99983a6b8d215173133c97cbaf8..75cd4f6faa8b427c02c282453011b8807d8ec2f8 100644 (file)
--- a/demu.h
+++ b/demu.h
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  *
  */
 
+#include <xenctrl.h>
+
 #ifndef  _DEMU_H
 #define  _DEMU_H
 
 #define TARGET_PAGE_SHIFT   12
 #define TARGET_PAGE_SIZE    (1 << TARGET_PAGE_SHIFT)
 
+#define        P2ROUNDUP(_x, _a) -(-(_x) & -(_a))
+
 void    *demu_map_guest_pages(xen_pfn_t pfn[], unsigned int n);
 
 static inline void *demu_map_guest_page(xen_pfn_t pfn)
@@ -60,4 +64,20 @@ void demu_deregister_pci_config_space(uint8_t bus, uint8_t device, uint8_t funct
 void demu_deregister_port_space(uint64_t start);
 void demu_deregister_memory_space(uint64_t start);
 
+
+void    demu_new_framebuffer(uint32_t width, uint32_t height, uint32_t depth);
+uint8_t *demu_get_framebuffer(void);
+void    demu_update_framebuffer(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
+
 #endif  /* _DEMU_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-tab-always-indent: nil
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index cd03d0c4b7f5c6d70a71fbb80e57e87ff22ef026..18e7daa1a5daaa8ac48b4679aba23cc7ea378ae6 100644 (file)
--- a/device.c
+++ b/device.c
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 #include <err.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <string.h>
 #include <assert.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <errno.h>
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/mman.h>
 
 #include <xenctrl.h>
@@ -47,7 +75,9 @@
 
 #define FALSE 0
 
-#define DEBUG_VGA_MEMORY 0
+#define DEBUG_VGA_MEMORY    0
+#define DEBUG_VGA_IO        0
+#define DEBUG_VBE_IO        0
 
 /* force some bits to zero */
 static const uint8_t __sr_mask[8] = {
@@ -106,9 +136,16 @@ static const uint32_t mask16[16] = {
 #undef PAT
 
 typedef struct device {
+    vga_t           vga;
+    int             fd;
+    uint64_t        vram_addr;
     uint64_t        vram_size;
     uint8_t         *vram;
-    vga_t           vga;
+    uint64_t        mmio_addr;
+    uint64_t        mmio_size;
+    uint64_t        rom_addr;
+    uint64_t        rom_size;
+    uint8_t         *rom;
 } device_t;
 
 static  device_t   device_state;
@@ -365,6 +402,10 @@ device_vga_port_readb(void *priv, uint64_t addr)
         }
     }
 
+#if  DEBUG_VGA_IO
+    DBG("[0x%"PRIx64"] -> 0x%02x\n", addr, val);
+#endif
+
     return val;
 }
 
@@ -376,6 +417,10 @@ device_vga_port_writeb(void *priv, uint64_t addr, uint8_t val)
 
     assert(priv == NULL);
 
+#if  DEBUG_VGA_IO
+    DBG("[0x%"PRIx64"] <- 0x%02x\n", addr, val);
+#endif
+
     /* check port range access depending on color/monochrome mode */
     if ((addr >= 0x3b0 && addr <= 0x3bf && (vga->msr & MSR_COLOR_EMULATION)) ||
         (addr >= 0x3d0 && addr <= 0x3df && !(vga->msr & MSR_COLOR_EMULATION)))
@@ -552,6 +597,10 @@ device_vga_memory_readb(void *priv, uint64_t addr)
         }
     }
 
+#if  DEBUG_VGA_MEMORY
+    DBG("[0x%"PRIx64"] -> 0x%02x\n", addr, val);
+#endif
+
     return val;
 }
 
@@ -572,7 +621,7 @@ device_vga_memory_writeb(void *priv, uint64_t addr, uint8_t val)
     assert(priv == NULL);
 
 #if  DEBUG_VGA_MEMORY
-    DBG("[0x%llx] = 0x%02x\n", addr, val);
+    DBG("[0x%"PRIx64"] <- 0x%02x\n", addr, val);
 #endif
 
     /* convert to VGA memory offset */
@@ -607,7 +656,7 @@ device_vga_memory_writeb(void *priv, uint64_t addr, uint8_t val)
         if (vga->sr[2] & mask) {
             __copy_to_vram(&val, addr, 1);
 #if  DEBUG_VGA_MEMORY
-            DBG("chain4: [0x%llx] val=0x%02x\n", addr, val);
+            DBG("chain4: [0x%"PRIx64"] val=0x%02x\n", addr, val);
 #endif
             vga->plane_updated |= mask; /* only used to detect font change */
 
@@ -620,7 +669,7 @@ device_vga_memory_writeb(void *priv, uint64_t addr, uint8_t val)
             addr = ((addr & ~1) << 1) | plane;
             __copy_to_vram(&val, addr, 1);
 #if  DEBUG_VGA_MEMORY
-            DBG("odd/even: [0x%llx] val=0x%02x\n", addr, val);
+            DBG("odd/even: [0x%"PRIx64"] val=0x%02x\n", addr, val);
 #endif
             vga->plane_updated |= mask; /* only used to detect font change */
         }
@@ -707,7 +756,7 @@ device_vga_memory_writeb(void *priv, uint64_t addr, uint8_t val)
         __copy_to_vram((uint8_t *)&tmp, addr << 2, 4);
 
 #if  DEBUG_VGA_MEMORY
-        DBG("latch: [0x%llx] val=0x%08x\n", addr << 2, tmp);
+        DBG("latch: [0x%"PRIx64"] val=0x%08x\n", addr << 2, tmp);
 #endif
 
     }
@@ -782,6 +831,10 @@ device_vbe_port_readw(void *priv, uint64_t addr)
         break;
     }
 
+#if  DEBUG_VBE_IO
+    DBG("[0x%"PRIx64"] -> 0x%04x\n", addr, val);
+#endif
+
     return val;
 }
 
@@ -943,6 +996,10 @@ device_vbe_port_writew(void *priv, uint64_t addr, uint16_t val)
 {
     assert(priv == NULL);
 
+#if  DEBUG_VBE_IO
+    DBG("[0x%"PRIx64"] <- 0x%04x\n", addr, val);
+#endif
+
     switch (addr) {
     case 0x1ce:
     case 0xff80:
@@ -1064,64 +1121,202 @@ device_vga_deregister(void)
 }
 
 static uint8_t
-device_bar_readb(void *priv, uint64_t addr)
+device_vram_readb(void *priv, uint64_t addr)
 {
-    vga_t   *vga = &device_state.vga;
     uint8_t val;
 
-    __copy_from_vram(addr - vga->lfb_addr, &val, 1);
+    addr -= device_state.vram_addr;
+
+    __copy_from_vram(addr, &val, 1);
 
     return val;
 }
 
 static void
-device_bar_writeb(void *priv, uint64_t addr, uint8_t val)
+device_vram_writeb(void *priv, uint64_t addr, uint8_t val)
 {
-    vga_t   *vga = &device_state.vga;
+    addr -= device_state.vram_addr;
 
-    __copy_to_vram(&val, addr - vga->lfb_addr, 1);
+    __copy_to_vram(&val, addr, 1);
 }
 
-static io_ops_t device_bar_ops = {
-    .readb = device_bar_readb,
-    .writeb = device_bar_writeb
+static io_ops_t device_vram_ops = {
+    .readb = device_vram_readb,
+    .writeb = device_vram_writeb
 };
 
 static void
-device_bar_enable(void *priv, uint64_t addr)
+device_vram_bar_enable(void *priv, uint64_t addr)
 {
     vga_t   *vga = &device_state.vga;
-    int     rc;
 
     assert(priv == NULL);
 
-    vga->lfb_addr = addr;
+    device_state.vram_addr = addr;
+    DBG("%"PRIx64"\n", device_state.vram_addr);
+
+    vga->lfb_addr = device_state.vram_addr;
     vga->lfb_size = device_state.vram_size;
 
     vga->vbe_regs[VBE_DISPI_INDEX_LFB_ADDRESS_H] = vga->lfb_addr >> 16;
     vga->vbe_regs[VBE_DISPI_INDEX_LFB_ADDRESS_L] = vga->lfb_addr & 0xFFFF;
     vga->vbe_regs[VBE_DISPI_INDEX_VIDEO_MEMORY_64K] = vga->lfb_size >> 16;
 
-    rc = demu_register_memory_space(vga->lfb_addr, vga->lfb_size,
-                                    &device_bar_ops, NULL);
-    assert(rc == 0);
+    (void) demu_register_memory_space(device_state.vram_addr,
+                                      device_state.vram_size,
+                                      &device_vram_ops,
+                                      NULL);
 }
 
 static void
-device_bar_disable(void *priv)
+device_vram_bar_disable(void *priv)
 {
-    vga_t   *vga = &device_state.vga;
+    assert(priv == FALSE);
+
+    DBG("%"PRIx64"\n", device_state.vram_addr);
+
+    demu_deregister_memory_space(device_state.vram_addr);
+}
+
+#define PCI_VGA_OFFSET  0x400
+#define PCI_VGA_SIZE    (0x3e0 - 0x3c0)
+#define PCI_VBE_OFFSET  0x500
+#define PCI_VBE_SIZE    (0x0b * 2)
+#define MMIO_SIZE       0x1000
+
+static uint8_t
+device_pci_vga_readb(void *priv, uint64_t addr)
+{
+    addr -= device_state.mmio_addr + PCI_VGA_OFFSET;
+
+    return device_vga_port_readb(priv, addr + 0x3c0);
+}
+
+static void
+device_pci_vga_writeb(void *priv, uint64_t addr, uint8_t val)
+{
+    addr -= device_state.mmio_addr + PCI_VGA_OFFSET;
+
+    device_vga_port_writeb(priv, addr + 0x3c0, val);
+}
+
+static io_ops_t device_pci_vga_ops = {
+    .readb = device_pci_vga_readb,
+    .writeb = device_pci_vga_writeb
+};
+
+static uint16_t
+device_pci_vbe_readw(void *priv, uint64_t addr)
+{
+    addr -= device_state.mmio_addr + PCI_VBE_OFFSET;
+
+    device_vbe_index_write(priv, addr >> 1);
+    return device_vbe_data_read(priv);
+}
+
+static void
+device_pci_vbe_writew(void *priv, uint64_t addr, uint16_t val)
+{
+    addr -= device_state.mmio_addr + PCI_VBE_OFFSET;
+
+    device_vbe_index_write(priv, addr >> 1);
+    device_vbe_data_write(priv, val);
+}
+
+static io_ops_t device_pci_vbe_ops = {
+    .readw = device_pci_vbe_readw,
+    .writew = device_pci_vbe_writew
+};
+
+static void
+device_mmio_bar_enable(void *priv, uint64_t addr)
+{
+    assert(priv == NULL);
+
+    device_state.mmio_addr = addr;
+    DBG("%"PRIx64"\n", device_state.mmio_addr);
+
+    (void) demu_register_memory_space(device_state.mmio_addr + PCI_VGA_OFFSET,
+                                      PCI_VGA_SIZE,
+                                      &device_pci_vga_ops,
+                                      NULL);
+
+    (void)demu_register_memory_space(device_state.mmio_addr + PCI_VBE_OFFSET,
+                                     PCI_VBE_SIZE,
+                                     &device_pci_vbe_ops,
+                                     NULL);
+}
+
+static void
+device_mmio_bar_disable(void *priv)
+{
+    assert(priv == FALSE);
+
+    DBG("%"PRIx64"\n", device_state.mmio_addr);
+
+    demu_deregister_memory_space(device_state.mmio_addr + PCI_VGA_OFFSET);
+    demu_deregister_memory_space(device_state.mmio_addr + PCI_VBE_OFFSET);
+}
+
+static void
+__copy_from_rom(uint64_t addr, uint8_t *dst, uint64_t size)
+{
+    memcpy(dst, &device_state.rom[addr], size);
+}
+
+static uint8_t
+device_rom_readb(void *priv, uint64_t addr)
+{
+    uint8_t val;
+
+    addr -= device_state.rom_addr;
+
+    __copy_from_rom(addr, &val, 1);
+
+    return val;
+}
+
+static void
+device_rom_writeb(void *priv, uint64_t addr, uint8_t val)
+{
+    DBG("%"PRIx64" <- %02x\n", addr, val);
+}
+
+static io_ops_t device_rom_bar_ops = {
+    .readb = device_rom_readb,
+    .writeb = device_rom_writeb
+};
+
+static void
+device_rom_bar_enable(void *priv, uint64_t addr)
+{
+    assert(priv == NULL);
+
+    device_state.rom_addr = addr;
+    DBG("%"PRIx64"\n", device_state.rom_addr);
+
+    (void) demu_register_memory_space(device_state.rom_addr,
+                                      device_state.rom_size,
+                                      &device_rom_bar_ops,
+                                      NULL);
+}
 
+static void
+device_rom_bar_disable(void *priv)
+{
     assert(priv == FALSE);
 
-    demu_deregister_memory_space(vga->lfb_addr);
+    DBG("%"PRIx64"\n", device_state.rom_addr);
+
+    demu_deregister_memory_space(device_state.rom_addr);
 }
 
 int
 device_initialize(unsigned int bus, unsigned int device, unsigned int function,
-                  uint64_t vram_size)
+                  uint64_t vram_size, char *romfile)
 {
     pci_info_t  info;
+    struct stat st;
     int         rc;
 
     device_state.vram_size = vram_size;
@@ -1159,14 +1354,95 @@ device_initialize(unsigned int bus, unsigned int device, unsigned int function,
     rc = pci_bar_register(0,
                           PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH,
                           device_state.vram_size,
-                          device_bar_enable,
-                          device_bar_disable,
+                          device_vram_bar_enable,
+                          device_vram_bar_disable,
                           NULL);
     if (rc < 0)
         goto fail4;
 
+    device_state.mmio_size = MMIO_SIZE;
+
+    rc = pci_bar_register(2,
+                          PCI_BASE_ADDRESS_SPACE_MEMORY,
+                          device_state.mmio_size,
+                          device_mmio_bar_enable,
+                          device_mmio_bar_disable,
+                          NULL);
+    if (rc < 0)
+        goto fail5;
+
+    device_state.fd = -1;
+
+    if (romfile == NULL)
+        goto done;
+
+    device_state.fd = open(romfile, O_RDONLY);
+    if (device_state.fd < 0)
+        goto fail6;
+
+    rc = fstat(device_state.fd, &st);
+    if (rc < 0)
+        goto fail7;
+
+    device_state.rom_size = P2ROUNDUP(st.st_size, TARGET_PAGE_SIZE);
+
+    DBG("ROM: %s (%"PRIu64"k)\n", romfile, device_state.rom_size / 4);
+
+    device_state.rom = mmap(NULL,
+                            device_state.rom_size,
+                            PROT_READ,
+                            MAP_SHARED,
+                            device_state.fd,
+                            0);
+    if (device_state.rom == MAP_FAILED)
+        goto fail8;
+
+    if (device_state.rom[0] != 0x55 &&
+        device_state.rom[1] != 0xAA) {
+        errno = EINVAL;
+        goto fail9;
+    }
+
+    rc = pci_bar_register(PCI_ROM_SLOT,
+                          0,
+                          device_state.rom_size,
+                          device_rom_bar_enable,
+                          device_rom_bar_disable,
+                          NULL);
+    if (rc < 0)
+        goto fail10;
+
+done:
+    pci_device_dump();
+
     return 0;
 
+fail10:
+    DBG("fail10\n");
+
+fail9:
+    DBG("fail9\n");
+
+    munmap(device_state.rom, device_state.rom_size);
+
+fail8:
+    DBG("fail8\n");
+
+fail7:
+    DBG("fail7\n");
+
+    close(device_state.fd);
+
+fail6:
+    DBG("fail6\n");
+
+    pci_bar_deregister(2);
+
+fail5:
+    DBG("fail5\n");
+
+    pci_bar_deregister(0);
+
 fail4:
     DBG("fail4\n");
 
@@ -1189,11 +1465,45 @@ fail1:
     return -1;
 }
 
+uint8_t *device_get_vram(void)
+{
+       return device_state.vram;
+}
+
+vga_t *device_get_vga(void)
+{
+       return &device_state.vga;
+}
+
+int device_vram_dirty(uint64_t addr, uint64_t size)
+{
+    return 1;
+}
+
 void
 device_teardown(void)
 {
+    if (device_state.fd >= 0) {
+        pci_bar_deregister(PCI_ROM_SLOT);
+        munmap(device_state.rom, device_state.rom_size);
+        close(device_state.fd);
+    }
+
+    pci_bar_deregister(2);
     pci_bar_deregister(0);
     pci_device_deregister();
     device_vga_deregister();
     free(device_state.vram);
 }
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 7d9883a523b72de4a9736b599727c3aab4a6096d..b83233e4341721ebc91435e52b2259053077977e 100644 (file)
--- a/device.h
+++ b/device.h
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+
+#include "vga.h"
+
 #ifndef  _DEVICE_H
 #define  _DEVICE_H
 
 int     device_initialize(unsigned int bus, unsigned int device, unsigned int function,
-                          uint64_t vram_size);
+                          uint64_t vram_size, char *romfile);
 void    device_teardown(void);
 
+uint8_t *device_get_vram(void);
+vga_t   *device_get_vga(void);
+int     device_vram_dirty(uint64_t addr, uint64_t size);
+
 #endif  /* _DEVICE_H */
 
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index c142486cdebacbdce94e013ff6da176cf843b056..f9c20eddd3a3d3775462104839b57ba0179342b5 100644 (file)
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
+#include <inttypes.h>
 
 #include <sys/types.h>
 #include <sys/mman.h>
@@ -90,7 +91,7 @@ __mapcache_fault(xen_pfn_t pfn)
     int         i;
     uint64_t    oldest_epoch;
 
-    DBG("%llx\n", (unsigned long long)pfn);
+    DBG("%"PRIx64"\n", pfn);
 
     bucket = pfn % MAPCACHE_BUCKET_COUNT;
 
@@ -126,18 +127,13 @@ __mapcache_fault(xen_pfn_t pfn)
 }
 
 uint8_t *
-mapcache_lookup(uint64_t addr)
+mapcache_lookup(xen_pfn_t pfn)
 {
-    xen_pfn_t       pfn;
-    unsigned int    offset;
     uint8_t         *ptr;
     int             faulted;
 
-    pfn = addr >> TARGET_PAGE_SHIFT;
-    offset = addr & (TARGET_PAGE_SIZE - 1);
-
     faulted = 0;
-again:
+gain:
     ptr = __mapcache_lookup(pfn);
     if (ptr == NULL) {
         if (!faulted) {
@@ -148,7 +144,6 @@ again:
         goto fail1;
     }
 
-    ptr += offset;
     return ptr;
 
 fail1:
@@ -162,6 +157,8 @@ mapcache_invalidate(void)
 {
     int i;
 
+    DBG("\n");
+
     for (i = 0; i < MAPCACHE_BUCKET_SIZE * MAPCACHE_BUCKET_COUNT; i++) {
         mapcache_entry_t *entry = &mapcache[i];
 
@@ -171,3 +168,14 @@ mapcache_invalidate(void)
         }
     }
 }
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-tab-always-indent: nil
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 158b556d88d31e65fb86ce08e349c512e20400d0..6712a25b01edc0a61eb2c45028746ce9880d818d 100644 (file)
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
 #ifndef  _MAPCACHE_H
 #define  _MAPCACHE_H
 
-uint8_t *mapcache_lookup(uint64_t addr);
+uint8_t *mapcache_lookup(xen_pfn_t pfn);
 void    mapcache_invalidate(void);
 
 #endif  /* _MAPCACHE_H */
 
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-tab-always-indent: nil
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/pci.c b/pci.c
index 3eaac4b07563b10e9cc515b38e4a71471aafc4b2..07fba58515cf8f010f54009d400b22d4c1137721 100644 (file)
--- a/pci.c
+++ b/pci.c
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -89,21 +89,38 @@ static void
 pci_bar_update(unsigned int index)
 {
     pci_bar_t  *bar = &pci_state.bar[index];
-    uint32_t   addr = *(uint32_t *)&pci_state.config[PCI_BASE_ADDRESS_0 + (index * 4)];
     uint16_t   cmd = *(uint16_t *)&pci_state.config[PCI_COMMAND];
-    uint32_t   mask = ~(bar->size - 1);
+    uint8_t     offset;
+    uint32_t   addr;
+    uint32_t   mask;
 
     if (bar->size == 0)
         return;
 
-    if (bar->is_mmio)
-        addr &= PCI_BASE_ADDRESS_MEM_MASK;
+    if (index == PCI_ROM_SLOT)
+           offset = PCI_ROM_ADDRESS;
     else
-        addr &= PCI_BASE_ADDRESS_IO_MASK;
+           offset = PCI_BASE_ADDRESS_0 + (index * 4);
+
+    addr = *(uint32_t *)&pci_state.config[offset];
+    mask = *(uint32_t *)&pci_state.mask[offset];
+
+    if (index == PCI_ROM_SLOT) {
+           addr &= PCI_ROM_ADDRESS_MASK;
+           mask &= PCI_ROM_ADDRESS_MASK;
+    } else {
+           if (bar->is_mmio) {
+                   addr &= PCI_BASE_ADDRESS_MEM_MASK;
+                   mask &= PCI_BASE_ADDRESS_MEM_MASK;
+           } else {
+                   addr &= PCI_BASE_ADDRESS_IO_MASK;
+                   mask &= PCI_BASE_ADDRESS_IO_MASK;
+           }
+    }
 
     if ((!(cmd & PCI_COMMAND_IO) && !bar->is_mmio)
         || (!(cmd & PCI_COMMAND_MEMORY) && bar->is_mmio))
-        addr = PCI_BAR_UNMAPPED;
+           addr = PCI_BAR_UNMAPPED;
 
     if (addr == 0 || addr == mask)
         addr = PCI_BAR_UNMAPPED;
@@ -117,6 +134,7 @@ pci_bar_update(unsigned int index)
     }
 
     if (addr != PCI_BAR_UNMAPPED) {
+           assert(bar->addr == PCI_BAR_UNMAPPED);
         bar->addr = addr;
         pci_bar_enable(index);
     }
@@ -164,16 +182,21 @@ pci_device_dump(void)
 {
     int        i;
 
-    fprintf(stderr, "    3  2  1  0\n");
-    fprintf(stderr, "--------------\n");
+    fprintf(stderr, "      VALUE      |  MASK        \n");
+    fprintf(stderr, "      3  2  1  0 |  3  2  1  0  \n");
+    fprintf(stderr, "-----------------|--------------\n");
 
     for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i += 4) {
-        fprintf(stderr, "%02x |%02x %02x %02x %02x\n",
+        fprintf(stderr, "%02x | %02x %02x %02x %02x | %02x %02x %02x %02x\n",
                 i,
                 pci_state.config[i + 3],
                 pci_state.config[i + 2],
                 pci_state.config[i + 1],
-                pci_state.config[i ]);
+                pci_state.config[i ],
+                pci_state.mask[i + 3],
+                pci_state.mask[i + 2],
+                pci_state.mask[i + 1],
+                pci_state.mask[i ]);
     }
 }
 
@@ -242,6 +265,8 @@ pci_bar_register(unsigned int index, uint8_t type, uint64_t size,
                  void *priv)
 {
     pci_bar_t  *bar;
+    uint32_t    mask;
+    uint8_t     offset;
 
     DBG("%d: %"PRIx64"\n", index, size);
 
@@ -261,8 +286,17 @@ pci_bar_register(unsigned int index, uint8_t type, uint64_t size,
     bar->addr = PCI_BAR_UNMAPPED;
     bar->size = size;
 
-    *(uint32_t *)&pci_state.config[PCI_BASE_ADDRESS_0 + (index * 4)] = type;
-    *(uint32_t *)&pci_state.mask[PCI_BASE_ADDRESS_0 + (index * 4)] = ~(bar->size - 1);
+    mask = ~(bar->size - 1);
+
+    if (index == PCI_ROM_SLOT) {
+           offset = PCI_ROM_ADDRESS;
+           mask |= PCI_ROM_ADDRESS_ENABLE;
+    } else {
+           offset = PCI_BASE_ADDRESS_0 + (index * 4);
+    }
+
+    *(uint32_t *)&pci_state.config[offset] = type;
+    *(uint32_t *)&pci_state.mask[offset] = mask;
 
     return 0;
 
@@ -290,3 +324,16 @@ pci_bar_deregister(unsigned int index)
     bar->disable(bar->priv);
     bar->size = 0;
 }
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/pci.h b/pci.h
index 41865ec7127246a1425da282643e92f41fc2aa63..a02b5417a98a25861bdab09124c87fd07696b58b 100644 (file)
--- a/pci.h
+++ b/pci.h
@@ -1,5 +1,5 @@
 /*  
- * Copyright (c) 2012, Citrix Systems Inc.
+ * Copyright (c) 2014, Citrix Systems Inc.
  * All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,8 @@
 #ifndef  _PCI_H
 #define  _PCI_H
 
-#define PCI_NUM_BAR             6
+#define PCI_NUM_BAR             7
+#define PCI_ROM_SLOT            6
 #define PCI_CONFIG_HEADER_SIZE  0x40
 #define PCI_CONFIG_SIZE         0x100
 #define PCI_BAR_UNMAPPED        (~(0u))
@@ -66,3 +67,14 @@ void    pci_device_dump(void);
 
 #endif  /* _PCI_H */
 
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/surface.c b/surface.c
new file mode 100644 (file)
index 0000000..3894d03
--- /dev/null
+++ b/surface.c
@@ -0,0 +1,1010 @@
+/*  
+ * Copyright (c) 2014, Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "debug.h"
+#include "demu.h"
+#include "device.h"
+#include "vga.h"
+#include "surface.h"
+
+#define FALSE 0
+#define TRUE  1
+
+#define GMODE_TEXT      0
+#define GMODE_GRAPHIC   1
+#define GMODE_BLANK     2
+
+#define CH_ATTR_SIZE (160 * 100)
+#define VGA_MAX_HEIGHT 2048
+
+typedef struct surface {
+    uint8_t             *vram;
+    uint8_t             *framebuffer;
+    vga_t               *vga;
+    uint32_t            font_offsets[2];
+    int                 graphic_mode;
+    uint8_t             shift_control;
+    uint8_t             double_scan;
+    uint32_t            line_offset;
+    uint32_t            line_compare;
+    uint32_t            start_addr;
+    uint32_t            linesize;
+    uint32_t            last_line_offset;
+    uint8_t             last_cw;
+    uint8_t             last_ch;
+    uint32_t            last_width;
+    uint32_t            last_height;
+    uint32_t            last_scr_width;
+    uint32_t            last_scr_height;
+    uint32_t            last_depth;
+    uint8_t             cursor_start;
+    uint8_t             cursor_end;
+    uint32_t            cursor_offset;
+    unsigned int        (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
+    uint32_t            last_palette[256];
+    uint32_t            last_ch_attr[CH_ATTR_SIZE];
+    uint32_t            invalidated_y_table[VGA_MAX_HEIGHT / 32];
+} surface_t;
+
+static surface_t    surface_state;
+
+static uint32_t     expand4[256];
+static uint16_t     expand2[256];
+static uint8_t      expand4to8[16];
+
+static uint8_t get_ar_index(surface_t *s)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->ar_index;
+}
+
+static uint8_t get_ar(surface_t *s, int reg)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->ar[reg];
+}
+
+static uint8_t get_cr(surface_t *s, int reg)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->cr[reg];
+}
+
+static uint8_t get_sr(surface_t *s, int reg)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->sr[reg];
+}
+
+static uint8_t get_gr(surface_t *s, int reg)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->gr[reg];
+}
+
+static uint8_t get_palette(surface_t *s, int offset)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->palette[offset];
+}
+
+static int is_dac_8bit(surface_t *s)
+{
+    vga_t   *vga = s->vga;
+
+    return !!vga->dac_8bit;
+}
+
+static int test_and_clear_plane2(surface_t *s)
+{
+    vga_t   *vga = s->vga;
+    uint32_t val;
+
+    val = vga->plane_updated & (1 << 2);
+    if (val)
+        vga->plane_updated = 0;
+
+    return !!val;
+}
+
+static uint16_t get_vbe_regs(surface_t *s, int reg)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->vbe_regs[reg];
+}
+
+static uint32_t get_vbe_start_addr(surface_t *s)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->vbe_start_addr;
+}
+
+static uint32_t get_vbe_line_offset(surface_t *s)
+{
+    vga_t   *vga = s->vga;
+
+    return vga->vbe_line_offset;
+}
+
+static void get_offsets(surface_t *s,
+                        uint32_t *pline_offset,
+                        uint32_t *pstart_addr,
+                        uint32_t *pline_compare)
+{
+    uint32_t start_addr, line_offset, line_compare;
+
+    if (get_vbe_regs(s, VBE_DISPI_INDEX_ENABLE) & VBE_DISPI_ENABLED) {
+        line_offset = get_vbe_line_offset(s);
+        start_addr = get_vbe_start_addr(s);
+        line_compare = 65535;
+    } else {
+        /* compute line_offset in bytes */
+        line_offset = get_cr(s, 0x13);
+        line_offset <<= 3;
+
+        /* starting address */
+        start_addr = get_cr(s, 0x0d) | (get_cr(s, 0x0c) << 8);
+
+        /* line compare */
+        line_compare = get_cr(s, 0x18) |
+            ((get_cr(s, 0x07) & 0x10) << 4) |
+            ((get_cr(s, 0x09) & 0x40) << 3);
+    }
+    *pline_offset = line_offset;
+    *pstart_addr = start_addr;
+    *pline_compare = line_compare;
+}
+
+static int get_bpp(surface_t *s)
+{
+    int ret;
+
+    if (get_vbe_regs(s, VBE_DISPI_INDEX_ENABLE) & VBE_DISPI_ENABLED) {
+        ret = get_vbe_regs(s, VBE_DISPI_INDEX_BPP);
+    } else  {
+        ret = 0;
+    }
+
+    return ret;
+}
+
+static void get_resolution(surface_t *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+    if (get_vbe_regs(s, VBE_DISPI_INDEX_ENABLE) & VBE_DISPI_ENABLED) {
+        width = get_vbe_regs(s, VBE_DISPI_INDEX_XRES);
+        height = get_vbe_regs(s, VBE_DISPI_INDEX_YRES);
+    } else  {
+        width = (get_cr(s, 0x01) + 1) * 8;
+        height = get_cr(s, 0x12) |
+            ((get_cr(s, 0x07) & 0x02) << 7) |
+            ((get_cr(s, 0x07) & 0x40) << 3);
+        height = (height + 1);
+    }
+    *pwidth = width;
+    *pheight = height;
+}
+
+static inline int c6_to_8(int v)
+{
+    int b;
+    v &= 0x3f;
+    b = v & 1;
+    return (v << 2) | (b << 1) | b;
+}
+
+/* return true if the palette was modified */
+static int vgpu_update_palette16(surface_t *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    for(i = 0; i < 16; i++) {
+        v = get_ar(s, i);
+        if (get_ar(s, 0x10) & 0x80)
+            v = ((get_ar(s, 0x14) & 0xf) << 4) | (v & 0xf);
+        else
+            v = ((get_ar(s, 0x14) & 0xc) << 4) | (v & 0x3f);
+        v = v * 3;
+        col = s->rgb_to_pixel(c6_to_8(get_palette(s, v)),
+                              c6_to_8(get_palette(s, v + 1)),
+                              c6_to_8(get_palette(s, v + 2)));
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+    }
+    return full_update;
+}
+
+static int vgpu_update_palette256(surface_t *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    v = 0;
+    for(i = 0; i < 256; i++) {
+        if (is_dac_8bit(s)) {
+          col = s->rgb_to_pixel(get_palette(s, v),
+                                get_palette(s, v + 1),
+                                get_palette(s, v + 2));
+        } else {
+          col = s->rgb_to_pixel(c6_to_8(get_palette(s, v)),
+                                c6_to_8(get_palette(s, v + 1)),
+                                c6_to_8(get_palette(s, v + 2)));
+        }
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+        v += 3;
+    }
+    return full_update;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(surface_t *s)
+{
+    int full_update;
+    uint32_t start_addr, line_offset, line_compare;
+
+    full_update = 0;
+
+    get_offsets(s, &line_offset, &start_addr, &line_compare);
+
+    if (line_offset != s->line_offset ||
+        start_addr != s->start_addr ||
+        line_compare != s->line_compare) {
+        s->line_offset = line_offset;
+        s->start_addr = start_addr;
+        s->line_compare = line_compare;
+        full_update = 1;
+    }
+    return full_update;
+}
+
+static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
+{
+    return (b << 16) | (g << 8) | r;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32(r, g, b);
+    return col;
+}
+
+#define PAT(x) (x)
+
+static const uint32_t mask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+#undef PAT
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#define PAT(x) cbswap_32(x)
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+#undef PAT
+
+#define BIG 0
+
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+
+#define xglue(_x, _y) _x##_y
+#define glue(_x, _y) xglue(_x, _y)
+
+#define cpu_to_32wu(_p, _v) \
+    *(_p) = (_v)
+
+#define lduw_raw(_p) \
+    (*(uint16_t *)(_p))
+
+#define DEPTH 32
+#include "template.h"
+
+typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
+                             const uint8_t *font_ptr, int h,
+                             uint32_t fgcol, uint32_t bgcol);
+typedef void vga_draw_glyph16_func(uint8_t *d, int linesize,
+                             const uint8_t *font_ptr, int h,
+                             uint32_t fgcol, uint32_t bgcol);
+typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
+                                  const uint8_t *font_ptr, int h,
+                                  uint32_t fgcol, uint32_t bgcol, int dup9);
+
+static vga_draw_glyph8_func *vga_draw_glyph8 = __vga_draw_glyph8_32;
+static vga_draw_glyph16_func *vga_draw_glyph16 = __vga_draw_glyph16_32;
+static vga_draw_glyph9_func *vga_draw_glyph9 = __vga_draw_glyph9_32;
+
+static const uint8_t cursor_glyph[32 * 4] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+enum {
+    VGA_DRAW_LINE2,
+    VGA_DRAW_LINE2D2,
+    VGA_DRAW_LINE4,
+    VGA_DRAW_LINE4D2,
+    VGA_DRAW_LINE8D2,
+    VGA_DRAW_LINE8,
+    VGA_DRAW_LINE15,
+    VGA_DRAW_LINE16,
+    VGA_DRAW_LINE24,
+    VGA_DRAW_LINE32,
+    VGA_DRAW_LINE_NB,
+};
+
+typedef void vga_draw_line_func(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                const uint8_t *s, int width);
+
+static vga_draw_line_func *vga_draw_line_table[VGA_DRAW_LINE_NB] = {
+    __vga_draw_line2_32,
+    __vga_draw_line2d2_32,
+    __vga_draw_line4_32,
+    __vga_draw_line4d2_32,
+    __vga_draw_line8d2_32,
+    __vga_draw_line8_32,
+    __vga_draw_line15_32,
+    __vga_draw_line16_32,
+    __vga_draw_line24_32,
+    __vga_draw_line32_32,
+};
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func *rgb_to_pixel_dup = rgb_to_pixel32_dup;
+
+static void
+surface_resize(uint32_t width, uint32_t height)
+{
+    DBG("%ux%u\n", width, height);
+
+    surface_state.linesize = width * 4;
+
+    surface_state.last_scr_width = width;
+    surface_state.last_scr_height = height;
+
+    demu_new_framebuffer(width, height, 4);
+
+    surface_state.framebuffer = demu_get_framebuffer();
+}
+
+int
+surface_initialize(void)
+{
+    int i;
+    int j;
+    int v;
+    int b;
+
+    for (i = 0; i < 256; i++) {
+        v = 0;
+        for (j = 0; j < 8; j++)
+            v |= ((i >> j) & 1) << (j * 4);
+        expand4[i] = v;
+
+        v = 0;
+        for (j = 0; j < 4; j++)
+            v |= ((i >> (2 * j)) & 3) << (j * 4);
+        expand2[i] = v;
+    }
+
+    for (i = 0; i < 16; i++) {
+        v = 0;
+        for (j = 0; j < 4; j++) {
+            b = ((i >> j) & 1);
+            v |= b << (2 * j);
+            v |= b << (2 * j + 1);
+        }
+        expand4to8[i] = v;
+    }
+
+    surface_state.graphic_mode = -1;
+    surface_state.vram = device_get_vram();
+    surface_state.vga = device_get_vga();
+
+    return 0;
+}
+
+static void
+surface_update(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
+{
+    demu_update_framebuffer(x, y, width, height);
+}
+
+static void
+surface_draw_text(surface_t *s, int full_update)
+{
+    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
+    int cx_min, cx_max, linesize, x_incr;
+    uint32_t offset, fgcol, bgcol, v, cursor_offset;
+    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
+    const uint8_t *font_ptr, *font_base[2];
+    int dup9, line_offset;
+    uint32_t *palette;
+    uint32_t *ch_attr_ptr;
+    vga_draw_glyph8_func *__vga_draw_glyph8;
+    vga_draw_glyph9_func *__vga_draw_glyph9;
+
+    /* compute font data address (in plane 2) */
+    v = get_sr(s, 3);
+    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
+    if (offset != s->font_offsets[0]) {
+        s->font_offsets[0] = offset;
+        full_update = 1;
+    }
+    font_base[0] = s->vram + offset;
+
+    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+    font_base[1] = s->vram + offset;
+    if (offset != s->font_offsets[1]) {
+        s->font_offsets[1] = offset;
+        full_update = 1;
+    }
+
+    if (test_and_clear_plane2(s)) {
+        /* if the plane 2 was modified since the last display, it
+           indicates the font may have been modified */
+        full_update = 1;
+    }
+
+    full_update |= update_basic_params(s);
+
+    line_offset = s->line_offset;
+    s1 = s->vram + (s->start_addr * 4);
+
+    /* total width & height */
+    cheight = (get_cr(s, 9) & 0x1f) + 1;
+    cw = 8;
+    if (!(get_sr(s, 1) & 0x01))
+        cw = 9;
+    if (get_sr(s, 1) & 0x08)
+        cw = 16; /* NOTE: no 18 pixel wide */
+    width = (get_cr(s, 0x01) + 1);
+    if (get_cr(s, 0x06) == 100) {
+        /* ugly hack for CGA 160x100x16 - explain me the logic */
+        height = 100;
+    } else {
+        height = get_cr(s, 0x12) |
+            ((get_cr(s, 0x07) & 0x02) << 7) |
+            ((get_cr(s, 0x07) & 0x40) << 3);
+        height = (height + 1) / cheight;
+    }
+    if ((height * width) > CH_ATTR_SIZE) {
+        /* better than nothing: exit if transient size is too big */
+        return;
+    }
+
+    if (width * cw != s->last_scr_width ||
+        height * cheight != s->last_scr_height ||
+        cw != s->last_cw ||
+        cheight != s->last_ch ||
+        s->last_depth) {
+        surface_resize(width * cw, height * cheight);
+        s->last_depth = 0;
+        s->last_width = width;
+        s->last_height = height;
+        s->last_ch = cheight;
+        s->last_cw = cw;
+        full_update = 1;
+    }
+
+    s->rgb_to_pixel = rgb_to_pixel_dup;
+    full_update |= vgpu_update_palette16(s);
+    palette = s->last_palette;
+    x_incr = cw * 4;
+    
+    cursor_offset = ((get_cr(s, 0x0e) << 8) | get_cr(s, 0x0f)) - s->start_addr;
+    if (cursor_offset != s->cursor_offset ||
+        get_cr(s, 0xa) != s->cursor_start ||
+        get_cr(s, 0xb) != s->cursor_end) {
+      /* if the cursor position changed, we update the old and new
+         chars */
+        if (s->cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[s->cursor_offset] = -1;
+        if (cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[cursor_offset] = -1;
+        s->cursor_offset = cursor_offset;
+        s->cursor_start = get_cr(s, 0xa);
+        s->cursor_end = get_cr(s, 0xb);
+    }
+    cursor_ptr = s->vram + (s->start_addr + cursor_offset) * 4;
+
+    if (cw == 16)
+        __vga_draw_glyph8 = vga_draw_glyph16;
+    else
+        __vga_draw_glyph8 = vga_draw_glyph8;
+    __vga_draw_glyph9 = vga_draw_glyph9;
+
+    dest = s->framebuffer;
+    linesize = s->linesize;
+    ch_attr_ptr = s->last_ch_attr;
+    for(cy = 0; cy < height; cy++) {
+        d1 = dest;
+        src = s1;
+        cx_min = width;
+        cx_max = -1;
+        for(cx = 0; cx < width; cx++) {
+            ch_attr = *(uint16_t *)src;
+            if (full_update || ch_attr != *ch_attr_ptr) {
+                if (cx < cx_min)
+                    cx_min = cx;
+                if (cx > cx_max)
+                    cx_max = cx;
+                *ch_attr_ptr = ch_attr;
+                ch = ch_attr & 0xff;
+                cattr = ch_attr >> 8;
+                font_ptr = font_base[(cattr >> 3) & 1];
+                font_ptr += 32 * 4 * ch;
+                bgcol = palette[cattr >> 4];
+                fgcol = palette[cattr & 0x0f];
+                if (cw != 9) {
+                    __vga_draw_glyph8(d1, linesize, font_ptr, cheight, fgcol, bgcol);
+                } else {
+                    dup9 = 0;
+                    if (ch >= 0xb0 && ch <= 0xdf && (get_ar(s, 0x10) & 0x04))
+                        dup9 = 1;
+                    __vga_draw_glyph9(d1, linesize, font_ptr, cheight, fgcol, bgcol, dup9);
+                }
+                if (src == cursor_ptr &&
+                    !(get_cr(s, 0x0a) & 0x20)) {
+                    int line_start, line_last, h;
+                    /* draw the cursor */
+                    line_start = get_cr(s, 0x0a) & 0x1f;
+                    line_last = get_cr(s, 0x0b) & 0x1f;
+                    /* XXX: check that */
+                    if (line_last > cheight - 1)
+                        line_last = cheight - 1;
+                    if (line_last >= line_start && line_start < cheight) {
+                        h = line_last - line_start + 1;
+                        d = d1 + linesize * line_start;
+                        if (cw != 9) {
+                            __vga_draw_glyph8(d, linesize, cursor_glyph, h, fgcol, bgcol);
+                        } else {
+                            __vga_draw_glyph9(d, linesize, cursor_glyph, h, fgcol, bgcol, 1);
+                        }
+                    }
+                }
+            }
+            d1 += x_incr;
+            src += 4;
+            ch_attr_ptr++;
+            if (cx_max != -1)
+                surface_update(cx_min * cw, cy * cheight,
+                               (cx_max - cx_min + 1) * cw, cheight);
+
+        }
+        dest += linesize * cheight;
+        s1 += line_offset;
+    }
+}
+
+static void
+surface_draw_graphic(surface_t *s, int full_update)
+{
+    int y1, y, update, linesize, y_start, double_scan, mask, depth;
+    int width, height, shift_control, line_offset, bwidth, bits;
+    int disp_width, multi_scan, multi_run;
+    uint8_t *d;
+    uint32_t v, addr1, addr;
+    vga_draw_line_func *__vga_draw_line;
+
+    full_update |= update_basic_params(s);
+
+    get_resolution(s, &width, &height);
+    disp_width = width;
+
+    shift_control = (get_gr(s, 0x05) >> 5) & 3;
+    double_scan = (get_cr(s, 0x09) >> 7);
+    if (shift_control != 1) {
+        multi_scan = (((get_cr(s, 0x09) & 0x1f) + 1) << double_scan) - 1;
+    } else {
+        /* in CGA modes, multi_scan is ignored */
+        multi_scan = double_scan;
+    }
+    multi_run = multi_scan;
+    if (shift_control != s->shift_control ||
+        double_scan != s->double_scan) {
+        full_update = 1;
+        s->shift_control = shift_control;
+        s->double_scan = double_scan;
+    }
+    if (shift_control == 1 && (get_sr(s, 0x01) & 8)) {
+        disp_width <<= 1;
+    }
+
+    if (shift_control == 0) {
+        if (get_sr(s, 0x01) & 8) {
+            disp_width <<= 1;
+        }
+    } else if (shift_control == 1) {
+        if (get_sr(s, 0x01) & 8) {
+            disp_width <<= 1;
+        }
+    }
+
+    depth = get_bpp(s);
+    if (s->line_offset != s->last_line_offset || 
+        disp_width != s->last_scr_width ||
+        height != s->last_scr_height ||
+        s->last_depth != depth) {
+
+        DBG("depth = %d\n", depth);
+        surface_resize(disp_width, height);
+
+        s->last_width = disp_width;
+        s->last_height = height;
+        s->last_line_offset = s->line_offset;
+        s->last_depth = depth;
+        full_update = 1;
+    }
+
+    s->rgb_to_pixel = rgb_to_pixel_dup;
+
+    if (shift_control == 0) {
+        full_update |= vgpu_update_palette16(s);
+        if (get_sr(s, 0x01) & 8) {
+            v = VGA_DRAW_LINE4D2;
+        } else {
+            v = VGA_DRAW_LINE4;
+        }
+        bits = 4;
+    } else if (shift_control == 1) {
+        full_update |= vgpu_update_palette16(s);
+        if (get_sr(s, 0x01) & 8) {
+            v = VGA_DRAW_LINE2D2;
+        } else {
+            v = VGA_DRAW_LINE2;
+        }
+        bits = 4;
+    } else {
+        switch(get_bpp(s)) {
+        default:
+        case 0:
+            full_update |= vgpu_update_palette256(s);
+            v = VGA_DRAW_LINE8D2;
+            bits = 4;
+            break;
+        case 8:
+            full_update |= vgpu_update_palette256(s);
+            v = VGA_DRAW_LINE8;
+            bits = 8;
+            break;
+        case 15:
+            v = VGA_DRAW_LINE15;
+            bits = 16;
+            break;
+        case 16:
+            v = VGA_DRAW_LINE16;
+            bits = 16;
+            break;
+        case 24:
+            v = VGA_DRAW_LINE24;
+            bits = 24;
+            break;
+        case 32:
+            v = VGA_DRAW_LINE32;
+            bits = 32;
+            break;
+        }
+    }
+
+    __vga_draw_line = vga_draw_line_table[v];
+
+    line_offset = s->line_offset;
+
+    addr1 = (s->start_addr * 4);
+    bwidth = (width * bits + 7) / 8;
+    y_start = -1;
+    d = s->framebuffer;
+    linesize = s->linesize;
+    y1 = 0;
+
+    for(y = 0; y < height; y++) {
+        addr = addr1;
+        if (!(get_cr(s, 0x17) & 1)) {
+            int shift;
+            /* CGA compatibility handling */
+            shift = 14 + ((get_cr(s, 0x17) >> 6) & 1);
+            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+        }
+        if (!(get_cr(s, 0x17) & 2)) {
+            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
+        }
+        update = full_update | device_vram_dirty(addr, bwidth);
+        /* explicit invalidation for the hardware cursor */
+        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+        if (update) {
+            uint32_t plane_enable;
+
+            if (y_start < 0)
+                y_start = y;
+
+            plane_enable = get_ar(s, 0x12) & 0xf;
+            __vga_draw_line(s->last_palette, plane_enable, d, s->vram + addr, width);
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                surface_update(0, y_start,
+                               disp_width, y - y_start);
+                y_start = -1;
+            }
+        }
+        if (!multi_run) {
+            mask = (get_cr(s, 0x17) & 3) ^ 3;
+            if ((y1 & mask) == mask)
+                addr1 += line_offset;
+            y1++;
+            multi_run = multi_scan;
+        } else {
+            multi_run--;
+        }
+        /* line compare acts on the displayed lines */
+        if (y == s->line_compare)
+            addr1 = 0;
+        d += linesize;
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        surface_update(0, y_start,
+                       disp_width, y - y_start);
+        y_start = -1;
+    }
+
+    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void
+surface_draw_blank(surface_t *s, int full_update)
+{
+    int val;
+
+    if (!full_update)
+        return;
+
+    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+        return;
+
+    s->rgb_to_pixel = rgb_to_pixel_dup;
+    val = s->rgb_to_pixel(0, 0, 0);
+
+    memset(s->framebuffer, val,
+           s->last_scr_width * s->last_scr_height * 4);
+
+    surface_update(0, 0,
+                   s->last_scr_width, s->last_scr_height);
+}
+
+void
+surface_refresh(void)
+{
+    surface_t *s = &surface_state;
+    int full_update;
+    int graphic_mode;
+
+    if (!(get_ar_index(s) & 0x20)) {
+        graphic_mode = GMODE_BLANK;
+    } else {
+        graphic_mode = get_gr(s, 6) & 1;
+    }
+
+    if (graphic_mode != s->graphic_mode) {
+        s->graphic_mode = graphic_mode;
+
+        switch(s->graphic_mode) {
+        case GMODE_TEXT:
+            DBG("text\n");
+            break;
+        case GMODE_GRAPHIC:
+            DBG("graphic\n");
+            break;
+        case GMODE_BLANK:
+        default:
+            DBG("blank\n");
+            break;
+        }
+
+        full_update = 1;
+    }
+
+    switch(graphic_mode) {
+    case GMODE_TEXT:
+        surface_draw_text(s, full_update);
+        break;
+    case GMODE_GRAPHIC:
+        surface_draw_graphic(s, full_update);
+        break;
+    case GMODE_BLANK:
+    default:
+        surface_draw_blank(s, full_update);
+        break;
+    }
+
+}
+
+void
+surface_refresh_test(void)
+{
+    surface_t       *s = &surface_state;
+    uint32_t        pixel;
+    static uint8_t  val;
+
+    if (s->last_scr_width != 640 ||
+        s->last_scr_height != 480 ||
+        s->last_depth != 32) {
+        surface_resize(640, 480);
+
+        s->last_width = 640;
+        s->last_height = 480;
+        s->last_depth = 32;
+    }
+
+    for (pixel = 0;
+         pixel < s->last_scr_width * s->last_scr_height * 4;
+         pixel += 4) {
+        s->framebuffer[pixel] = val;
+        s->framebuffer[pixel + 1] = val;
+        s->framebuffer[pixel + 2] = val;
+    }
+
+    surface_update(0, 0,
+                   s->last_scr_width, s->last_scr_height);
+
+    val++;
+}
+
+void
+surface_teardown(void)
+{
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/surface.h b/surface.h
new file mode 100644 (file)
index 0000000..45eb1fd
--- /dev/null
+++ b/surface.h
@@ -0,0 +1,50 @@
+/*  
+ * Copyright (c) 2014, Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef  _SURFACE_H
+#define  _SURFACE_H
+
+int     surface_initialize(void);
+void    surface_refresh(void);
+void    surface_refresh_test(void);
+void    surface_teardown(void);
+
+#endif  /* _SURFACE_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/template.h b/template.h
new file mode 100644 (file)
index 0000000..c6f9796
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
+
+static inline void glue(__vga_draw_glyph_line_, DEPTH)(uint8_t *d,
+                                                       uint32_t font_data,
+                                                       uint32_t xorcol,
+                                                       uint32_t bgcol)
+{
+#if BPP == 1
+        ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+        ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+static void glue(__vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
+                                            const uint8_t *font_ptr, int h,
+                                            uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(__vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(__vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
+                                             const uint8_t *font_ptr, int h,
+                                             uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(__vga_draw_glyph_line_, DEPTH)(d,
+                                            expand4to8[font_data >> 4],
+                                            xorcol, bgcol);
+        glue(__vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+                                            expand4to8[font_data & 0x0f],
+                                            xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(__vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
+                                            const uint8_t *font_ptr, int h,
+                                            uint32_t fgcol, uint32_t bgcol, int dup9)
+{
+    uint32_t font_data, xorcol, v;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+#if BPP == 1
+        cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+        v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+1, v);
+        if (dup9)
+            ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
+        else
+            ((uint8_t *)d)[8] = bgcol;
+
+#elif BPP == 2
+        cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
+        v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+3, v);
+        if (dup9)
+            ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
+        else
+            ((uint16_t *)d)[8] = bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = v;
+        if (dup9)
+            ((uint32_t *)d)[8] = v;
+        else
+            ((uint32_t *)d)[8] = bgcol;
+#endif
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+/*
+ * 4 color mode
+ */
+static void glue(__vga_draw_line2_, DEPTH)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v;
+    int x;
+
+    plane_mask = mask16[plane_enable];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+#if BPP == 1
+#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
+#elif BPP == 2
+#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
+#else
+#define PUT_PIXEL2(d, n, v) \
+((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
+#endif
+
+/*
+ * 4 color mode, dup2 horizontal
+ */
+static void glue(__vga_draw_line2d2_, DEPTH)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                             const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v;
+    int x;
+
+    plane_mask = mask16[plane_enable];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        PUT_PIXEL2(d, 0, palette[v >> 12]);
+        PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        PUT_PIXEL2(d, 4, palette[v >> 12]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode
+ */
+static void glue(__vga_draw_line4_, DEPTH)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v;
+    int x;
+
+    plane_mask = mask16[plane_enable];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
+        ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode, dup2 horizontal
+ */
+static void glue(__vga_draw_line4d2_, DEPTH)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                             const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v;
+    int x;
+
+    plane_mask = mask16[plane_enable];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        PUT_PIXEL2(d, 0, palette[v >> 28]);
+        PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
+        PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 256 color mode, double pixels
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(__vga_draw_line8d2_, DEPTH)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                             const uint8_t *s, int width)
+{
+    int x;
+
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        PUT_PIXEL2(d, 0, palette[s[0]]);
+        PUT_PIXEL2(d, 1, palette[s[1]]);
+        PUT_PIXEL2(d, 2, palette[s[2]]);
+        PUT_PIXEL2(d, 3, palette[s[3]]);
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * standard 256 color mode
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(__vga_draw_line8_, DEPTH)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    int x;
+
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        ((PIXEL_TYPE *)d)[0] = palette[s[0]];
+        ((PIXEL_TYPE *)d)[1] = palette[s[1]];
+        ((PIXEL_TYPE *)d)[2] = palette[s[2]];
+        ((PIXEL_TYPE *)d)[3] = palette[s[3]];
+        ((PIXEL_TYPE *)d)[4] = palette[s[4]];
+        ((PIXEL_TYPE *)d)[5] = palette[s[5]];
+        ((PIXEL_TYPE *)d)[6] = palette[s[6]];
+        ((PIXEL_TYPE *)d)[7] = palette[s[7]];
+        d += BPP * 8;
+        s += 8;
+    }
+}
+
+#endif /* DEPTH != 15 */
+
+
+/* XXX: optimize */
+
+/*
+ * 15 bit color
+ */
+static void glue(__vga_draw_line15_, PIXEL_NAME)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                                 const uint8_t *s, int width)
+{
+#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 7) & 0xf8;
+        g = (v >> 2) & 0xf8;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 16 bit color
+ */
+static void glue(__vga_draw_line16_, PIXEL_NAME)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                                 const uint8_t *s, int width)
+{
+#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 24 bit color
+ */
+static void glue(__vga_draw_line24_, PIXEL_NAME)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                                 const uint8_t *s, int width)
+{
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[0];
+        g = s[1];
+        b = s[2];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 3;
+        d += BPP;
+    } while (--w != 0);
+}
+
+/*
+ * 32 bit color
+ */
+static void glue(__vga_draw_line32_, PIXEL_NAME)(uint32_t *palette, uint32_t plane_enable, uint8_t *d,
+                                                 const uint8_t *s, int width)
+{
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[1];
+        g = s[2];
+        b = s[3];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 4;
+        d += BPP;
+    } while (--w != 0);
+}
+
+#undef PUT_PIXEL2
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
diff --git a/vga.h b/vga.h
index 14b17d9ba893459b76562daa78750fdf12a77f67..5702d93c712d069d68d9b71bad2d6a502c4c850b 100644 (file)
--- a/vga.h
+++ b/vga.h
@@ -1,3 +1,57 @@
+/*  
+ * Copyright (c) 2014, Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef  _VGA_H
+#define  _VGA_H
+
 #define MSR_COLOR_EMULATION 0x01
 #define MSR_PAGE_SELECT     0x20
 
@@ -74,3 +128,19 @@ typedef struct vga {
 
     uint32_t    plane_updated;
 } vga_t;
+
+#endif  /*_VGA_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-tab-always-indent: nil
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * c-basic-indent: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
+
diff --git a/vgabios-stdvga.bin b/vgabios-stdvga.bin
new file mode 100644 (file)
index 0000000..d329e24
Binary files /dev/null and b/vgabios-stdvga.bin differ