VRAM is in local memory rather than guest. No surface display as yet.
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
OBJS := device.o \
pci.o \
+ mapcache.o \
demu.o
CFLAGS = -I$(shell pwd)/include
LDLIBS := -lutil -lrt
endif
-LDLIBS += -lxenstore -lxenctrl
+LDLIBS += -lxenctrl
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,$(@D)/.$(@F).d
rm -f $(OBJS)
rm -f $(DEPS)
rm -f $(TARGET)
- rm -f TAGS
-
-.PHONY: TAGS
-TAGS:
- find . -name \*.[ch] | etags -
-include $(DEPS)
#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
};
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;
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;
}
}
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:
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;
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;
}
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;
int i;
demu_state.domid = domid;
- demu_state.vcpus = vcpus;
demu_state.xch = xc_interface_open(NULL, NULL, 0);
if (demu_state.xch == NULL)
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;
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();
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);
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;
read_pointer = demu_state.buffered_iopage->read_pointer;
write_pointer = demu_state.buffered_iopage->write_pointer;
+ mb();
if (read_pointer == write_pointer)
break;
read_pointer++;
}
- handle_ioreq(&ioreq);
+ demu_handle_ioreq(&ioreq);
mb();
}
}
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;
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);
}
}
}
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;
prog = basename(argv[0]);
domain_str = NULL;
- vcpus_str = NULL;
- bus_str = NULL;
device_str = NULL;
- function_str = NULL;
for (;;) {
char c;
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;
}
if (domain_str == NULL ||
- vcpus_str == NULL ||
- bus_str == NULL ||
- device_str == NULL ||
- function_str == NULL) {
+ device_str == NULL) {
usage();
/*NOTREACHED*/
}
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);
}
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);
--- /dev/null
+/*
+ * 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 */
#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");
void
device_teardown(void)
{
- pci_bar_deregister(1);
pci_bar_deregister(0);
pci_device_deregister();
+ device_vga_deregister();
+ free(device_state.vram);
}
#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 */
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 */
+
#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)
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;
+}
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 */
--- /dev/null
+#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;