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