static demu_state_t demu_state;
void *
-demu_map_guest_pages(xen_pfn_t pfn[], unsigned int n)
+demu_map_guest_pages(xen_pfn_t pfn[], unsigned int n, int populate)
{
void *ptr;
+ if (populate) {
+ int rc;
+
+ rc = xc_domain_populate_physmap_exact(demu_state.xch, demu_state.domid,
+ n, 0, 0, pfn);
+ if (rc < 0)
+ goto fail1;
+ }
+
ptr = xc_map_foreign_pages(demu_state.xch, demu_state.domid,
PROT_READ | PROT_WRITE,
pfn, n);
if (ptr == NULL)
+ goto fail2;
+
+ if (populate)
+ memset(ptr, 0, n * TARGET_PAGE_SIZE);
+
+ return ptr;
+
+fail2:
+ DBG("fail2\n");
+
+ if (populate)
+ (void) xc_domain_decrease_reservation(demu_state.xch, demu_state.domid,
+ n, 0, pfn);
+
+fail1:
+ DBG("fail1\n");
+
+ warn("fail");
+ return NULL;
+}
+
+void *
+demu_map_guest_range(uint64_t addr, uint64_t size, int populate)
+{
+ xen_pfn_t *pfn;
+ int i, n;
+ void *ptr;
+
+ DBG("%"PRIx64"+%"PRIx64" %s\n", addr, size, (populate) ? "[POPULATE]" : "");
+
+ size = P2ROUNDUP(size, TARGET_PAGE_SIZE);
+
+ n = size >> TARGET_PAGE_SHIFT;
+ pfn = malloc(sizeof (xen_pfn_t) * n);
+
+ if (pfn == NULL)
goto fail1;
+
+ for (i = 0; i < n; i++)
+ pfn[i] = (addr >> TARGET_PAGE_SHIFT) + i;
+
+ ptr = demu_map_guest_pages(pfn, n, populate);
+ if (ptr == NULL)
+ goto fail2;
+ free(pfn);
return ptr;
+fail2:
+ DBG("fail2\n");
+
+ free(pfn);
+
fail1:
DBG("fail1\n");
return NULL;
}
+void
+demu_unmap_guest_pages(void *ptr, xen_pfn_t pfn[], unsigned int n, int depopulate)
+{
+ munmap(ptr, TARGET_PAGE_SIZE * n);
+ if (depopulate)
+ (void) xc_domain_decrease_reservation(demu_state.xch, demu_state.domid,
+ n, 0, pfn);
+}
+
+int
+demu_unmap_guest_range(void *ptr, uint64_t addr, uint64_t size, int depopulate)
+{
+ xen_pfn_t *pfn;
+ int i, n;
+
+ DBG("%"PRIx64"+%"PRIx64" %s\n", addr, size, (depopulate) ? "[DEPOPULATE]" : "");
+
+ size = P2ROUNDUP(size, TARGET_PAGE_SIZE);
+
+ n = size >> TARGET_PAGE_SHIFT;
+ pfn = malloc(sizeof (xen_pfn_t) * n);
+
+ if (pfn == NULL)
+ goto fail1;
+
+ for (i = 0; i < n; i++)
+ pfn[i] = (addr >> TARGET_PAGE_SHIFT) + i;
+
+ demu_unmap_guest_pages(ptr, pfn, n, depopulate);
+
+ free(pfn);
+ return 0;
+
+fail1:
+ DBG("fail1\n");
+
+ warn("fail");
+ return -1;
+}
+
+int
+demu_relocate_guest_pages(xen_pfn_t old[], xen_pfn_t new[], unsigned int n)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < n; i++) {
+ rc = xc_domain_add_to_physmap(demu_state.xch, demu_state.domid,
+ XENMAPSPACE_gmfn, old[i], new[i]);
+ if (rc < 0)
+ goto fail1;
+
+ }
+
+ return 0;
+
+fail1:
+ DBG("fail1\n");
+
+ warn("fail");
+ return -1;
+}
+
+int
+demu_relocate_guest_range(uint64_t old, uint64_t new, uint64_t size)
+{
+ xen_pfn_t *old_pfn, *new_pfn;
+ int i, n;
+ int rc;
+
+ DBG("%"PRIx64"+%"PRIx64" -> %"PRIx64"\n", old, size, new);
+
+ size = P2ROUNDUP(size, TARGET_PAGE_SIZE);
+
+ n = size >> TARGET_PAGE_SHIFT;
+
+ old_pfn = malloc(sizeof (xen_pfn_t) * n);
+ if (old_pfn == NULL)
+ goto fail1;
+
+ new_pfn = malloc(sizeof (xen_pfn_t) * n);
+ if (new_pfn == NULL)
+ goto fail2;
+
+ for (i = 0; i < n; i++) {
+ old_pfn[i] = (old >> TARGET_PAGE_SHIFT) + i;
+ new_pfn[i] = (new >> TARGET_PAGE_SHIFT) + i;
+ }
+
+ rc = demu_relocate_guest_pages(old_pfn, new_pfn, n);
+ if (rc < 0)
+ goto fail3;
+
+ free(new_pfn);
+ free(old_pfn);
+ return 0;
+
+fail3:
+ DBG("fail3\n");
+
+ free(new_pfn);
+
+fail2:
+ DBG("fail2\n");
+
+ free(old_pfn);
+
+fail1:
+ DBG("fail1\n");
+
+ warn("fail");
+ return -1;
+}
+
+void
+demu_set_guest_dirty_page(xen_pfn_t pfn)
+{
+ (void) xc_hvm_modified_memory(demu_state.xch, demu_state.domid,
+ pfn, 1);
+}
+
+void
+demu_track_dirty_vram(xen_pfn_t pfn, int n, unsigned long *bitmap)
+{
+ int rc;
+
+ rc = xc_hvm_track_dirty_vram(demu_state.xch, demu_state.domid,
+ pfn, n, bitmap);
+ if (rc < 0 && bitmap != NULL)
+ memset(bitmap, 0, n / 8);
+}
+
static demu_space_t *
demu_find_space(demu_space_t *head, uint64_t addr)
{
#ifndef _DEMU_H
#define _DEMU_H
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
#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);
+void *demu_map_guest_pages(xen_pfn_t pfn[], unsigned int n, int populate);
-static inline void *demu_map_guest_page(xen_pfn_t pfn)
+static inline void *demu_map_guest_page(xen_pfn_t pfn, int populate)
{
- return demu_map_guest_pages(&pfn, 1);
+ return demu_map_guest_pages(&pfn, 1, populate);
}
+void *demu_map_guest_range(uint64_t addr, uint64_t size, int populate);
+
+void demu_unmap_guest_pages(void *ptr, xen_pfn_t pfn[], unsigned int n,
+ int depopulate);
+
+static inline void demu_unmap_guest_page(void *ptr, xen_pfn_t pfn,
+ int depopulate)
+{
+ return demu_unmap_guest_pages(ptr, &pfn, 1, depopulate);
+}
+
+int demu_unmap_guest_range(void *ptr, uint64_t addr, uint64_t size,
+ int depopulate);
+
+int demu_relocate_guest_pages(xen_pfn_t old[], xen_pfn_t new[],
+ unsigned int n);
+int demu_relocate_guest_range(uint64_t old, uint64_t new,
+ uint64_t size);
+
+void demu_set_guest_dirty_page(xen_pfn_t pfn);
+void demu_track_dirty_vram(xen_pfn_t pfn, int n, unsigned long *bitmap);
+
typedef struct io_ops {
uint8_t (*readb)(void *priv, uint64_t addr);
uint16_t (*readw)(void *priv, uint64_t addr);
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);
#include "mapcache.h"
#include "vga.h"
-#define FALSE 0
-
#define DEBUG_VGA_MEMORY 0
#define DEBUG_VGA_IO 0
#define DEBUG_VBE_IO 0
uint64_t vram_addr;
uint64_t vram_size;
uint8_t *vram;
+ int vram_enabled;
+ unsigned long *bitmap;
uint64_t mmio_addr;
uint64_t mmio_size;
uint64_t rom_addr;
static void
__copy_from_vram(uint64_t addr, uint8_t *dst, uint64_t size)
{
- memcpy(dst, &device_state.vram[addr], size);
+ if (device_state.vram != NULL && device_state.vram_enabled)
+ memcpy(dst, &device_state.vram[addr], size);
+ else
+ memset(dst, 0xff, size);
}
static uint8_t
static void
__copy_to_vram(uint8_t *src, uint64_t addr, uint64_t size)
{
- memcpy(&device_state.vram[addr], src, size);
+ if (device_state.vram != NULL && device_state.vram_enabled) {
+ memcpy(&device_state.vram[addr], src, size);
+ demu_set_guest_dirty_page((device_state.vram_addr + addr) >> TARGET_PAGE_SHIFT);
+ }
}
static void
vga->vbe_index = val;
}
+static void
+__clear_vram(uint64_t size)
+{
+ if (device_state.vram != NULL && device_state.vram_enabled)
+ memset(device_state.vram, 0, size);
+}
+
static void
device_vbe_data_write(void *priv, uint16_t val)
{
/* 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);
+ __clear_vram(vga->vbe_regs[VBE_DISPI_INDEX_YRES] * vga->vbe_line_offset);
}
/* we initialize the VGA graphic mode (should be done
demu_deregister_port_space(0x3c0);
}
-static uint8_t
-device_vram_readb(void *priv, uint64_t addr)
-{
- uint8_t val;
-
- addr -= device_state.vram_addr;
-
- __copy_from_vram(addr, &val, 1);
-
- return val;
-}
-
-static void
-device_vram_writeb(void *priv, uint64_t addr, uint8_t val)
-{
- addr -= device_state.vram_addr;
-
- __copy_to_vram(&val, addr, 1);
-}
-
-static io_ops_t device_vram_ops = {
- .readb = device_vram_readb,
- .writeb = device_vram_writeb
-};
-
static void
device_vram_bar_enable(void *priv, uint64_t addr)
{
assert(priv == NULL);
+ DBG("%"PRIx64"\n", addr);
+
+ if (device_state.vram_addr == 0)
+ device_state.vram = demu_map_guest_range(addr,
+ device_state.vram_size,
+ TRUE);
+ else if (addr != device_state.vram_addr)
+ (void) demu_relocate_guest_range(device_state.vram_addr,
+ addr,
+ device_state.vram_size);
device_state.vram_addr = addr;
- DBG("%"PRIx64"\n", device_state.vram_addr);
+ device_state.vram_enabled = TRUE;
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;
-
- (void) demu_register_memory_space(device_state.vram_addr,
- device_state.vram_size,
- &device_vram_ops,
- NULL);
}
static void
DBG("%"PRIx64"\n", device_state.vram_addr);
- demu_deregister_memory_space(device_state.vram_addr);
+ demu_track_dirty_vram(0, 0, NULL);
+ device_state.vram_enabled = FALSE;
}
#define PCI_VGA_OFFSET 0x400
int rc;
device_state.vram_size = vram_size;
- device_state.vram = malloc(vram_size);
- if (device_state.vram == NULL)
+ device_state.bitmap = (unsigned long *)malloc(vram_size >> TARGET_PAGE_SHIFT);
+ if (device_state.bitmap == NULL)
goto fail1;
device_vga_reset();
fail2:
DBG("fail2\n");
- free(device_state.vram);
+ free(device_state.bitmap);
fail1:
DBG("fail1\n");
return -1;
}
-uint8_t *device_get_vram(void)
+uint8_t *
+device_get_vram(void)
{
return device_state.vram;
}
-vga_t *device_get_vga(void)
+vga_t *
+device_get_vga(void)
{
return &device_state.vga;
}
-int device_vram_dirty(uint64_t addr, uint64_t size)
+void
+device_vram_get_dirty_map(int enable)
+{
+ if (enable && device_state.vram_enabled)
+ demu_track_dirty_vram(device_state.vram_addr >> TARGET_PAGE_SHIFT,
+ device_state.vram_size >> TARGET_PAGE_SHIFT,
+ device_state.bitmap);
+ else
+ demu_track_dirty_vram(0, 0, NULL);
+}
+
+int
+device_vram_is_dirty(uint64_t addr, uint64_t size)
{
- return 1;
+ xen_pfn_t pfn = addr >> TARGET_PAGE_SHIFT;
+ int n = size >> TARGET_PAGE_SHIFT;
+ int dirty;
+
+ dirty = FALSE;
+ while (--n >= 0) {
+ dirty |= !!(device_state.bitmap[pfn / sizeof(unsigned long) * 8] &
+ (1ul << (pfn % sizeof(unsigned long) * 8)));
+ pfn++;
+ }
+
+ return dirty;
}
void
pci_bar_deregister(0);
pci_device_deregister();
device_vga_deregister();
- free(device_state.vram);
+ free(device_state.bitmap);
}
/*
uint8_t *device_get_vram(void);
vga_t *device_get_vga(void);
-int device_vram_dirty(uint64_t addr, uint64_t size);
+
+void device_vram_get_dirty_map(int enable);
+int device_vram_is_dirty(uint64_t addr, uint64_t size);
#endif /* _DEVICE_H */
continue;
if (entry->ptr != NULL) {
- munmap(entry->ptr, TARGET_PAGE_SIZE);
+ demu_unmap_guest_page(entry->ptr, entry->pfn, FALSE);
entry->ptr = NULL;
}
- entry->ptr = demu_map_guest_page(pfn);
+ entry->ptr = demu_map_guest_page(pfn, FALSE);
if (entry->ptr != NULL)
entry->pfn = pfn;
int faulted;
faulted = 0;
-gain:
+again:
ptr = __mapcache_lookup(pfn);
if (ptr == NULL) {
if (!faulted) {
#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;
static uint8_t get_ar_index(surface_t *s)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->ar_index;
}
static uint8_t get_ar(surface_t *s, int reg)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->ar[reg];
}
static uint8_t get_cr(surface_t *s, int reg)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->cr[reg];
}
static uint8_t get_sr(surface_t *s, int reg)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->sr[reg];
}
static uint8_t get_gr(surface_t *s, int reg)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->gr[reg];
}
static uint8_t get_palette(surface_t *s, int offset)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->palette[offset];
}
static int is_dac_8bit(surface_t *s)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return !!vga->dac_8bit;
}
static int test_and_clear_plane2(surface_t *s)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
uint32_t val;
val = vga->plane_updated & (1 << 2);
static uint16_t get_vbe_regs(surface_t *s, int reg)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->vbe_regs[reg];
}
static uint32_t get_vbe_start_addr(surface_t *s)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->vbe_start_addr;
}
static uint32_t get_vbe_line_offset(surface_t *s)
{
- vga_t *vga = s->vga;
+ vga_t *vga = device_get_vga();
return vga->vbe_line_offset;
}
}
surface_state.graphic_mode = -1;
- surface_state.vram = device_get_vram();
- surface_state.vga = device_get_vga();
return 0;
}
uint32_t *ch_attr_ptr;
vga_draw_glyph8_func *__vga_draw_glyph8;
vga_draw_glyph9_func *__vga_draw_glyph9;
+ uint8_t *vram = device_get_vram();
+
+ assert(vram != NULL);
+
+ device_vram_get_dirty_map(FALSE);
/* compute font data address (in plane 2) */
v = get_sr(s, 3);
s->font_offsets[0] = offset;
full_update = 1;
}
- font_base[0] = s->vram + offset;
+ font_base[0] = vram + offset;
offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
- font_base[1] = s->vram + offset;
+ font_base[1] = vram + offset;
if (offset != s->font_offsets[1]) {
s->font_offsets[1] = offset;
full_update = 1;
full_update |= update_basic_params(s);
line_offset = s->line_offset;
- s1 = s->vram + (s->start_addr * 4);
+ s1 = vram + (s->start_addr * 4);
/* total width & height */
cheight = (get_cr(s, 9) & 0x1f) + 1;
s->cursor_start = get_cr(s, 0xa);
s->cursor_end = get_cr(s, 0xb);
}
- cursor_ptr = s->vram + (s->start_addr + cursor_offset) * 4;
+ cursor_ptr = vram + (s->start_addr + cursor_offset) * 4;
if (cw == 16)
__vga_draw_glyph8 = vga_draw_glyph16;
uint8_t *d;
uint32_t v, addr1, addr;
vga_draw_line_func *__vga_draw_line;
+ uint8_t *vram = device_get_vram();
+
+ assert(vram != NULL);
full_update |= update_basic_params(s);
linesize = s->linesize;
y1 = 0;
+ device_vram_get_dirty_map(TRUE);
+
for(y = 0; y < height; y++) {
addr = addr1;
if (!(get_cr(s, 0x17) & 1)) {
if (!(get_cr(s, 0x17) & 2)) {
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
}
- update = full_update | device_vram_dirty(addr, bwidth);
+ update = full_update | device_vram_is_dirty(addr, bwidth);
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
if (update) {
y_start = y;
plane_enable = get_ar(s, 0x12) & 0xf;
- __vga_draw_line(s->last_palette, plane_enable, d, s->vram + addr, width);
+ __vga_draw_line(s->last_palette, plane_enable, d, vram + addr, width);
} else {
if (y_start >= 0) {
/* flush to display */
{
int val;
+ device_vram_get_dirty_map(FALSE);
+
if (!full_update)
return;
surface_t *s = &surface_state;
int full_update;
int graphic_mode;
+ uint8_t *vram = device_get_vram();
- if (!(get_ar_index(s) & 0x20)) {
+ if (!(get_ar_index(s) & 0x20) || vram == NULL) {
graphic_mode = GMODE_BLANK;
} else {
graphic_mode = get_gr(s, 6) & 1;
}
-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)
{
int surface_initialize(void);
void surface_refresh(void);
-void surface_refresh_test(void);
void surface_teardown(void);
#endif /* _SURFACE_H */