]> xenbits.xensource.com Git - people/pauldu/demu.git/commitdiff
Basic VGA device implementation
authorPaul Durrant <paul.durrant@citrix.com>
Wed, 5 Feb 2014 13:01:51 +0000 (13:01 +0000)
committerPaul Durrant <paul.durrant@citrix.com>
Wed, 5 Feb 2014 13:01:51 +0000 (13:01 +0000)
VRAM is in local memory rather than guest. No surface display as yet.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Makefile
demu.c
demu.h [new file with mode: 0644]
device.c
device.h
mapcache.c [new file with mode: 0644]
mapcache.h [new file with mode: 0644]
pci.c
pci.h
vga.h [new file with mode: 0644]

index f7bcbd4da02b77fdb436103f877db314bbad3b79..a502c5f78e7055dbdf6a606b111976af49bf0856 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@ TARGET = demu
 
 OBJS :=        device.o \
        pci.o \
+       mapcache.o \
        demu.o
 
 CFLAGS  = -I$(shell pwd)/include
@@ -14,7 +15,7 @@ ifeq ($(shell uname),Linux)
 LDLIBS := -lutil -lrt
 endif
 
-LDLIBS += -lxenstore -lxenctrl
+LDLIBS += -lxenctrl
 
 # Get gcc to generate the dependencies for us.
 CFLAGS   += -Wp,-MD,$(@D)/.$(@F).d
@@ -39,11 +40,6 @@ clean:
        rm -f $(OBJS)
        rm -f $(DEPS)
        rm -f $(TARGET)
-       rm -f TAGS
-
-.PHONY: TAGS
-TAGS:
-       find . -name \*.[ch] | etags -
 
 -include $(DEPS)
 
diff --git a/demu.c b/demu.c
index 0c49d4920dc4e94e7b5656aaa91597b4b1181a2c..37c54d191c069df4dcf2612cff6114fc9816888f 100644 (file)
--- a/demu.c
+++ b/demu.c
@@ -42,6 +42,7 @@
 #include <unistd.h>
 #include <sched.h>
 #include <assert.h>
+#include <inttypes.h>
 
 #include <sys/mman.h>
 #include <sys/poll.h>
 #include <xen/hvm/ioreq.h>
 
 #include "debug.h"
+#include "mapcache.h"
 #include "device.h"
 #include "pci.h"
+#include "demu.h"
 
 #define FALSE 0
+#define TRUE  1
 
 #define mb() asm volatile ("" : : : "memory")
 
 enum {
     DEMU_OPT_DOMAIN,
-    DEMU_OPT_VCPUS,
-    DEMU_OPT_BUS,
     DEMU_OPT_DEVICE,
-    DEMU_OPT_FUNCTION,
     DEMU_NR_OPTS
     };
 
 static struct option demu_option[] = {
     {"domain", 1, NULL, 0},
-    {"vcpus", 1, NULL, 0},
-    {"bus", 1, NULL, 0},
     {"device", 1, NULL, 0},
-    {"function", 1, NULL, 0},
     {NULL, 0, NULL, 0}
 };
 
 static const char *demu_option_text[] = {
     "<domid>",
-    "<vcpu count>",
-    "<bus>",
     "<device>",
-    "<function>",
     NULL
 };
 
@@ -127,6 +122,16 @@ typedef enum {
     DEMU_NR_SEQS
 } demu_seq_t;
 
+typedef struct demu_space demu_space_t;
+
+struct demu_space {
+    demu_space_t       *next;
+    uint64_t           start;
+    uint64_t           end;
+    const io_ops_t     *ops;
+    void                   *priv;
+};
+
 typedef struct demu_state {
     demu_seq_t          seq;
     xc_interface        *xch;
@@ -134,93 +139,465 @@ typedef struct demu_state {
     domid_t             domid;
     unsigned int        vcpus;
     ioservid_t          ioservid;
-    shared_iopage_t     *iopage;
+    shared_iopage_t     *shared_iopage;
     evtchn_port_t       *ioreq_local_port;
     buffered_iopage_t   *buffered_iopage;
     evtchn_port_t       buf_ioreq_port;
     evtchn_port_t       buf_ioreq_local_port;
+    demu_space_t           *memory;
+    demu_space_t        *port;
+    demu_space_t        *pci_config;
 } demu_state_t;
 
 static demu_state_t demu_state;
 
+void *
+demu_map_guest_pages(xen_pfn_t pfn[], unsigned int n)
+{
+    void *ptr;
+
+    ptr = xc_map_foreign_pages(demu_state.xch, demu_state.domid,
+                               PROT_READ | PROT_WRITE,
+                               pfn, n);
+    if (ptr == NULL)
+        goto fail1;
+    
+    return ptr;
+    
+fail1:
+    DBG("fail1\n");
+
+    warn("fail");
+    return NULL;
+}
+
+static demu_space_t *
+demu_find_space(demu_space_t *head, uint64_t addr)
+{
+    demu_space_t    *space;
+
+    for (space = head; space != NULL; space = space->next)
+        if (addr >= space->start && addr <= space->end)
+            return space;
+
+    return NULL;
+}
+
+static demu_space_t *
+demu_find_pci_config_space(uint8_t bdf)
+{
+    return demu_find_space(demu_state.pci_config, bdf);
+}
+
+static demu_space_t *
+demu_find_port_space(uint64_t addr)
+{
+    return demu_find_space(demu_state.port, addr);
+}
+
+static demu_space_t *
+demu_find_memory_space(uint64_t addr)
+{
+    return demu_find_space(demu_state.memory, addr);
+}
+
+static int
+demu_register_space(demu_space_t **headp, uint64_t start, uint64_t end,
+                    const io_ops_t *ops, void *priv)
+{
+    demu_space_t    *space;
+
+    if (demu_find_space(*headp, start) || demu_find_space(*headp, end))
+        goto fail1;
+
+    space = malloc(sizeof (demu_space_t));
+    if (space == NULL)
+        goto fail2;
+
+    space->start = start;
+    space->end = end;
+    space->ops = ops;
+    space->priv = priv;
+
+    space->next = *headp;
+    *headp = space;
+
+    return 0;
+
+fail2:
+    DBG("fail2\n");
+
+fail1:
+    DBG("fail1\n");
+    warn("fail");
+    return -1;
+}
+
 static void
-handle_pio(ioreq_t *ioreq)
+demu_deregister_space(demu_space_t **headp, uint64_t start)
 {
-    if (ioreq->dir == IOREQ_READ) {
-        if (!ioreq->data_is_ptr) {
-            ioreq->data = (uint64_t)pci_bar_read(0, ioreq->addr, ioreq->size);
-        } else {
-            assert(FALSE);
+    demu_space_t    **spacep;
+    demu_space_t    *space;
+
+    spacep = headp;
+    while ((space = *spacep) != NULL) {
+        if (start == space->start) {
+            *spacep = space->next;
+            free(space);
+            return;
         }
-    } else if (ioreq->dir == IOREQ_WRITE) {
-        if (!ioreq->data_is_ptr) {
-            pci_bar_write(0, ioreq->addr, ioreq->size, (uint32_t)ioreq->data);
+        spacep = &(space->next);
+    }
+    assert(FALSE);
+}
+
+int
+demu_register_pci_config_space(uint8_t bus, uint8_t device, uint8_t function,
+                               const io_ops_t *ops, void *priv)
+{
+    uint16_t    bdf;
+    int         rc;
+
+    DBG("%02x:%02x:%02x\n", bus, device, function);
+
+    bdf = (bus << 8) | (device << 3) | function;
+
+    rc = demu_register_space(&demu_state.pci_config, bdf, bdf, ops, priv);
+    if (rc < 0)
+        goto fail1;
+
+    rc = xc_hvm_map_pcidev_to_ioreq_server(demu_state.xch, demu_state.domid, demu_state.ioservid,
+                                           bdf);
+    if (rc < 0)
+        goto fail2;
+
+    return 0;
+
+fail2:
+    DBG("fail2\n");
+
+    demu_deregister_space(&demu_state.pci_config, bdf);
+
+fail1:
+    DBG("fail1\n");
+
+    warn("fail");
+    return -1;
+}
+
+int
+demu_register_port_space(uint64_t start, uint64_t size, const io_ops_t *ops, void *priv)
+{
+    int rc;
+
+    DBG("%"PRIx64" - %"PRIx64"\n", start, start + size - 1);
+
+    rc = demu_register_space(&demu_state.port, start, start + size - 1, ops, priv);
+    if (rc < 0)
+        goto fail1;
+
+    rc = xc_hvm_map_io_range_to_ioreq_server(demu_state.xch, demu_state.domid, demu_state.ioservid,
+                                             0, start, start + size - 1);
+    if (rc < 0)
+        goto fail2;
+
+    return 0;
+
+fail2:
+    DBG("fail2\n");
+
+    demu_deregister_space(&demu_state.port, start);
+
+fail1:
+    DBG("fail1\n");
+
+    warn("fail");
+    return -1;
+}
+
+int
+demu_register_memory_space(uint64_t start, uint64_t size, const io_ops_t *ops, void *priv)
+{
+    int rc;
+
+    DBG("%"PRIx64" - %"PRIx64"\n", start, start + size - 1);
+
+    rc = demu_register_space(&demu_state.memory, start, start + size - 1, ops, priv);
+    if (rc < 0)
+        goto fail1;
+
+    rc = xc_hvm_map_io_range_to_ioreq_server(demu_state.xch, demu_state.domid, demu_state.ioservid,
+                                             1, start, start + size - 1);
+    if (rc < 0)
+        goto fail2;
+
+    return 0;
+
+fail2:
+    DBG("fail2\n");
+
+    demu_deregister_space(&demu_state.memory, start);
+
+fail1:
+    DBG("fail1\n");
+
+    warn("fail");
+    return -1;
+}
+
+void
+demu_deregister_pci_config_space(uint8_t bus, uint8_t device, uint8_t function)
+{
+    uint16_t    bdf;
+
+    DBG("%02x:%02x:%02x\n", bus, device, function);
+
+    bdf = (bus << 8) | (device << 3) | function;
+
+    xc_hvm_unmap_pcidev_from_ioreq_server(demu_state.xch, demu_state.domid, demu_state.ioservid,
+                                          bdf);
+    demu_deregister_space(&demu_state.pci_config, bdf);
+}
+
+void
+demu_deregister_port_space(uint64_t start)
+{
+    DBG("%"PRIx64"\n", start);
+
+    xc_hvm_unmap_io_range_from_ioreq_server(demu_state.xch, demu_state.domid, demu_state.ioservid,
+                                            0, start);
+    demu_deregister_space(&demu_state.port, start);
+}
+
+void
+demu_deregister_memory_space(uint64_t start)
+{
+    DBG("%"PRIx64"\n", start);
+
+    xc_hvm_unmap_io_range_from_ioreq_server(demu_state.xch, demu_state.domid, demu_state.ioservid,
+                                            1, start);
+    demu_deregister_space(&demu_state.memory, start);
+}
+
+#define DEMU_IO_READ(_fn, _priv, _addr, _size, _count, _val)        \
+    do {                                                            \
+        int                    _i = 0;                                     \
+        unsigned int   _shift = 0;                                 \
+                                                                    \
+        (_val) = 0;                                                 \
+        for (_i = 0; _i < (_count); _i++)                           \
+        {                                                           \
+            (_val) |= (uint32_t)(_fn)((_priv), (_addr)) << _shift;  \
+            _shift += 8 * (_size);                                  \
+            (_addr) += (_size);                                     \
+        }                                                           \
+    } while (FALSE)
+
+static uint32_t
+demu_io_read(demu_space_t *space, uint64_t addr, uint64_t size)
+{
+    uint32_t    val = 0;
+
+    switch (size) {
+    case 1:
+        val = space->ops->readb(space->priv, addr);
+        break;
+
+    case 2:
+        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);
+        break;
+
+    case 4:
+        if (space->ops->readl == NULL) {
+            if (space->ops->readw == NULL)
+                DEMU_IO_READ(space->ops->readb, space->priv, addr, 1, 4, val);
+            else
+                DEMU_IO_READ(space->ops->readw, space->priv, addr, 2, 2, val);
         } else {
-            assert(FALSE);
+            val = space->ops->readl(space->priv, addr);
         }
+        break;
+
+    default:
+        assert(FALSE);
     }
+
+    return val;
 }
 
+#define DEMU_IO_WRITE(_fn, _priv, _addr, _size, _count, _val)   \
+    do {                                                        \
+        int                    _i = 0;                             \
+        unsigned int   _shift = 0;                             \
+                                                                \
+        for (_i = 0; _i < (_count); _i++)                       \
+        {                                                       \
+            (_fn)((_priv), (_addr), (_val) >> _shift);          \
+            _shift += 8 * (_size);                              \
+            (_addr) += (_size);                                 \
+        }                                                       \
+    } while (FALSE)
+
 static void
-handle_copy(ioreq_t *ioreq)
+demu_io_write(demu_space_t *space, uint64_t addr, uint64_t size, uint32_t val)
 {
-    if (ioreq->dir == IOREQ_READ) {
-        if (!ioreq->data_is_ptr) {
-            ioreq->data = (uint64_t)pci_bar_read(1, ioreq->addr, ioreq->size);
-        } else {
-            assert(FALSE);
-        }
-    } else if (ioreq->dir == IOREQ_WRITE) {
-        if (!ioreq->data_is_ptr) {
-            pci_bar_write(1, ioreq->addr, ioreq->size, (uint32_t)ioreq->data);
+    switch (size) {
+    case 1:
+        space->ops->writeb(space->priv, addr, val);
+        break;
+
+    case 2:
+        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);
+        break;
+
+    case 4:
+        if (space->ops->writel == NULL) {
+            if (space->ops->writew == NULL)
+                DEMU_IO_WRITE(space->ops->writeb, space->priv, addr, 1, 4, val);
+            else
+                DEMU_IO_WRITE(space->ops->writew, space->priv, addr, 2, 2, val);
         } else {
-            assert(FALSE);
+            space->ops->writel(space->priv, addr, val);
         }
+        break;
+
+    default:
+        assert(FALSE);
     }
 }
 
+static inline void
+__copy_to_guest_memory(uint64_t addr, uint64_t size, uint8_t *src)
+{
+    uint8_t *dst = mapcache_lookup(addr);
+
+    assert(((addr + size - 1) >> TARGET_PAGE_SHIFT) == (addr >> TARGET_PAGE_SHIFT));
+
+    if (dst == NULL)
+        goto fail1;
+
+    memcpy(dst, src, size);
+    return;
+
+fail1:
+    DBG("fail1\n");
+}
+
+static inline void
+__copy_from_guest_memory(uint64_t addr, uint64_t size, uint8_t *dst)
+{
+    uint8_t *src = mapcache_lookup(addr);
+
+    assert(((addr + size - 1) >> TARGET_PAGE_SHIFT) == (addr >> TARGET_PAGE_SHIFT));
+
+    if (src == NULL)
+        goto fail1;
+
+    memcpy(dst, src, size);
+    return;
+
+fail1:
+    DBG("fail1\n");
+
+    memset(dst, 0xff, size);
+}
+
 static void
-handle_pci_config(ioreq_t *ioreq)
+demu_handle_io(demu_space_t *space, ioreq_t *ioreq, int is_mmio)
 {
+    if (space == NULL)
+        goto fail1;
+
     if (ioreq->dir == IOREQ_READ) {
         if (!ioreq->data_is_ptr) {
-            ioreq->data = (uint32_t)pci_config_read(ioreq->addr, ioreq->size);
+            ioreq->data = (uint64_t)demu_io_read(space, ioreq->addr, ioreq->size);
         } else {
-            assert(FALSE);
+            int i, sign;
+
+            sign = ioreq->df ? -1 : 1;
+            for (i = 0; i < ioreq->count; i++) {
+                uint32_t    data;
+                
+                data = demu_io_read(space, ioreq->addr, ioreq->size);
+
+                __copy_to_guest_memory(ioreq->data + (sign * i * ioreq->size),
+                                       ioreq->size, (uint8_t *)&data);
+
+                if (is_mmio)
+                    ioreq->addr += sign * ioreq->size;
+            }
         }
     } else if (ioreq->dir == IOREQ_WRITE) {
         if (!ioreq->data_is_ptr) {
-            pci_config_write(ioreq->addr, ioreq->size, (uint32_t)ioreq->data);
+            demu_io_write(space, ioreq->addr, ioreq->size, (uint32_t)ioreq->data);
         } else {
-            assert(FALSE);
+            int i, sign;
+
+            sign = ioreq->df ? -1 : 1;
+            for (i = 0; i < ioreq->count; i++) {
+                uint32_t    data;
+
+                __copy_from_guest_memory(ioreq->data + (sign * i * ioreq->size),
+                                         ioreq->size, (uint8_t *)&data);
+
+                demu_io_write(space, ioreq->addr, ioreq->size, data);
+
+                if (is_mmio)
+                    ioreq->addr += sign * ioreq->size;
+            }
         }
     }
-}
 
+    return;
+
+fail1:
+    DBG("fail1\n");
+}
 static void
-handle_ioreq(ioreq_t *ioreq)
+demu_handle_ioreq(ioreq_t *ioreq)
 {
+    demu_space_t    *space;
+
     switch (ioreq->type) {
     case IOREQ_TYPE_PIO:
-        handle_pio(ioreq);
+        space = demu_find_port_space(ioreq->addr);
+        demu_handle_io(space, ioreq, FALSE);
         break;
 
     case IOREQ_TYPE_COPY:
-        handle_copy(ioreq);
+        space = demu_find_memory_space(ioreq->addr);
+        demu_handle_io(space, ioreq, TRUE);
         break;
 
-    case IOREQ_TYPE_PCI_CONFIG:
-        handle_pci_config(ioreq);
-        break;
+    case IOREQ_TYPE_PCI_CONFIG: {
+        uint16_t    bdf;
+
+        bdf = (uint16_t)(ioreq->addr >> 8);
 
+        ioreq->addr &= 0xff;
+        ioreq->addr += ioreq->size >> 16;
+        ioreq->size &= 0xffff;
+
+        space = demu_find_pci_config_space(bdf);
+        demu_handle_io(space, ioreq, FALSE);
+        break;
+    }
     case IOREQ_TYPE_TIMEOFFSET:
         break;
 
     case IOREQ_TYPE_INVALIDATE:
+        mapcache_invalidate();
         break;
 
     default:
-        DBG("UNKNOWN (%02x)", ioreq->type);
+        assert(FALSE);
         break;
     }
 }
@@ -242,7 +619,7 @@ demu_seq_next(void)
 
     case DEMU_SEQ_SHARED_IOPAGE_MAPPED:
         DBG(">SHARED_IOPAGE_MAPPED\n");
-        DBG("iopage = %p\n", demu_state.iopage);
+        DBG("shared_iopage = %p\n", demu_state.shared_iopage);
         break;
 
     case DEMU_SEQ_BUFFERED_IOPAGE_MAPPED:
@@ -265,7 +642,7 @@ demu_seq_next(void)
 
         for (i = 0; i < demu_state.vcpus; i++)
             DBG("VCPU%d: %u -> %u\n", i,
-                demu_state.iopage->vcpu_ioreq[i].vp_eport,
+                demu_state.shared_iopage->vcpu_ioreq[i].vp_eport,
                 demu_state.ioreq_local_port[i]);
 
         break;
@@ -357,7 +734,7 @@ demu_teardown(void)
     if (demu_state.seq >= DEMU_SEQ_SHARED_IOPAGE_MAPPED) {
         DBG("<SHARED_IOPAGE_MAPPED\n");
 
-        munmap(demu_state.iopage, XC_PAGE_SIZE);
+        munmap(demu_state.shared_iopage, XC_PAGE_SIZE);
 
         demu_state.seq = DEMU_SEQ_SERVER_REGISTERED;
     }
@@ -401,12 +778,11 @@ demu_sigusr1(int num)
 
     sigaction(SIGHUP, &sigusr1_handler, NULL);
 
-    pci_config_dump();
+    pci_device_dump();
 }
 
 static int
-demu_initialize(domid_t domid, unsigned int vcpus, unsigned int bus,
-                unsigned int device, unsigned int function)
+demu_initialize(domid_t domid, unsigned int bus, unsigned int device, unsigned int function)
 {
     int             rc;
     xc_dominfo_t    dominfo;
@@ -417,7 +793,6 @@ demu_initialize(domid_t domid, unsigned int vcpus, unsigned int bus,
     int             i;
 
     demu_state.domid = domid;
-    demu_state.vcpus = vcpus;
 
     demu_state.xch = xc_interface_open(NULL, NULL, 0);
     if (demu_state.xch == NULL)
@@ -429,6 +804,10 @@ demu_initialize(domid_t domid, unsigned int vcpus, unsigned int bus,
     if (rc < 0 || dominfo.domid != demu_state.domid)
         goto fail2;
 
+    demu_state.vcpus = dominfo.max_vcpu_id + 1;
+
+    DBG("%d vCPU(s)\n", demu_state.vcpus);
+
     rc = xc_hvm_create_ioreq_server(demu_state.xch, demu_state.domid, &demu_state.ioservid);
     if (rc < 0)
         goto fail3;
@@ -440,12 +819,12 @@ demu_initialize(domid_t domid, unsigned int vcpus, unsigned int bus,
     if (rc < 0)
         goto fail4;
 
-    demu_state.iopage = xc_map_foreign_range(demu_state.xch,
-                                             demu_state.domid,
-                                             XC_PAGE_SIZE,
-                                             PROT_READ | PROT_WRITE,
-                                             pfn);
-    if (demu_state.iopage == NULL)
+    demu_state.shared_iopage = xc_map_foreign_range(demu_state.xch,
+                                                    demu_state.domid,
+                                                    XC_PAGE_SIZE,
+                                                    PROT_READ | PROT_WRITE,
+                                                    pfn);
+    if (demu_state.shared_iopage == NULL)
         goto fail5;
 
     demu_seq_next();
@@ -477,7 +856,7 @@ demu_initialize(domid_t domid, unsigned int vcpus, unsigned int bus,
     demu_seq_next();
 
     for (i = 0; i < demu_state.vcpus; i++) {
-        port = demu_state.iopage->vcpu_ioreq[i].vp_eport;
+        port = demu_state.shared_iopage->vcpu_ioreq[i].vp_eport;
 
         rc = xc_evtchn_bind_interdomain(demu_state.xceh, demu_state.domid,
                                         port);
@@ -498,8 +877,7 @@ demu_initialize(domid_t domid, unsigned int vcpus, unsigned int bus,
 
     demu_seq_next();
 
-    rc = device_initialize(demu_state.xch, demu_state.domid,
-                           demu_state.ioservid, bus, device, function);
+    rc = device_initialize(bus, device, function, 0x01000000);
     if (rc < 0)
         goto fail11;
 
@@ -557,6 +935,7 @@ demu_poll_buffered_iopage(void)
         
         read_pointer = demu_state.buffered_iopage->read_pointer;
         write_pointer = demu_state.buffered_iopage->write_pointer;
+        mb();
 
         if (read_pointer == write_pointer)
             break;
@@ -591,7 +970,7 @@ demu_poll_buffered_iopage(void)
                 read_pointer++;
             }
 
-            handle_ioreq(&ioreq);
+            demu_handle_ioreq(&ioreq);
             mb();
         }
 
@@ -601,23 +980,19 @@ demu_poll_buffered_iopage(void)
 }
 
 static void
-demu_poll_iopage(unsigned int i)
+demu_poll_shared_iopage(unsigned int i)
 {
-    ioreq_t         *ioreq;
+    ioreq_t *ioreq;
 
-    if (demu_state.seq != DEMU_SEQ_INITIALIZED)
+    ioreq = &demu_state.shared_iopage->vcpu_ioreq[i];
+    if (ioreq->state != STATE_IOREQ_READY)
         return;
 
-    ioreq = &demu_state.iopage->vcpu_ioreq[i];
-    if (ioreq->state != STATE_IOREQ_READY) {
-        fprintf(stderr, "IO request not ready\n");
-        return;
-    }
     mb();
 
     ioreq->state = STATE_IOREQ_INPROCESS;
 
-    handle_ioreq(ioreq);
+    demu_handle_ioreq(ioreq);
     mb();
 
     ioreq->state = STATE_IORESP_READY;
@@ -646,7 +1021,7 @@ demu_poll_iopages(void)
         for (i = 0; i < demu_state.vcpus; i++) {
             if (port == demu_state.ioreq_local_port[i]) {
                 xc_evtchn_unmask(demu_state.xceh, port);
-                demu_poll_iopage(i);
+                demu_poll_shared_iopage(i);
             }
         }
     }
@@ -656,17 +1031,11 @@ int
 main(int argc, char **argv, char **envp)
 {
     char            *domain_str;
-    char            *vcpus_str;
-    char            *bus_str;
     char            *device_str;
-    char            *function_str;
     int             index;
     char            *end;
     domid_t         domid;
-    unsigned int    vcpus;
-    unsigned int    bus;
     unsigned int    device;
-    unsigned int    function;
     sigset_t        block;
     struct pollfd   pfd;
     int             rc;
@@ -674,10 +1043,7 @@ main(int argc, char **argv, char **envp)
     prog = basename(argv[0]);
 
     domain_str = NULL;
-    vcpus_str = NULL;
-    bus_str = NULL;
     device_str = NULL;
-    function_str = NULL;
 
     for (;;) {
         char    c;
@@ -694,22 +1060,10 @@ main(int argc, char **argv, char **envp)
             domain_str = optarg;
             break;
 
-        case DEMU_OPT_VCPUS:
-            vcpus_str = optarg;
-            break;
-
-        case DEMU_OPT_BUS:
-            bus_str = optarg;
-            break;
-
         case DEMU_OPT_DEVICE:
             device_str = optarg;
             break;
 
-        case DEMU_OPT_FUNCTION:
-            function_str = optarg;
-            break;
-
         default:
             assert(FALSE);
             break;
@@ -717,10 +1071,7 @@ main(int argc, char **argv, char **envp)
     }
 
     if (domain_str == NULL ||
-        vcpus_str == NULL ||
-        bus_str == NULL ||
-        device_str == NULL ||
-        function_str == NULL) {
+        device_str == NULL) {
         usage();
         /*NOTREACHED*/
     }
@@ -731,27 +1082,9 @@ main(int argc, char **argv, char **envp)
         exit(1);
     }
 
-    vcpus = (unsigned int)strtol(vcpus_str, &end, 0);
-    if (*end != '\0') {
-        fprintf(stderr, "invalid vcpu count '%s'\n", vcpus_str);
-        exit(1);
-    }
-
-    bus = (unsigned int)strtol(bus_str, &end, 0);
-    if (*end != '\0') {
-        fprintf(stderr, "invalid bus '%s'\n", bus_str);
-        exit(1);
-    }
-
     device = (unsigned int)strtol(device_str, &end, 0);
     if (*end != '\0') {
-        fprintf(stderr, "invalid vcpu count '%s'\n", device_str);
-        exit(1);
-    }
-
-    function = (unsigned int)strtol(function_str, &end, 0);
-    if (*end != '\0') {
-        fprintf(stderr, "invalid vcpu count '%s'\n", function_str);
+        fprintf(stderr, "invalid device '%s'\n", device_str);
         exit(1);
     }
 
@@ -780,7 +1113,7 @@ main(int argc, char **argv, char **envp)
 
     sigprocmask(SIG_BLOCK, &block, NULL);
 
-    rc = demu_initialize(domid, vcpus, bus, device, function);
+    rc = demu_initialize(domid, 0, device, 0);
     if (rc < 0) {
         demu_teardown();
         exit(1);
diff --git a/demu.h b/demu.h
new file mode 100644 (file)
index 0000000..451ac54
--- /dev/null
+++ b/demu.h
@@ -0,0 +1,63 @@
+/*  
+ * Copyright (c) 2012, 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  _DEMU_H
+#define  _DEMU_H
+
+#define TARGET_PAGE_SHIFT   12
+#define TARGET_PAGE_SIZE    (1 << TARGET_PAGE_SHIFT)
+
+void    *demu_map_guest_pages(xen_pfn_t pfn[], unsigned int n);
+
+static inline void *demu_map_guest_page(xen_pfn_t pfn)
+{
+       return demu_map_guest_pages(&pfn, 1);
+}
+
+typedef struct io_ops {
+        uint8_t         (*readb)(void *priv, uint64_t addr);
+        uint16_t        (*readw)(void *priv, uint64_t addr);
+        uint32_t        (*readl)(void *priv, uint64_t addr);
+        void            (*writeb)(void *priv, uint64_t addr, uint8_t val);
+        void            (*writew)(void *priv, uint64_t addr, uint16_t val);
+        void            (*writel)(void *priv, uint64_t addr, uint32_t val);
+} io_ops_t;
+
+int demu_register_pci_config_space(uint8_t bus, uint8_t device, uint8_t function,
+                                   const io_ops_t *ops, void *priv);
+int demu_register_port_space(uint64_t start, uint64_t size,
+                             const io_ops_t *ops, void *priv);
+int demu_register_memory_space(uint64_t start, uint64_t size,
+                               const io_ops_t *ops, void *priv);
+
+void demu_deregister_pci_config_space(uint8_t bus, uint8_t device, uint8_t function);
+void demu_deregister_port_space(uint64_t start);
+void demu_deregister_memory_space(uint64_t start);
+
+#endif  /* _DEMU_H */
index 5cc2df518a67bad6e6cb823ea48583dc0f5c2243..cd03d0c4b7f5c6d70a71fbb80e57e87ff22ef026 100644 (file)
--- a/device.c
+++ b/device.c
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <inttypes.h>
 #include <assert.h>
 
 #include <sys/types.h>
+#include <sys/mman.h>
 
 #include <xenctrl.h>
 
 #include "debug.h"
 #include "pci.h"
 #include "device.h"
+#include "demu.h"
+#include "mapcache.h"
+#include "vga.h"
 
 #define FALSE 0
 
-typedef struct _device_io_state {
-    unsigned int    index;
-    unsigned int    order;
-} device_io_state_t;
+#define DEBUG_VGA_MEMORY 0
 
-static  device_io_state_t   device_io_state;
+/* force some bits to zero */
+static const uint8_t __sr_mask[8] = {
+    (uint8_t)~0xfc,
+    (uint8_t)~0xc2,
+    (uint8_t)~0xf0,
+    (uint8_t)~0xc0,
+    (uint8_t)~0xf1,
+    (uint8_t)~0xff,
+    (uint8_t)~0xff,
+    (uint8_t)~0x00,
+};
+
+static const uint8_t __gr_mask[16] = {
+    (uint8_t)~0xf0, /* 0x00 */
+    (uint8_t)~0xf0, /* 0x01 */
+    (uint8_t)~0xf0, /* 0x02 */
+    (uint8_t)~0xe0, /* 0x03 */
+    (uint8_t)~0xfc, /* 0x04 */
+    (uint8_t)~0x84, /* 0x05 */
+    (uint8_t)~0xf0, /* 0x06 */
+    (uint8_t)~0xf0, /* 0x07 */
+    (uint8_t)~0x00, /* 0x08 */
+    (uint8_t)~0xff, /* 0x09 */
+    (uint8_t)~0xff, /* 0x0a */
+    (uint8_t)~0xff, /* 0x0b */
+    (uint8_t)~0xff, /* 0x0c */
+    (uint8_t)~0xff, /* 0x0d */
+    (uint8_t)~0xff, /* 0x0e */
+    (uint8_t)~0xff, /* 0x0f */
+};
+
+#define PAT(x) (x)
+
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+
+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
+
+typedef struct device {
+    uint64_t        vram_size;
+    uint8_t         *vram;
+    vga_t           vga;
+} device_t;
+
+static  device_t   device_state;
 
 static void
-device_io_map(void *priv, uint64_t addr)
+device_vga_bios_init(void)
 {
-    device_io_state_t   *state = priv;
+    vga_t   *vga = &device_state.vga;
+
+    uint8_t palette_model[192] = {
+        0,   0,   0,   0,   0, 170,   0, 170,
+        0,   0, 170, 170, 170,   0,   0, 170,
+        0, 170, 170,  85,   0, 170, 170, 170,
+       85,  85,  85,  85,  85, 255,  85, 255,
+       85,  85, 255, 255, 255,  85,  85, 255,
+       85, 255, 255, 255,  85, 255, 255, 255,
+        0,  21,   0,   0,  21,  42,   0,  63,
+        0,   0,  63,  42,  42,  21,   0,  42,
+       21,  42,  42,  63,   0,  42,  63,  42,
+        0,  21,  21,   0,  21,  63,   0,  63,
+       21,   0,  63,  63,  42,  21,  21,  42,
+       21,  63,  42,  63,  21,  42,  63,  63,
+       21,   0,   0,  21,   0,  42,  21,  42,
+        0,  21,  42,  42,  63,   0,   0,  63,
+        0,  42,  63,  42,   0,  63,  42,  42,
+       21,   0,  21,  21,   0,  63,  21,  42,
+       21,  21,  42,  63,  63,   0,  21,  63,
+        0,  63,  63,  42,  21,  63,  42,  63,
+       21,  21,   0,  21,  21,  42,  21,  63,
+        0,  21,  63,  42,  63,  21,   0,  63,
+       21,  42,  63,  63,   0,  63,  63,  42,
+       21,  21,  21,  21,  21,  63,  21,  63,
+       21,  21,  63,  63,  63,  21,  21,  63,
+       21,  63,  63,  63,  21,  63,  63,  63
+    };
+
+    vga->latch = 0;
 
-    DBG("%d: %016"PRIx64" - %016"PRIx64"\n",
-        state->index,
-        addr,
-        addr + (1 << state->order) - 1);
+    vga->sr_index = 3;
+    vga->sr[0] = 3;
+    vga->sr[1] = 0;
+    vga->sr[2] = 3;
+    vga->sr[3] = 0;
+    vga->sr[4] = 2;
+    vga->sr[5] = 0;
+    vga->sr[6] = 0;
+    vga->sr[7] = 0;
+
+    vga->gr_index = 5;
+    vga->gr[0] = 0;
+    vga->gr[1] = 0;
+    vga->gr[2] = 0;
+    vga->gr[3] = 0;
+    vga->gr[4] = 0;
+    vga->gr[5] = 16;
+    vga->gr[6] = 14;
+    vga->gr[7] = 15;
+    vga->gr[8] = 255;
+
+    /* changed by out 0x03c0 */
+    vga->ar_index = 32;
+    vga->ar[0] = 0;
+    vga->ar[1] = 1;
+    vga->ar[2] = 2;
+    vga->ar[3] = 3;
+    vga->ar[4] = 4;
+    vga->ar[5] = 5;
+    vga->ar[6] = 6;
+    vga->ar[7] = 7;
+    vga->ar[8] = 8;
+    vga->ar[9] = 9;
+    vga->ar[10] = 10;
+    vga->ar[11] = 11;
+    vga->ar[12] = 12;
+    vga->ar[13] = 13;
+    vga->ar[14] = 14;
+    vga->ar[15] = 15;
+    vga->ar[16] = 12;
+    vga->ar[17] = 0;
+    vga->ar[18] = 15;
+    vga->ar[19] = 8;
+    vga->ar[20] = 0;
+
+    vga->ar_flip_flop = 1;
+
+    vga->cr_index = 15;
+    vga->cr[0] = 95;
+    vga->cr[1] = 79;
+    vga->cr[2] = 80;
+    vga->cr[3] = 130;
+    vga->cr[4] = 85;
+    vga->cr[5] = 129;
+    vga->cr[6] = 191;
+    vga->cr[7] = 31;
+    vga->cr[8] = 0;
+    vga->cr[9] = 79;
+    vga->cr[10] = 14;
+    vga->cr[11] = 15;
+    vga->cr[12] = 0;
+    vga->cr[13] = 0;
+    vga->cr[14] = 5;
+    vga->cr[15] = 160;
+    vga->cr[16] = 156;
+    vga->cr[17] = 142;
+    vga->cr[18] = 143;
+    vga->cr[19] = 40;
+    vga->cr[20] = 31;
+    vga->cr[21] = 150;
+    vga->cr[22] = 185;
+    vga->cr[23] = 163;
+    vga->cr[24] = 255;
+
+    vga->msr = 103;
+    vga->fcr = 0;
+    vga->st00 = 0;
+    vga->st01 = 0;
+
+    /* dac_* & palette will be initialized by os through out 0x03c8 &
+     * out 0c03c9(1:3) */
+    vga->dac_state = 0;
+    vga->dac_sub_index = 0;
+    vga->dac_read_index = 0;
+    vga->dac_write_index = 16;
+    vga->dac_cache[0] = 255;
+    vga->dac_cache[1] = 255;
+    vga->dac_cache[2] = 255;
+
+    /* palette */
+    memcpy(vga->palette, palette_model, 192);
+
+    vga->bank_offset = 0;
 }
 
 static void
-device_io_unmap(void *priv)
+device_vga_reset(void)
 {
-    device_io_state_t   *state = priv;
+    vga_t   *vga = &device_state.vga;
+
+    vga->lfb_addr = 0;
+    vga->lfb_size = 0;
+    vga->sr_index = 0;
+    memset(vga->sr, '\0', sizeof(vga->sr));
+    vga->gr_index = 0;
+    memset(vga->gr, '\0', sizeof(vga->gr));
+    vga->ar_index = 0;
+    memset(vga->ar, '\0', sizeof(vga->ar));
+    vga->ar_flip_flop = 0;
+    vga->cr_index = 0;
+    memset(vga->cr, '\0', sizeof(vga->cr));
+    vga->msr = 0;
+    vga->fcr = 0;
+    vga->st00 = 0;
+    vga->st01 = 0;
+    vga->dac_state = 0;
+    vga->dac_sub_index = 0;
+    vga->dac_read_index = 0;
+    vga->dac_write_index = 0;
+    memset(vga->dac_cache, '\0', sizeof(vga->dac_cache));
+    vga->dac_8bit = 0;
+    memset(vga->palette, '\0', sizeof(vga->palette));
+    vga->bank_offset = 0;
+    vga->vbe_index = 0;
+    memset(vga->vbe_regs, '\0', sizeof(vga->vbe_regs));
+    vga->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
+    vga->vbe_start_addr = 0;
+    vga->vbe_line_offset = 0;
+    vga->vbe_bank_mask = (device_state.vram_size >> 16) - 1;
+    vga->plane_updated = 0;
 
-    DBG("%d\n", state->index);
+    device_vga_bios_init();
 }
 
 static uint8_t
-device_io_readb(void *priv, uint64_t offset)
+device_vga_port_readb(void *priv, uint64_t addr)
 {
-    return 0;
+    vga_t   *vga = &device_state.vga;
+    uint8_t index;
+    uint8_t val;
+
+    assert(priv == NULL);
+
+    /* 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))) {
+        val = 0xff;
+    } else {
+        switch(addr) {
+        case 0x3c0:
+            if (vga->ar_flip_flop == 0) {
+                val = vga->ar_index;
+            } else {
+                val = 0;
+            }
+            break;
+        case 0x3c1:
+            index = vga->ar_index & 0x1f;
+            if (index < 21)
+                val = vga->ar[index];
+            else
+                val = 0;
+            break;
+        case 0x3c2:
+            val = vga->st00;
+            break;
+        case 0x3c4:
+            val = vga->sr_index;
+            break;
+        case 0x3c5:
+            val = vga->sr[vga->sr_index];
+            break;
+        case 0x3c7:
+            val = vga->dac_state;
+            break;
+       case 0x3c8:
+           val = vga->dac_write_index;
+           break;
+        case 0x3c9:
+            val = vga->palette[vga->dac_read_index * 3 + vga->dac_sub_index];
+            if (++vga->dac_sub_index == 3) {
+                vga->dac_sub_index = 0;
+                vga->dac_read_index++;
+            }
+            break;
+        case 0x3ca:
+            val = vga->fcr;
+            break;
+        case 0x3cc:
+            val = vga->msr;
+            break;
+        case 0x3ce:
+            val = vga->gr_index;
+            break;
+        case 0x3cf:
+            val = vga->gr[vga->gr_index];
+            break;
+        case 0x3b4:
+        case 0x3d4:
+            val = vga->cr_index;
+            break;
+        case 0x3b5:
+        case 0x3d5:
+            val = vga->cr[vga->cr_index];
+            break;
+        case 0x3ba:
+        case 0x3da:
+            /* just toggle to fool polling */
+            vga->st01 ^= (ST01_V_RETRACE | ST01_DISP_ENABLE);
+            val = vga->st01;
+            vga->ar_flip_flop = 0;
+            break;
+        default:
+            val = 0x00;
+            break;
+        }
+    }
+
+    return val;
 }
 
 static void
-device_io_writeb(void *priv, uint64_t offset, uint8_t val)
+device_vga_port_writeb(void *priv, uint64_t addr, uint8_t val)
 {
+    vga_t   *vga = &device_state.vga;
+    uint8_t index;
+
+    assert(priv == NULL);
+
+    /* 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)))
+        return;
+
+    switch(addr) {
+    case 0x3c0:
+        if (vga->ar_flip_flop == 0) {
+            val &= 0x3f;
+            vga->ar_index = val;
+        } else {
+            index = vga->ar_index & 0x1f;
+            switch(index) {
+            case 0x00 ... 0x0f:
+                vga->ar[index] = val & 0x3f;
+                break;
+            case 0x10:
+                vga->ar[index] = val & ~0x10;
+                break;
+            case 0x11:
+                vga->ar[index] = val;
+                break;
+            case 0x12:
+                vga->ar[index] = val & ~0xc0;
+                break;
+            case 0x13:
+                vga->ar[index] = val & ~0xf0;
+                break;
+            case 0x14:
+                vga->ar[index] = val & ~0xf0;
+                break;
+            default:
+                break;
+            }
+        }
+        vga->ar_flip_flop ^= 1;
+        break;
+    case 0x3c2:
+        vga->msr = val & ~0x10;
+        break;
+    case 0x3c4:
+        vga->sr_index = val & 7;
+        break;
+    case 0x3c5:
+        vga->sr[vga->sr_index] = val & __sr_mask[vga->sr_index];
+        break;
+    case 0x3c7:
+        vga->dac_read_index = val;
+        vga->dac_sub_index = 0;
+        vga->dac_state = 3;
+        break;
+    case 0x3c8:
+        vga->dac_write_index = val;
+        vga->dac_sub_index = 0;
+        vga->dac_state = 0;
+        break;
+    case 0x3c9:
+        vga->dac_cache[vga->dac_sub_index] = val;
+        if (++vga->dac_sub_index == 3) {
+            memcpy(&vga->palette[vga->dac_write_index * 3], vga->dac_cache, 3);
+            vga->dac_sub_index = 0;
+            vga->dac_write_index++;
+        }
+        break;
+    case 0x3ce:
+        vga->gr_index = val & 0x0f;
+        break;
+    case 0x3cf:
+        vga->gr[vga->gr_index] = val & __gr_mask[vga->gr_index];
+        break;
+    case 0x3b4:
+    case 0x3d4:
+        vga->cr_index = val;
+        break;
+    case 0x3b5:
+    case 0x3d5:
+        /* handle CR0-7 protection */
+        if ((vga->cr[0x11] & 0x80) && vga->cr_index <= 7) {
+            /* can always write bit 4 of CR7 */
+            if (vga->cr_index == 7)
+                vga->cr[7] = (vga->cr[7] & ~0x10) | (val & 0x10);
+            return;
+        }
+        switch(vga->cr_index) {
+        case 0x01: /* horizontal display end */
+        case 0x07:
+        case 0x09:
+        case 0x0c:
+        case 0x0d:
+        case 0x12: /* vertical display end */
+            vga->cr[vga->cr_index] = val;
+            break;
+        default:
+            vga->cr[vga->cr_index] = val;
+            break;
+        }
+
+        break;
+    case 0x3ba:
+    case 0x3da:
+        vga->fcr = val & 0x10;
+        break;
+    }
 }
 
-static bar_ops_t    device_io_ops = {
-    .map = device_io_map,
-    .unmap = device_io_unmap,
-    .readb = device_io_readb,
-    .writeb = device_io_writeb
+static io_ops_t device_vga_port_ops  = {
+    .readb = device_vga_port_readb,
+    .writeb = device_vga_port_writeb
 };
 
-typedef struct _device_memory_state {
-    unsigned int    index;
-    unsigned int    order;
-} device_memory_state_t;
+static void
+__copy_from_vram(uint64_t addr, uint8_t *dst, uint64_t size)
+{
+    memcpy(dst, &device_state.vram[addr], size);
+}
+
+static uint8_t
+device_vga_memory_readb(void *priv, uint64_t addr)
+{
+    vga_t   *vga = &device_state.vga;
+    uint8_t memory_map_mode;
+    uint8_t plane;
+    uint8_t val;
+
+    assert(priv == NULL);
 
-static  device_memory_state_t   device_memory_state;
+    /* convert to VGA memory offset */
+    memory_map_mode = (vga->gr[6] >> 2) & 3;
+    addr &= 0x1ffff;
+
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return 0xff;
+        addr += vga->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    }
+
+    if (vga->sr[4] & 0x08) {
+        /* chain 4 mode : simplest access */
+        __copy_from_vram(addr, &val, 1);
+    } else if (vga->gr[5] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (vga->gr[4] & 2) | (addr & 1);
+        __copy_from_vram(((addr & ~1) << 1) | plane, &val, 1);
+    } else {
+        /* standard VGA latched access */
+        __copy_from_vram(addr << 2, (uint8_t *)&vga->latch, 4);
+
+        if (!(vga->gr[5] & 0x08)) {
+            /* read mode 0 */
+            plane = vga->gr[4];
+            val = GET_PLANE(vga->latch, plane);
+        } else {
+            uint32_t    tmp;
+            /* read mode 1 */
+            tmp = (vga->latch ^ mask16[vga->gr[2]]) & mask16[vga->gr[7]];
+            tmp |= tmp >> 16;
+            tmp |= tmp >> 8;
+            val = (~tmp) & 0xff;
+        }
+    }
+
+    return val;
+}
+
+static void
+__copy_to_vram(uint8_t *src, uint64_t addr, uint64_t size)
+{
+    memcpy(&device_state.vram[addr], src, size);
+}
 
 static void
-device_memory_map(void *priv, uint64_t addr)
+device_vga_memory_writeb(void *priv, uint64_t addr, uint8_t val)
 {
-    device_memory_state_t   *state = priv;
+    vga_t   *vga = &device_state.vga;
+    uint8_t memory_map_mode;
+    uint8_t plane;
+    uint8_t mask;
+
+    assert(priv == NULL);
+
+#if  DEBUG_VGA_MEMORY
+    DBG("[0x%llx] = 0x%02x\n", addr, val);
+#endif
+
+    /* convert to VGA memory offset */
+    memory_map_mode = (vga->gr[6] >> 2) & 3;
+    addr &= 0x1ffff;
 
-    DBG("%d: %016"PRIx64" - %016"PRIx64"\n",
-        state->index,
-        addr,
-        addr + (1 << state->order) - 1);
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return;
+        addr += vga->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    }
+
+    if (vga->sr[4] & 0x08) {
+        /* chain 4 mode : simplest access */
+        plane = addr & 3;
+        mask = (1 << plane);
+        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);
+#endif
+            vga->plane_updated |= mask; /* only used to detect font change */
+
+        }
+    } else if (vga->gr[5] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (vga->gr[4] & 2) | (addr & 1);
+        mask = (1 << plane);
+        if (vga->sr[2] & mask) {
+            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);
+#endif
+            vga->plane_updated |= mask; /* only used to detect font change */
+        }
+    } else {
+        uint8_t     write_mode;
+        uint8_t     func_select;
+        uint8_t     b;
+        uint32_t    write_mask;
+        uint32_t    bit_mask;
+        uint32_t    set_mask;
+        uint32_t    write_val;
+        uint32_t    tmp;
+
+        write_val = val;
+
+        /* standard VGA latched access */
+        write_mode = vga->gr[5] & 3;
+        switch(write_mode) {
+        default:
+        case 0:
+            /* rotate */
+            b = vga->gr[3] & 7;
+            write_val = ((write_val >> b) | (write_val << (8 - b))) & 0xff;
+            write_val |= write_val << 8;
+            write_val |= write_val << 16;
+
+            /* apply set/reset mask */
+            set_mask = mask16[vga->gr[1]];
+            write_val = (write_val & ~set_mask) | (mask16[vga->gr[0]] & set_mask);
+            bit_mask = vga->gr[8];
+            break;
+        case 1:
+            write_val = vga->latch;
+            goto do_write;
+        case 2:
+            write_val = mask16[write_val & 0x0f];
+            bit_mask = vga->gr[8];
+            break;
+        case 3:
+            /* rotate */
+            b = vga->gr[3] & 7;
+            write_val = (write_val >> b) | (write_val << (8 - b));
+
+            bit_mask = vga->gr[8] & write_val;
+            write_val = mask16[vga->gr[0]];
+            break;
+        }
+
+        /* apply logical operation */
+        func_select = vga->gr[3] >> 3;
+        switch(func_select) {
+        case 0:
+        default:
+            /* nothing to do */
+            break;
+        case 1:
+            /* and */
+            write_val &= vga->latch;
+            break;
+        case 2:
+            /* or */
+            write_val |= vga->latch;
+            break;
+        case 3:
+            /* xor */
+            write_val ^= vga->latch;
+            break;
+        }
+
+        /* apply bit mask */
+        bit_mask |= bit_mask << 8;
+        bit_mask |= bit_mask << 16;
+        write_val = (write_val & bit_mask) | (vga->latch & ~bit_mask);
+
+    do_write:
+        /* mask data according to sr[2] */
+        mask = vga->sr[2];
+        vga->plane_updated |= mask; /* only used to detect font change */
+        write_mask = mask16[mask];
+
+        __copy_from_vram(addr << 2, (uint8_t *)&tmp, 4);
+        tmp &= ~write_mask;
+        tmp |= write_val & write_mask;
+        __copy_to_vram((uint8_t *)&tmp, addr << 2, 4);
+
+#if  DEBUG_VGA_MEMORY
+        DBG("latch: [0x%llx] val=0x%08x\n", addr << 2, tmp);
+#endif
+
+    }
+}
+
+static io_ops_t device_vga_memory_ops = {
+    .readb = device_vga_memory_readb,
+    .writeb = device_vga_memory_writeb
+};
+
+static uint16_t
+device_vbe_index_read(void *priv)
+{
+    vga_t   *vga = &device_state.vga;
+
+    return vga->vbe_index;
+}
+
+static uint16_t
+device_vbe_data_read(void *priv)
+{
+    vga_t       *vga = &device_state.vga;
+    uint16_t    val;
+
+    if (vga->vbe_index <= VBE_DISPI_INDEX_NB) {
+        if (vga->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
+            switch(vga->vbe_index) {
+            case VBE_DISPI_INDEX_XRES:
+                val = VBE_DISPI_MAX_XRES;
+                break;
+            case VBE_DISPI_INDEX_YRES:
+                val = VBE_DISPI_MAX_YRES;
+                break;
+            case VBE_DISPI_INDEX_BPP:
+                val = VBE_DISPI_MAX_BPP;
+                break;
+            default:
+                val = vga->vbe_regs[vga->vbe_index];
+                break;
+            }
+        } else {
+            val = vga->vbe_regs[vga->vbe_index];
+        }
+    } else {
+        val = 0;
+    }
+
+    return val;
+}
+
+static uint16_t
+device_vbe_port_readw(void *priv, uint64_t addr)
+{
+    uint16_t val;
+
+    assert(priv == NULL);
+
+    switch (addr) {
+    case 0x1ce:
+    case 0xff80:
+        val = device_vbe_index_read(priv);
+        break;
+
+    case 0x1cf:
+    case 0xff81:
+        val = device_vbe_data_read(priv);
+        break;
+
+    default:
+        assert(FALSE);
+        val = 0xff;
+        break;
+    }
+
+    return val;
 }
 
 static void
-device_memory_unmap(void *priv)
+device_vbe_index_write(void *priv, uint16_t val)
 {
-    device_memory_state_t   *state = priv;
+    vga_t   *vga = &device_state.vga;
+
+    assert(priv == NULL);
 
-    DBG("%d\n", state->index);
+    vga->vbe_index = val;
 }
 
-static uint8_t
-device_memory_readb(void *priv, uint64_t offset)
+static void
+device_vbe_data_write(void *priv, uint16_t val)
 {
+    vga_t   *vga = &device_state.vga;
+
+    assert(priv == NULL);
+
+    if (vga->vbe_index <= VBE_DISPI_INDEX_NB) {
+        switch(vga->vbe_index) {
+        case VBE_DISPI_INDEX_ID:
+            if (val == VBE_DISPI_ID0 ||
+                val == VBE_DISPI_ID1 ||
+                val == VBE_DISPI_ID2 ||
+                val == VBE_DISPI_ID3 ||
+                val == VBE_DISPI_ID4) {
+                vga->vbe_regs[vga->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_XRES:
+            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
+                vga->vbe_regs[vga->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_YRES:
+            if (val <= VBE_DISPI_MAX_YRES) {
+                vga->vbe_regs[vga->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BPP:
+            if (val == 0)
+                val = 8;
+            if (val == 4 || val == 8 || val == 15 ||
+                val == 16 || val == 24 || val == 32) {
+                vga->vbe_regs[vga->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BANK:
+            if (vga->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+              val &= (vga->vbe_bank_mask >> 2);
+            } else {
+              val &= vga->vbe_bank_mask;
+            }
+            vga->vbe_regs[vga->vbe_index] = val;
+            vga->bank_offset = (val << 16);
+            break;
+        case VBE_DISPI_INDEX_ENABLE:
+            if ((val & VBE_DISPI_ENABLED) &&
+                !(vga->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+                int h, shift_control;
+                
+                vga->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
+                    vga->vbe_regs[VBE_DISPI_INDEX_XRES];
+                vga->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
+                    vga->vbe_regs[VBE_DISPI_INDEX_YRES];
+                vga->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
+                vga->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
+
+                if (vga->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    vga->vbe_line_offset = vga->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
+                else
+                    vga->vbe_line_offset = vga->vbe_regs[VBE_DISPI_INDEX_XRES] *
+                        ((vga->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                vga->vbe_start_addr = 0;
+
+                /* clear the screen (should be done in BIOS) */
+                if (!(val & VBE_DISPI_NOCLEARMEM)) {
+                    memset(device_state.vram, 0,
+                           vga->vbe_regs[VBE_DISPI_INDEX_YRES] * vga->vbe_line_offset);
+                }
+
+                /* we initialize the VGA graphic mode (should be done
+                   in BIOS) */
+                vga->gr[0x06] = (vga->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
+                vga->cr[0x17] |= 3; /* no CGA modes */
+                vga->cr[0x13] = vga->vbe_line_offset >> 3;
+                /* width */
+                vga->cr[0x01] = (vga->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+                /* height (only meaningful if < 1024) */
+                h = vga->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+                vga->cr[0x12] = h;
+                vga->cr[0x07] = (vga->cr[0x07] & ~0x42) |
+                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+                /* line compare to 1023 */
+                vga->cr[0x18] = 0xff;
+                vga->cr[0x07] |= 0x10;
+                vga->cr[0x09] |= 0x40;
+
+                if (vga->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+                    shift_control = 0;
+                    vga->sr[0x01] &= ~8; /* no double line */
+                } else {
+                    shift_control = 2;
+                    vga->sr[4] |= 0x08; /* set chain 4 mode */
+                    vga->sr[2] |= 0x0f; /* activate all planes */
+                }
+                vga->gr[0x05] = (vga->gr[0x05] & ~0x60) | (shift_control << 5);
+                vga->cr[0x09] &= ~0x9f; /* no double scan */
+            } else {
+                /* XXX: the bios should do that */
+                vga->bank_offset = 0;
+            }
+            vga->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
+            vga->vbe_regs[vga->vbe_index] = val;
+            break;
+        case VBE_DISPI_INDEX_VIRT_WIDTH:
+            {
+                int w, h, line_offset;
+
+                if (val < vga->vbe_regs[VBE_DISPI_INDEX_XRES])
+                    return;
+                w = val;
+                if (vga->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    line_offset = w >> 1;
+                else
+                    line_offset = w * ((vga->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                h = device_state.vram_size / line_offset;
+                if (h < vga->vbe_regs[VBE_DISPI_INDEX_YRES])
+                    return;
+                vga->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
+                vga->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
+                vga->vbe_line_offset = line_offset;
+            }
+            break;
+        case VBE_DISPI_INDEX_X_OFFSET:
+        case VBE_DISPI_INDEX_Y_OFFSET:
+            {
+                int x;
+                vga->vbe_regs[vga->vbe_index] = val;
+                vga->vbe_start_addr = vga->vbe_line_offset * vga->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
+                x = vga->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
+                if (vga->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    vga->vbe_start_addr += x >> 1;
+                else
+                    vga->vbe_start_addr += x * ((vga->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                vga->vbe_start_addr >>= 2;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+static void
+device_vbe_port_writew(void *priv, uint64_t addr, uint16_t val)
+{
+    assert(priv == NULL);
+
+    switch (addr) {
+    case 0x1ce:
+    case 0xff80:
+        device_vbe_index_write(priv, val);
+        break;
+
+    case 0x1cf:
+    case 0xff81:
+        device_vbe_data_write(priv, val);
+        break;
+
+    default:
+        assert(FALSE);
+        break;
+    }
+}
+
+static io_ops_t device_vbe_port_ops = {
+    .readw = device_vbe_port_readw,
+    .writew = device_vbe_port_writew
+};
+
+static int
+device_vga_register(void)
+{
+    vga_t   *vga = &device_state.vga;
+    int     rc;
+
+    rc = demu_register_port_space(0x3c0, 16, &device_vga_port_ops, NULL);
+    if (rc < 0)
+        goto fail1;
+
+    rc = demu_register_port_space(0x3b4, 2, &device_vga_port_ops, NULL);
+    if (rc < 0)
+        goto fail2;
+
+    rc = demu_register_port_space(0x3d4, 2, &device_vga_port_ops, NULL);
+    if (rc < 0)
+        goto fail3;
+
+    rc = demu_register_port_space(0x3ba, 1, &device_vga_port_ops, NULL);
+    if (rc < 0)
+        goto fail4;
+
+    rc = demu_register_port_space(0x3da, 1, &device_vga_port_ops, NULL);
+    if (rc < 0)
+        goto fail5;
+
+    vga->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
+    vga->vbe_bank_mask = ((device_state.vram_size >> 16) - 1);
+
+    rc = demu_register_port_space(0x1ce, 2, &device_vbe_port_ops, NULL);
+    if (rc < 0)
+        goto fail6;
+
+    rc = demu_register_port_space(0xff80, 2, &device_vbe_port_ops, NULL);
+    if (rc < 0)
+        goto fail7;
+
+    rc = demu_register_memory_space(0xa0000, 0x20000, &device_vga_memory_ops, NULL);
+    if (rc < 0)
+        goto fail8;
+
     return 0;
+
+fail8:
+    DBG("fail8\n");
+
+    demu_deregister_port_space(0xff80);
+
+fail7:
+    DBG("fail7\n");
+
+    demu_deregister_port_space(0x1ce);
+
+fail6:
+    DBG("fail6\n");
+
+    demu_deregister_port_space(0x3da);
+
+fail5:
+    DBG("fail5\n");
+
+    demu_deregister_port_space(0x3ba);
+
+fail4:
+    DBG("fail4\n");
+
+    demu_deregister_port_space(0x3d4);
+
+fail3:
+    DBG("fail3\n");
+
+    demu_deregister_port_space(0x3b4);
+
+fail2:
+    DBG("fail2\n");
+
+    demu_deregister_port_space(0x3c0);
+
+fail1:
+    DBG("fail1\n");
+
+    return -1;
+}
+
+static void
+device_vga_deregister(void)
+{
+    demu_deregister_memory_space(0xa0000);
+
+    demu_deregister_port_space(0xff80);
+    demu_deregister_port_space(0x1ce);
+    demu_deregister_port_space(0x3da);
+    demu_deregister_port_space(0x3ba);
+    demu_deregister_port_space(0x3d4);
+    demu_deregister_port_space(0x3b4);
+    demu_deregister_port_space(0x3c0);
+}
+
+static uint8_t
+device_bar_readb(void *priv, uint64_t addr)
+{
+    vga_t   *vga = &device_state.vga;
+    uint8_t val;
+
+    __copy_from_vram(addr - vga->lfb_addr, &val, 1);
+
+    return val;
 }
 
 static void
-device_memory_writeb(void *priv, uint64_t offset, uint8_t val)
+device_bar_writeb(void *priv, uint64_t addr, uint8_t val)
 {
+    vga_t   *vga = &device_state.vga;
+
+    __copy_to_vram(&val, addr - vga->lfb_addr, 1);
 }
 
-static bar_ops_t    device_memory_ops = {
-    .map = device_memory_map,
-    .unmap = device_memory_unmap,
-    .readb = device_memory_readb,
-    .writeb = device_memory_writeb
+static io_ops_t device_bar_ops = {
+    .readb = device_bar_readb,
+    .writeb = device_bar_writeb
 };
 
+static void
+device_bar_enable(void *priv, uint64_t addr)
+{
+    vga_t   *vga = &device_state.vga;
+    int     rc;
+
+    assert(priv == NULL);
+
+    vga->lfb_addr = 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);
+}
+
+static void
+device_bar_disable(void *priv)
+{
+    vga_t   *vga = &device_state.vga;
+
+    assert(priv == FALSE);
+
+    demu_deregister_memory_space(vga->lfb_addr);
+}
+
 int
-device_initialize(xc_interface *xch, domid_t domid, ioservid_t ioservid,
-                  unsigned int bus, unsigned int device, unsigned int function)
+device_initialize(unsigned int bus, unsigned int device, unsigned int function,
+                  uint64_t vram_size)
 {
     pci_info_t  info;
     int         rc;
 
+    device_state.vram_size = vram_size;
+    device_state.vram = malloc(vram_size);
+
+    if (device_state.vram == NULL)
+        goto fail1;
+
+    device_vga_reset();
+
+    rc = device_vga_register();
+    if (rc < 0)
+        goto fail2;
+
     info.bus = bus;
     info.device = device;
     info.function = function;
 
-    info.vendor_id = 0x5853;
-    info.device_id = 0x0003;
+    info.vendor_id = 0x1234;
+    info.device_id = 0x1111;
     info.subvendor_id = 0x5853;
-    info.subdevice_id = 0x0003;
+    info.subdevice_id = 0x0001;
     info.revision = 0x01;
-    info.class = 0x01;
+    info.class = 0x03;
     info.subclass = 0x00;
     info.prog_if = 0x00;
     info.header_type = 0;
-    info.command = PCI_COMMAND_IO;
+    info.command = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
     info.interrupt_pin = 1;
 
-    rc = pci_device_register(xch, domid, ioservid, &info);
+    rc = pci_device_register(&info);
     if (rc < 0)
-        goto fail1;
-
-    device_io_state.index = 0;
-    device_io_state.order = 8;
+        goto fail3;
 
-    rc = pci_bar_register(device_io_state.index,
-                          PCI_BASE_ADDRESS_SPACE_IO,
-                          device_io_state.order,
-                          &device_io_ops,
-                          &device_io_state);
+    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,
+                          NULL);
     if (rc < 0)
-        goto fail2;
+        goto fail4;
 
-    device_memory_state.index = 1;
-    device_memory_state.order = 24;
+    return 0;
 
-    rc = pci_bar_register(device_memory_state.index,
-                          PCI_BASE_ADDRESS_SPACE_MEMORY |
-                          PCI_BASE_ADDRESS_MEM_PREFETCH,
-                          device_memory_state.order,
-                          &device_memory_ops,
-                          &device_memory_state);
-    if (rc < 0)
-        goto fail3;
+fail4:
+    DBG("fail4\n");
 
-    return 0;
+    pci_device_deregister();
 
 fail3:
     DBG("fail3\n");
 
-    pci_bar_deregister(0);
+    device_vga_deregister();
 
 fail2:
     DBG("fail2\n");
 
-    pci_device_deregister();
+    free(device_state.vram);
 
 fail1:
     DBG("fail1\n");
@@ -204,7 +1192,8 @@ fail1:
 void
 device_teardown(void)
 {
-    pci_bar_deregister(1);
     pci_bar_deregister(0);
     pci_device_deregister();
+    device_vga_deregister();
+    free(device_state.vram);
 }
index 8e4622e2347e0fc950e6abf41db4d0fad9cc13a9..7d9883a523b72de4a9736b599727c3aab4a6096d 100644 (file)
--- a/device.h
+++ b/device.h
 #ifndef  _DEVICE_H
 #define  _DEVICE_H
 
-int     device_initialize(xc_interface *xch, domid_t domid, ioservid_t ioservid,
-                          unsigned int bus, unsigned int device,
-                          unsigned int function);
-
+int     device_initialize(unsigned int bus, unsigned int device, unsigned int function,
+                          uint64_t vram_size);
 void    device_teardown(void);
 
 #endif  /* _DEVICE_H */
diff --git a/mapcache.c b/mapcache.c
new file mode 100644 (file)
index 0000000..c142486
--- /dev/null
@@ -0,0 +1,173 @@
+/*  
+ * Copyright (c) 2012, 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.
+ *
+ */
+#include <err.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <xenctrl.h>
+
+#include "debug.h"
+#include "demu.h"
+
+#define FALSE 0
+#define TRUE  1
+
+typedef struct mapcache_entry {
+    uint8_t     *ptr;
+    xen_pfn_t   pfn;
+    uint64_t    epoch;
+} mapcache_entry_t;
+
+#define MAPCACHE_BUCKET_SHIFT   5
+#define MAPCACHE_BUCKET_SIZE    (1 << MAPCACHE_BUCKET_SHIFT)
+
+#define MAPCACHE_BUCKET_COUNT   32
+
+static mapcache_entry_t mapcache[MAPCACHE_BUCKET_SIZE *
+                                 MAPCACHE_BUCKET_COUNT];
+static uint64_t mapcache_epoch;
+
+static inline uint8_t *
+__mapcache_lookup(xen_pfn_t pfn)
+{
+    int     bucket;
+    int     i;
+    uint8_t *ptr;
+
+    bucket = pfn % MAPCACHE_BUCKET_COUNT;
+
+    ptr = NULL;
+    for (i = 0; i < MAPCACHE_BUCKET_SIZE; i++) {
+        mapcache_entry_t *entry;
+
+        entry = &mapcache[(bucket * MAPCACHE_BUCKET_SIZE) + i];
+
+        if (entry->pfn == pfn) {
+            entry->epoch = mapcache_epoch++;
+            ptr = entry->ptr;
+        }
+    }
+
+    return ptr;
+}
+
+static inline void
+__mapcache_fault(xen_pfn_t pfn)
+{
+    int         bucket;
+    int         i;
+    uint64_t    oldest_epoch;
+
+    DBG("%llx\n", (unsigned long long)pfn);
+
+    bucket = pfn % MAPCACHE_BUCKET_COUNT;
+
+    oldest_epoch = mapcache_epoch;
+    for (i = 0; i < MAPCACHE_BUCKET_SIZE; i++) {
+        mapcache_entry_t *entry;
+
+        entry = &mapcache[(bucket * MAPCACHE_BUCKET_SIZE) + i];
+
+        if (entry->epoch < oldest_epoch)
+            oldest_epoch = entry->epoch;
+    }
+
+    for (i = 0; i < MAPCACHE_BUCKET_SIZE; i++) {
+        mapcache_entry_t *entry;
+
+        entry = &mapcache[(bucket * MAPCACHE_BUCKET_SIZE) + i];
+
+        if (entry->epoch != oldest_epoch)
+            continue;
+
+        if (entry->ptr != NULL) {
+            munmap(entry->ptr, TARGET_PAGE_SIZE);
+            entry->ptr = NULL;
+        }
+
+        entry->ptr = demu_map_guest_page(pfn);
+        if (entry->ptr != NULL)
+            entry->pfn = pfn;
+
+        break;
+    }
+}
+
+uint8_t *
+mapcache_lookup(uint64_t addr)
+{
+    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:
+    ptr = __mapcache_lookup(pfn);
+    if (ptr == NULL) {
+        if (!faulted) {
+            faulted = TRUE;
+            __mapcache_fault(pfn);
+            goto again;
+        }
+        goto fail1;
+    }
+
+    ptr += offset;
+    return ptr;
+
+fail1:
+    DBG("fail1\n");
+
+    return NULL;
+}
+
+void
+mapcache_invalidate(void)
+{
+    int i;
+
+    for (i = 0; i < MAPCACHE_BUCKET_SIZE * MAPCACHE_BUCKET_COUNT; i++) {
+        mapcache_entry_t *entry = &mapcache[i];
+
+        if (entry->ptr != NULL) {
+            munmap(entry->ptr, TARGET_PAGE_SIZE);
+            entry->ptr = NULL;
+        }
+    }
+}
diff --git a/mapcache.h b/mapcache.h
new file mode 100644 (file)
index 0000000..158b556
--- /dev/null
@@ -0,0 +1,37 @@
+/*  
+ * Copyright (c) 2012, 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  _MAPCACHE_H
+#define  _MAPCACHE_H
+
+uint8_t *mapcache_lookup(uint64_t addr);
+void    mapcache_invalidate(void);
+
+#endif  /* _MAPCACHE_H */
+
diff --git a/pci.c b/pci.c
index 952c8eb93d9ba60d94c97a386a273ee1bfced742..3eaac4b07563b10e9cc515b38e4a71471aafc4b2 100644 (file)
--- a/pci.c
+++ b/pci.c
@@ -32,6 +32,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
+#include <inttypes.h>
 
 #include <sys/types.h>
 
 
 #include "debug.h"
 #include "pci.h"
+#include "demu.h"
 
 #define FALSE 0
 
 typedef struct pci_bar {
-    const bar_ops_t *ops;
+    const io_ops_t *ops;
     int             is_mmio;
-    int             enable;
-    uint32_t        addr;
-    uint32_t        size;
+    uint64_t        addr;
+    uint64_t        size;
+    void            (*enable)(void *, uint64_t);
+    void            (*disable)(void *);
     void            *priv;
 } pci_bar_t;
 
 typedef struct pci {
-    xc_interface    *xch;
-    domid_t         domid;
-    ioservid_t      ioservid;
-    uint16_t        bdf;
-    uint8_t         config[PCI_CONFIG_SIZE];
-    uint8_t         mask[PCI_CONFIG_SIZE];
-    pci_bar_t       bar[PCI_NUM_BAR];
-    uint32_t        irq_pin;
-    uint32_t        irq_state;
+    uint8_t     bus;
+    uint8_t     device:5;
+    uint8_t     function:3;
+    uint8_t     config[PCI_CONFIG_SIZE];
+    uint8_t     mask[PCI_CONFIG_SIZE];
+    pci_bar_t   bar[PCI_NUM_BAR];
+    uint32_t    irq_pin;
+    uint32_t    irq_state;
 } pci_t;
 
-static pci_t    pci;
-
-int
-pci_device_register(xc_interface *xch, domid_t domid, ioservid_t ioservid,
-                    const pci_info_t *info)
-{
-    int     rc;
-
-    pci.xch = xch;
-    pci.domid = domid;
-    pci.ioservid = ioservid;
-
-    if (info->bus & ~0xff ||
-        info->device & ~0x1f ||
-        info->function & ~0x07)
-        goto fail1;
-
-    pci.bdf = (info->bus << 8) | (info->device << 3) | (info->function);
-
-    *(uint16_t *)&pci.config[PCI_VENDOR_ID] = info->vendor_id;
-    *(uint16_t *)&pci.config[PCI_DEVICE_ID] = info->device_id;
-    pci.config[PCI_REVISION_ID] = info->revision;
-    pci.config[PCI_CLASS_PROG] = info->prog_if;
-    pci.config[PCI_CLASS_DEVICE + 1] = info->class;
-    pci.config[PCI_CLASS_DEVICE] = info->subclass;
-    pci.config[PCI_HEADER_TYPE] = info->header_type;
-    *(uint16_t *)&pci.config[PCI_SUBSYSTEM_VENDOR_ID] = info->subvendor_id;
-    *(uint16_t *)&pci.config[PCI_SUBSYSTEM_ID] = info->subdevice_id;
-    *(uint16_t *)&pci.config[PCI_COMMAND] = info->command;
-    pci.config[PCI_INTERRUPT_PIN] = info->interrupt_pin;
-
-    pci.mask[PCI_CACHE_LINE_SIZE] = 0xff;
-    pci.mask[PCI_INTERRUPT_LINE] = 0xff;
-    *(uint16_t *)&pci.mask[PCI_COMMAND] = PCI_COMMAND_IO |
-                                          PCI_COMMAND_MEMORY |
-                                          PCI_COMMAND_MASTER |
-                                          PCI_COMMAND_INTX_DISABLE;
-    memset(&pci.mask[PCI_CONFIG_HEADER_SIZE], 0xff,
-           PCI_CONFIG_SIZE - PCI_CONFIG_HEADER_SIZE);
-
-    DBG("%02x:%02x:%02x\n", info->bus, info->device, info->function);
-
-    rc = xc_hvm_map_pcidev_to_ioreq_server(xch, domid, ioservid, pci.bdf);
-    if (rc < 0)
-        goto fail2;
-
-    rc = xc_hvm_pci_hotplug_enable(xch, domid, info->device);
-    if (rc < 0)
-        goto fail3;
-
-    return 0;
-
-fail3:
-    DBG("fail3\n");
-
-    (void) xc_hvm_unmap_pcidev_from_ioreq_server(xch, domid, ioservid,
-                                                 pci.bdf);
-
-fail2:
-    DBG("fail2\n");
-
-fail1:
-    DBG("fail1\n");
-
-    warn("fail");
-    return -1;
-}
-
-void
-pci_device_deregister(void)
-{
-    uint8_t bus = (pci.bdf >> 8) & 0xff;
-    uint8_t device = (pci.bdf >> 3) & 0x1f;
-    uint8_t function= pci.bdf & 0x07;
-
-    DBG("%02x:%02x:%02x\n", bus, device, function);
-
-    (void) xc_hvm_pci_hotplug_disable(pci.xch, pci.domid, device);
-    (void) xc_hvm_unmap_pcidev_from_ioreq_server(pci.xch, pci.domid,
-                                                pci.ioservid, pci.bdf);
-}
-
-int
-pci_bar_register(unsigned int index, uint8_t type, unsigned int order,
-                 const bar_ops_t *ops, void *priv)
-{
-    pci_bar_t   *bar;
-
-    DBG("%d: %08x\n", index, 1u << order);
-
-    if (index >= PCI_NUM_BAR)
-        goto fail;
-
-    bar = &pci.bar[index];
-
-    if (bar->enable)
-        goto fail;
-
-    if (ops == NULL ||
-        ops->readb == NULL ||
-        ops->writeb == NULL)
-        goto fail;
-
-    bar->ops = ops;
-    bar->is_mmio = !(type & PCI_BASE_ADDRESS_SPACE_IO);
-    bar->size = 1u << order;
-
-    *(uint32_t *)&pci.config[PCI_BASE_ADDRESS_0 + (index * 4)] = type;
-    *(uint32_t *)&pci.mask[PCI_BASE_ADDRESS_0 + (index * 4)] = ~(bar->size - 1);
-
-    bar->enable = 1;
-    bar->addr = PCI_BAR_UNMAPPED;
-
-    bar->priv = priv;
-
-    return 0;
-
-fail:
-    return -1;
-}
-
-void
-pci_bar_deregister(unsigned int index)
-{
-    pci_bar_t *bar = &pci.bar[index];
-
-    DBG("%d\n", index);
-
-    if (bar->addr == PCI_BAR_UNMAPPED)
-        return;
-
-    (void) xc_hvm_unmap_io_range_from_ioreq_server(pci.xch,
-                                                  pci.domid,
-                                                  pci.ioservid,
-                                                  bar->is_mmio,
-                                                  bar->addr);
-}
-
-static pci_bar_t *
-pci_bar_get(int is_mmio, uint64_t addr)
-{
-    int i;
-
-    for (i = 0; i < PCI_NUM_BAR; i++)
-    {
-        pci_bar_t *bar = &pci.bar[i];
-
-        if (!bar->enable || bar->is_mmio != is_mmio)
-            continue;
-
-        if (bar->addr <= addr && addr < (bar->addr + bar->size))
-            return bar;
-    }
-
-    return NULL;
-}
-
-#define PCI_BAR_READ(_fn, _priv, _addr, _size, _count, _val)    \
-do {                                                            \
-    int             _i = 0;                                     \
-    unsigned int    _shift = 0;                                 \
-                                                                \
-    (_val) = 0;                                                 \
-    for (_i = 0; _i < (_count); _i++)                           \
-    {                                                           \
-        (_val) |= (_fn)((_priv), (_addr)) << _shift;            \
-        _shift += 8 * (_size);                                  \
-        (_addr) += (_size);                                     \
-    }                                                           \
-} while (FALSE)
-
-uint32_t
-pci_bar_read(int is_mmio, uint64_t addr, uint64_t size)
-{
-    pci_bar_t   *bar = pci_bar_get(is_mmio, addr);
-    uint32_t    val = 0;
-
-    assert(bar != NULL);
-
-    addr -= bar->addr;
-
-    switch (size) {
-    case 1:
-        val = bar->ops->readb(bar->priv, addr);
-        break;
-
-    case 2:
-        if (bar->ops->readw == NULL)
-            PCI_BAR_READ(bar->ops->readb, bar->priv, addr, 1, 2, val);
-        else
-            val = bar->ops->readw(bar->priv, addr);
-        break;
-
-    case 4:
-        if (bar->ops->readl == NULL) {
-            if (bar->ops->readw == NULL)
-                PCI_BAR_READ(bar->ops->readb, bar->priv, addr, 1, 4, val);
-            else
-                PCI_BAR_READ(bar->ops->readw, bar->priv, addr, 2, 2, val);
-        } else {
-            val = bar->ops->readl(bar->priv, addr);
-        }
-        break;
-
-    default:
-        assert(FALSE);
-    }
-
-    return val;
-}
-
-#define PCI_BAR_WRITE(_fn, _priv, _addr, _size, _count, _val)   \
-do {                                                            \
-    int             _i = 0;                                     \
-    unsigned int    _shift = 0;                                 \
-                                                                \
-    (_val) = 0;                                                 \
-    for (_i = 0; _i < (_count); _i++)                           \
-    {                                                           \
-        (_fn)((_priv), (_addr), (_val) >> _shift);              \
-        _shift += 8 * (_size);                                  \
-        (_addr) += (_size);                                     \
-    }                                                           \
-} while (FALSE)
-
-void
-pci_bar_write(int is_mmio, uint64_t addr, uint64_t size, uint32_t val)
-{
-    pci_bar_t   *bar = pci_bar_get(is_mmio, addr);
-
-    assert(bar != NULL);
-
-    addr -= bar->addr;
-
-    switch (size) {
-    case 1:
-        bar->ops->writeb(bar->priv, addr, val);
-        break;
-
-    case 2:
-        if (bar->ops->writew == NULL)
-            PCI_BAR_WRITE(bar->ops->writeb, bar->priv, addr, 1, 2, val);
-        else
-            bar->ops->writew(bar->priv, addr, val);
-        break;
-
-    case 4:
-        if (bar->ops->writel == NULL) {
-            if (bar->ops->writew == NULL)
-                PCI_BAR_WRITE(bar->ops->writeb, bar->priv, addr, 1, 4, val);
-            else
-                PCI_BAR_WRITE(bar->ops->writew, bar->priv, addr, 2, 2, val);
-        } else {
-            bar->ops->writel(bar->priv, addr, val);
-        }
-        break;
-
-    default:
-        assert(FALSE);
-    }
-}
+static pci_t    pci_state;
 
 static void
-pci_map_bar(unsigned int index)
+pci_bar_enable(unsigned int index)
 {
-    pci_bar_t *bar = &pci.bar[index];
-
-    DBG("%d: %08x\n", index, bar->addr);
-
-    if (bar->ops->map)
-        bar->ops->map(bar->priv, bar->addr);
+    pci_bar_t  *bar = &pci_state.bar[index];
 
-    (void) xc_hvm_map_io_range_to_ioreq_server(pci.xch,
-                                               pci.domid,
-                                               pci.ioservid,
-                                               bar->is_mmio,
-                                               bar->addr,
-                                               bar->addr + bar->size - 1);
+    assert(bar->enable != NULL);
+    bar->enable(bar->priv, bar->addr);
 }
 
 static void
-pci_unmap_bar(unsigned int index)
+pci_bar_disable(unsigned int index)
 {
-    pci_bar_t *bar = &pci.bar[index];
+    pci_bar_t  *bar = &pci_state.bar[index];
 
-    DBG("%d\n", index);
-
-    (void) xc_hvm_unmap_io_range_from_ioreq_server(pci.xch,
-                                                   pci.domid,
-                                                   pci.ioservid,
-                                                   bar->is_mmio,
-                                                   bar->addr);
-
-    if (bar->ops->unmap)
-        bar->ops->unmap(bar->priv);
+    assert(bar->disable != NULL);
+    bar->disable(bar->priv);
 }
 
 static void
-pci_update_bar(unsigned int index)
+pci_bar_update(unsigned int index)
 {
-    pci_bar_t *bar = &pci.bar[index];
-    uint32_t addr = *(uint32_t *)&pci.config[PCI_BASE_ADDRESS_0 + (index * 4)];
-    uint16_t cmd = *(uint16_t *)&pci.config[PCI_COMMAND];
-    uint32_t mask = ~(bar->size - 1);
+    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);
 
-    if (!bar->enable)
+    if (bar->size == 0)
         return;
 
     if (bar->is_mmio)
@@ -387,112 +112,181 @@ pci_update_bar(unsigned int index)
         return;
 
     if (bar->addr != PCI_BAR_UNMAPPED) {
-        pci_unmap_bar(index);
+        pci_bar_disable(index);
         bar->addr = PCI_BAR_UNMAPPED;
     }
 
     if (addr != PCI_BAR_UNMAPPED) {
         bar->addr = addr;
-        pci_map_bar(index);
+        pci_bar_enable(index);
     }
 }
 
 static void
-pci_update_config()
+pci_config_update()
 {
-    int i;
+    int        i;
 
     for (i = 0; i < PCI_NUM_BAR; i++)
-        pci_update_bar(i);
+        pci_bar_update(i);
 }
 
-uint32_t
-pci_config_read(uint64_t addr, uint64_t size)
+uint8_t
+pci_config_readb(void *priv, uint64_t addr)
 {
-    uint64_t    i;
-    uint32_t    val;
-    uint16_t    bdf;
+    uint8_t val;
 
-    val = ~(0u);
+    assert(priv == NULL);
+    val = pci_state.config[addr];
+    return val;
+}
 
-    if (!(addr & (1ull << 31)))
-        goto done;
+void
+pci_config_writeb(void *priv, uint64_t addr, uint8_t val)
+{
+    uint8_t    mask = pci_state.mask[addr];
+
+    assert(priv == NULL);
+    pci_state.config[addr] &= ~mask;
+    pci_state.config[addr] |= val & mask;
 
-    bdf = (uint16_t)(addr >> 8);
+    pci_config_update();
+}
 
-    if (bdf != pci.bdf)
-        goto done;
+static io_ops_t pci_config_ops = {
+    .readb = pci_config_readb,
+    .writeb = pci_config_writeb
+};
 
-    addr &= 0xff;
-    addr += size >> 16;
-    size &= 0xffff;
+void
+pci_device_dump(void)
+{
+    int        i;
 
-    val = 0;
-    for (i = 0; i < size; i++) {
-        if ((addr + i) < PCI_CONFIG_SIZE)
-            val |= (uint32_t)pci.config[addr + i] << (i * 8);
-        else
-            val |= (uint32_t)0xff << (i + 8);
+    fprintf(stderr, "    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",
+                i,
+                pci_state.config[i + 3],
+                pci_state.config[i + 2],
+                pci_state.config[i + 1],
+                pci_state.config[i ]);
     }
+}
 
-done:
-    return val;
+int
+pci_device_register(const pci_info_t *info)
+{
+    int        rc;
+
+    if (info->bus & ~0xff ||
+        info->device & ~0x1f ||
+        info->function & ~0x07)
+        goto fail1;
+
+    pci_state.bus = info->bus;
+    pci_state.device = info->device;
+    pci_state.function = info->function;
+
+    *(uint16_t *)&pci_state.config[PCI_VENDOR_ID] = info->vendor_id;
+    *(uint16_t *)&pci_state.config[PCI_DEVICE_ID] = info->device_id;
+    pci_state.config[PCI_REVISION_ID] = info->revision;
+    pci_state.config[PCI_CLASS_PROG] = info->prog_if;
+    pci_state.config[PCI_CLASS_DEVICE + 1] = info->class;
+    pci_state.config[PCI_CLASS_DEVICE] = info->subclass;
+    pci_state.config[PCI_HEADER_TYPE] = info->header_type;
+    *(uint16_t *)&pci_state.config[PCI_SUBSYSTEM_VENDOR_ID] = info->subvendor_id;
+    *(uint16_t *)&pci_state.config[PCI_SUBSYSTEM_ID] = info->subdevice_id;
+    *(uint16_t *)&pci_state.config[PCI_COMMAND] = info->command;
+    pci_state.config[PCI_INTERRUPT_PIN] = info->interrupt_pin;
+
+    pci_state.mask[PCI_CACHE_LINE_SIZE] = 0xff;
+    pci_state.mask[PCI_INTERRUPT_LINE] = 0xff;
+    *(uint16_t *)&pci_state.mask[PCI_COMMAND] = PCI_COMMAND_IO |
+                                          PCI_COMMAND_MEMORY |
+                                          PCI_COMMAND_MASTER |
+                                          PCI_COMMAND_INTX_DISABLE;
+    memset(&pci_state.mask[PCI_CONFIG_HEADER_SIZE], 0xff,
+           PCI_CONFIG_SIZE - PCI_CONFIG_HEADER_SIZE);
+
+    rc = demu_register_pci_config_space(pci_state.bus, pci_state.device, pci_state.function,
+                                        &pci_config_ops, NULL);
+    if (rc < 0)
+        goto fail2;
+
+    return 0;
+
+fail2:
+    DBG("fail2\n");
+
+fail1:
+    DBG("fail1\n");
+
+    warn("fail");
+    return -1;
 }
 
 void
-pci_config_write(uint64_t addr, uint64_t size, uint32_t val)
+pci_device_deregister(void)
 {
-    uint64_t    i;
-    uint8_t     mask;
-    uint16_t    bdf;
+    demu_deregister_pci_config_space(pci_state.bus, pci_state.device, pci_state.function);
+}
 
-    if (!(addr & (1ull << 31)))
-        return;
+int
+pci_bar_register(unsigned int index, uint8_t type, uint64_t size,
+                 void (*enable)(void *priv, uint64_t addr),
+                 void (*disable)(void *priv),
+                 void *priv)
+{
+    pci_bar_t  *bar;
 
-    bdf = (uint16_t)(addr >> 8);
+    DBG("%d: %"PRIx64"\n", index, size);
 
-    if (bdf != pci.bdf)
-        return;
+    if (index >= PCI_NUM_BAR)
+        goto fail1;
 
-    addr &= 0xff;
-    addr += size >> 16;
-    size &= 0xffff;
+    bar = &pci_state.bar[index];
 
-    for (i = 0; i < size; i++) {
-        if ((addr + i) < PCI_CONFIG_SIZE) {
-            mask = pci.mask[addr + i];
-            pci.config[addr + i] &= ~mask;
-            pci.config[addr + i] |= (uint8_t)(val >> (i * 8)) & mask;
-        }
-    }
+    if (enable == NULL ||
+        disable == NULL)
+        goto fail2;
+
+    bar->priv = priv;
+    bar->enable = enable;
+    bar->disable = disable;
+    bar->is_mmio = !(type & PCI_BASE_ADDRESS_SPACE_IO);
+    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);
+
+    return 0;
+
+fail2:
+    DBG("fail2\n");
 
-    pci_update_config();
+fail1:
+    DBG("fail1\n");
+
+    warn("fail");
+    return -1;
 }
 
 void
-pci_config_dump(void)
+pci_bar_deregister(unsigned int index)
 {
-    int i;
+    pci_bar_t  *bar = &pci_state.bar[index];
 
-    fprintf(stderr, "    3  2  1  0\n");
-    fprintf(stderr, "--------------\n");
+    DBG("%d\n", index);
 
-    for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i += 4) {
-        fprintf(stderr, "%02x |%02x %02x %02x %02x\n",
-                i,
-                pci.config[i + 3],
-                pci.config[i + 2],
-                pci.config[i + 1],
-                pci.config[i ]);
-    }
-}
+    if (bar->addr == PCI_BAR_UNMAPPED)
+        return;
 
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * c-tab-always-indent: nil
- * indent-tabs-mode: nil
- * End:
- */
+    assert(bar->disable != NULL);
+    bar->disable(bar->priv);
+    bar->size = 0;
+}
diff --git a/pci.h b/pci.h
index 6b7692780db9cf37b6f0ce3f6827d49f47711719..41865ec7127246a1425da282643e92f41fc2aa63 100644 (file)
--- a/pci.h
+++ b/pci.h
@@ -53,31 +53,16 @@ typedef struct pci_info {
         uint8_t         interrupt_pin;
 } pci_info_t;
 
-int     pci_device_register(xc_interface *xch, domid_t domid, ioservid_t ioservid,
-                            const pci_info_t *info);
+int     pci_device_register( const pci_info_t *info);
 void    pci_device_deregister(void);
 
-typedef struct bar_ops {
-        void            (*map)(void *priv, uint64_t addr);
-        void            (*unmap)(void *priv);
-        uint8_t         (*readb)(void *priv, uint64_t offset);
-        uint16_t        (*readw)(void *priv, uint64_t offset);
-        uint32_t        (*readl)(void *priv, uint64_t offset);
-        void            (*writeb)(void *priv, uint64_t offset, uint8_t val);
-        void            (*writew)(void *priv, uint64_t offset, uint16_t val);
-        void            (*writel)(void *priv, uint64_t offset, uint32_t val);
-} bar_ops_t;
-
-int     pci_bar_register(unsigned int index, uint8_t type, unsigned int order,
-                         const bar_ops_t *ops, void *priv);
+int     pci_bar_register(unsigned int index, uint8_t type, uint64_t size,
+                         void (*map)(void *priv, uint64_t addr),
+                         void (*unmap)(void *priv),
+                         void *priv);
 void    pci_bar_deregister(unsigned int index);
 
-uint32_t        pci_bar_read(int is_mmio, uint64_t addr, uint64_t size);
-void            pci_bar_write(int is_mmio, uint64_t addr, uint64_t size, uint32_t val);
-
-uint32_t        pci_config_read(uint64_t addr, uint64_t size);
-void            pci_config_write(uint64_t addr, uint64_t size, uint32_t val);
-void            pci_config_dump();
+void    pci_device_dump(void);
 
 #endif  /* _PCI_H */
 
diff --git a/vga.h b/vga.h
new file mode 100644 (file)
index 0000000..14b17d9
--- /dev/null
+++ b/vga.h
@@ -0,0 +1,76 @@
+#define MSR_COLOR_EMULATION 0x01
+#define MSR_PAGE_SELECT     0x20
+
+#define ST01_V_RETRACE      0x08
+#define ST01_DISP_ENABLE    0x01
+
+#define VBE_DISPI_MAX_XRES                      2560
+#define VBE_DISPI_MAX_YRES                      1600
+#define VBE_DISPI_MAX_BPP                       32
+
+#define VBE_DISPI_INDEX_ID                      0x0
+#define VBE_DISPI_INDEX_XRES                    0x1
+#define VBE_DISPI_INDEX_YRES                    0x2
+#define VBE_DISPI_INDEX_BPP                     0x3
+#define VBE_DISPI_INDEX_ENABLE                  0x4
+#define VBE_DISPI_INDEX_BANK                    0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH              0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT             0x7
+#define VBE_DISPI_INDEX_X_OFFSET                0x8
+#define VBE_DISPI_INDEX_Y_OFFSET                0x9
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K        0xa
+#define VBE_DISPI_INDEX_LFB_ADDRESS_H           0xb
+#define VBE_DISPI_INDEX_LFB_ADDRESS_L           0xc
+#define VBE_DISPI_INDEX_NB                      0xd
+
+#define VBE_DISPI_ID0                           0xb0c0
+#define VBE_DISPI_ID1                           0xb0c1
+#define VBE_DISPI_ID2                           0xb0c2
+#define VBE_DISPI_ID3                           0xb0c3
+#define VBE_DISPI_ID4                           0xb0c4
+
+#define VBE_DISPI_DISABLED                      0x00
+#define VBE_DISPI_ENABLED                       0x01
+#define VBE_DISPI_GETCAPS                       0x02
+#define VBE_DISPI_8BIT_DAC                      0x20
+#define VBE_DISPI_LFB_ENABLED                   0x40
+#define VBE_DISPI_NOCLEARMEM                    0x80
+
+typedef struct vga {
+    uint64_t    lfb_addr;
+    uint64_t    lfb_size;
+
+    uint32_t    latch;
+    uint8_t     sr_index;
+    uint8_t     sr[256];
+    uint8_t     gr_index;
+    uint8_t     gr[256];
+    uint8_t     ar_index;
+    uint8_t     ar[21];
+    int32_t     ar_flip_flop;
+    uint8_t     cr_index;
+    uint8_t     cr[256];        /* CRT registers */
+    uint8_t     msr;            /* Misc Output Register */
+    uint8_t     fcr;            /* Feature Control Register */
+    uint8_t     st00;           /* status 0 */
+    uint8_t     st01;           /* status 1 */
+
+    uint8_t     dac_state;
+    uint8_t     dac_sub_index;
+    uint8_t     dac_read_index;
+    uint8_t     dac_write_index;
+    uint8_t     dac_cache[3];   /* Used when writing */
+    int32_t     dac_8bit;
+
+    uint8_t     palette[768];
+
+    int32_t     bank_offset;
+
+    uint16_t    vbe_index;
+    uint16_t    vbe_regs[VBE_DISPI_INDEX_NB];
+    uint32_t    vbe_start_addr;
+    uint32_t    vbe_line_offset;
+    uint32_t    vbe_bank_mask;
+
+    uint32_t    plane_updated;
+} vga_t;