};
-/* FIXME Flush the shadow page */
-static int unset_mm_mapping(int xc_handle, uint32_t domid,
- unsigned long nr_pages, unsigned int address_bits,
- xen_pfn_t *extent_start)
+static void set_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
{
- int err = 0;
+ unsigned long i;
+ struct xen_add_to_physmap xatp;
+ int rc;
- err = xc_domain_memory_decrease_reservation(xc_handle, domid,
- nr_pages, 0, extent_start);
- if (err)
- fprintf(stderr, "Failed to decrease physmap\n");
+ if (end > begin + VGA_RAM_SIZE)
+ end = begin + VGA_RAM_SIZE;
- return err;
-}
-
-static int set_mm_mapping(int xc_handle, uint32_t domid,
- unsigned long nr_pages, unsigned int address_bits,
- xen_pfn_t *extent_start)
-{
- int err = 0;
-
- err = xc_domain_memory_populate_physmap(xc_handle, domid, nr_pages, 0,
- address_bits, extent_start);
- if (err) {
- fprintf(stderr, "Failed to populate physmap\n");
- return -1;
- }
-
- return 0;
-}
-
-static void *set_vram_mapping(unsigned long begin, unsigned long end)
-{
- xen_pfn_t *extent_start = NULL;
- unsigned long nr_extents;
- void *vram_pointer = NULL;
- int i;
-
- /* align begin and end address */
- begin = begin & TARGET_PAGE_MASK;
- end = begin + VGA_RAM_SIZE;
- end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK;
- nr_extents = (end - begin) >> TARGET_PAGE_BITS;
-
- extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
- if (extent_start == NULL) {
- fprintf(stderr, "Failed malloc on set_vram_mapping\n");
- return NULL;
- }
-
- memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
+ fprintf(logfile,"mapping vram to %lx - %lx\n", begin, end);
- for (i = 0; i < nr_extents; i++)
- extent_start[i] = (begin + i * TARGET_PAGE_SIZE) >> TARGET_PAGE_BITS;
+ xatp.domid = domid;
+ xatp.space = XENMAPSPACE_mfn;
- if (set_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start) < 0) {
- fprintf(logfile, "Failed set_mm_mapping\n");
- free(extent_start);
- return NULL;
+ for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) {
+ xatp.idx = s->vram_mfns[i];
+ xatp.gpfn = (begin >> TARGET_PAGE_BITS) + i;
+ rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
+ if (rc) {
+ fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"PRI_xen_pfn" failed: %d\n", xatp.idx, xatp.gpfn, rc);
+ return;
+ }
}
(void)xc_domain_pin_memory_cacheattr(
begin >> TARGET_PAGE_BITS,
end >> TARGET_PAGE_BITS,
XEN_DOMCTL_MEM_CACHEATTR_WB);
-
- vram_pointer = xc_map_foreign_pages(xc_handle, domid,
- PROT_READ|PROT_WRITE,
- extent_start, nr_extents);
- if (vram_pointer == NULL) {
- fprintf(logfile, "xc_map_foreign_batch vgaram returned error %d\n",
- errno);
- free(extent_start);
- return NULL;
- }
-
- memset(vram_pointer, 0, nr_extents * TARGET_PAGE_SIZE);
-
-#ifdef CONFIG_STUBDOM
- xenfb_pv_display_start(vram_pointer);
-#endif
-
- free(extent_start);
-
- return vram_pointer;
}
-static int unset_vram_mapping(unsigned long begin, unsigned long end,
- void *mapping)
+static void unset_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
{
- xen_pfn_t *extent_start = NULL;
- unsigned long nr_extents;
- int i;
+ if (s->stolen_vram_addr) {
+ /* We can put it there for xend to save it efficiently */
+ set_vram_mapping(s, s->stolen_vram_addr, s->stolen_vram_addr + VGA_RAM_SIZE);
+ } else {
+ /* Old image, we have to unmap them completely */
+ struct xen_remove_from_physmap xrfp;
+ unsigned long i;
+ int rc;
- /* align begin and end address */
+ if (end > begin + VGA_RAM_SIZE)
+ end = begin + VGA_RAM_SIZE;
- end = begin + VGA_RAM_SIZE;
- begin = begin & TARGET_PAGE_MASK;
- end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK;
- nr_extents = (end - begin) >> TARGET_PAGE_BITS;
+ fprintf(logfile,"unmapping vram from %lx - %lx\n", begin, end);
- extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
+ xrfp.domid = domid;
- if (extent_start == NULL) {
- fprintf(stderr, "Failed malloc on set_mm_mapping\n");
- return -1;
+ for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) {
+ xrfp.gpfn = (begin >> TARGET_PAGE_BITS) + i;
+ rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp);
+ if (rc) {
+ fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc);
+ return;
+ }
+ }
}
+}
- /* Drop our own references to the vram pages */
- munmap(mapping, nr_extents * TARGET_PAGE_SIZE);
-
- /* Now drop the guest's mappings */
- memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
- for (i = 0; i < nr_extents; i++)
- extent_start[i] = (begin + (i * TARGET_PAGE_SIZE)) >> TARGET_PAGE_BITS;
- unset_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start);
-
- free(extent_start);
-
- return 0;
+void cirrus_restart_acc(CirrusVGAState *s)
+{
+ set_vram_mapping(s, s->lfb_addr, s->lfb_end);
+ s->map_addr = s->lfb_addr;
+ s->map_end = s->lfb_end;
}
/* Compute the memory access functions */
mode = s->gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
if (s->lfb_addr && s->lfb_end && !s->map_addr) {
- void *vram_pointer, *old_vram;
-
- vram_pointer = set_vram_mapping(s->lfb_addr,
- s->lfb_end);
- if (!vram_pointer)
- fprintf(stderr, "NULL vram_pointer\n");
- else {
- old_vram = vga_update_vram((VGAState *)s, vram_pointer,
- VGA_RAM_SIZE);
- qemu_free(old_vram);
- }
+ set_vram_mapping(s, s->lfb_addr, s->lfb_end);
s->map_addr = s->lfb_addr;
s->map_end = s->lfb_end;
}
} else {
generic_io:
if (s->lfb_addr && s->lfb_end && s->map_addr) {
- void *old_vram;
-
- old_vram = vga_update_vram((VGAState *)s, NULL, VGA_RAM_SIZE);
-
- unset_vram_mapping(s->lfb_addr,
- s->lfb_end,
- old_vram);
-
+ unset_vram_mapping(s, s->map_addr, s->map_end);
s->map_addr = s->map_end = 0;
}
s->cirrus_linear_write[0] = cirrus_linear_writeb;
cirrus_mmio_writel,
};
-void cirrus_stop_acc(CirrusVGAState *s)
-{
- if (s->map_addr){
- int error;
- s->map_addr = 0;
- error = unset_vram_mapping(s->lfb_addr,
- s->lfb_end, s->vram_ptr);
- fprintf(stderr, "cirrus_stop_acc:unset_vram_mapping.\n");
- }
-}
-
-void cirrus_restart_acc(CirrusVGAState *s)
-{
- if (s->lfb_addr && s->lfb_end) {
- void *vram_pointer, *old_vram;
- fprintf(stderr, "cirrus_vga_load:re-enable vga acc.lfb_addr=0x%lx, lfb_end=0x%lx.\n",
- s->lfb_addr, s->lfb_end);
- vram_pointer = set_vram_mapping(s->lfb_addr ,s->lfb_end);
- if (!vram_pointer){
- fprintf(stderr, "cirrus_vga_load:NULL vram_pointer\n");
- } else {
- old_vram = vga_update_vram((VGAState *)s, vram_pointer,
- VGA_RAM_SIZE);
- qemu_free(old_vram);
- s->map_addr = s->lfb_addr;
- s->map_end = s->lfb_end;
- }
- }
-}
-
/* load/save state */
static void cirrus_vga_save(QEMUFile *f, void *opaque)
qemu_put_8s(f, &vga_acc);
qemu_put_be64s(f, (uint64_t*)&s->lfb_addr);
qemu_put_be64s(f, (uint64_t*)&s->lfb_end);
- qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
+ qemu_put_be64s(f, &s->stolen_vram_addr);
+ if (!s->stolen_vram_addr && !vga_acc)
+ /* Old guest: VRAM is not mapped, we have to save it ourselves */
+ qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
}
static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
uint8_t vga_acc = 0;
int ret;
- if (version_id > 2)
+ if (version_id > 3)
return -EINVAL;
if (s->pci_dev && version_id >= 2) {
qemu_get_8s(f, &vga_acc);
qemu_get_be64s(f, (uint64_t*)&s->lfb_addr);
qemu_get_be64s(f, (uint64_t*)&s->lfb_end);
- qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
- if (vga_acc){
- cirrus_restart_acc(s);
+ if (version_id >= 3) {
+ qemu_get_be64s(f, &s->stolen_vram_addr);
+ if (!s->stolen_vram_addr && !vga_acc) {
+ /* Old guest, VRAM is not mapped, we have to restore it ourselves */
+ qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
+ xen_vga_populate_vram(s->lfb_addr);
+ } else
+ xen_vga_vram_map(vga_acc ? s->lfb_addr : s->stolen_vram_addr, 0);
+ } else {
+ /* Old image, we have to populate and restore VRAM ourselves */
+ xen_vga_populate_vram(s->lfb_addr);
+ qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
+ if (vga_acc)
+ cirrus_restart_acc(s);
}
/* force refresh */
s->cursor_invalidate = cirrus_cursor_invalidate;
s->cursor_draw_line = cirrus_cursor_draw_line;
- register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);
+ register_savevm("cirrus_vga", 0, 3, cirrus_vga_save, cirrus_vga_load, s);
}
/***************************************
#include "pc.h"
#include "pci.h"
#include "vga_int.h"
+#include <sys/mman.h>
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
#endif
vram_size = s->vram_size;
qemu_put_be32s(f, &vram_size);
- qemu_put_buffer(f, s->vram_ptr, s->vram_size);
+ qemu_put_be64s(f, &s->stolen_vram_addr);
+ if (!s->stolen_vram_addr)
+ /* Old guest: VRAM is not mapped, we have to save it ourselves */
+ qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
}
static int vga_load(QEMUFile *f, void *opaque, int version_id)
int i;
#endif
- if (version_id > 3)
+ if (version_id > 4)
return -EINVAL;
if (s->pci_dev && version_id >= 2) {
qemu_get_be32s(f, &vram_size);
if (vram_size != s->vram_size)
return -EINVAL;
- qemu_get_buffer(f, s->vram_ptr, s->vram_size);
+ if (version_id >= 4) {
+ qemu_get_be64s(f, &s->stolen_vram_addr);
+ if (s->stolen_vram_addr)
+ xen_vga_vram_map(s->stolen_vram_addr, 0);
+ }
+ /* Old guest, VRAM is not mapped, we have to restore it ourselves */
+ if (!s->stolen_vram_addr)
+ qemu_get_buffer(f, s->vram_ptr, s->vram_size);
}
/* force refresh */
/* TODO: add vbe support if enabled */
}
+
+static VGAState *xen_vga_state;
+
+/* When loading old images we have to populate the video ram ourselves */
+void xen_vga_populate_vram(uint64_t vram_addr)
+{
+ unsigned long nr_pfn;
+ struct xen_remove_from_physmap xrfp;
+ xen_pfn_t *pfn_list;
+ int i;
+ int rc;
+
+ fprintf(logfile, "populating video RAM at %lx\n", vram_addr);
+
+ nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS;
+
+ pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
+
+ for (i = 0; i < nr_pfn; i++)
+ pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
+
+ if (xc_domain_memory_populate_physmap(xc_handle, domid, nr_pfn, 0, 0, pfn_list)) {
+ fprintf(stderr, "Failed to populate video ram\n");
+ exit(1);
+ }
+ free(pfn_list);
+
+ xen_vga_vram_map(vram_addr, 0);
+
+ /* Unmap them from the guest for now. */
+ xrfp.domid = domid;
+ for (i = 0; i < nr_pfn; i++) {
+ xrfp.gpfn = (vram_addr >> TARGET_PAGE_BITS) + i;
+ rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp);
+ if (rc) {
+ fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc);
+ break;
+ }
+ }
+}
+
+/* Called once video memory has been allocated in the GPFN space */
+void xen_vga_vram_map(uint64_t vram_addr, int copy)
+{
+ unsigned long nr_pfn;
+ xen_pfn_t *pfn_list;
+ int i;
+ void *vram;
+
+ fprintf(logfile, "mapping video RAM from %lx\n", vram_addr);
+
+ nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS;
+
+ pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
+
+ for (i = 0; i < nr_pfn; i++)
+ pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
+
+ vram = xc_map_foreign_pages(xc_handle, domid,
+ PROT_READ|PROT_WRITE,
+ pfn_list, nr_pfn);
+
+ if (!vram) {
+ fprintf(stderr, "Failed to map vram\n");
+ exit(1);
+ }
+
+ if (xc_domain_memory_translate_gpfn_list(xc_handle, domid, nr_pfn,
+ pfn_list, pfn_list)) {
+ fprintf(stderr, "Failed translation in xen_vga_vram_addr\n");
+ exit(1);
+ }
+
+ if (copy)
+ memcpy(vram, xen_vga_state->vram_ptr, VGA_RAM_SIZE);
+ qemu_free(xen_vga_state->vram_ptr);
+ xen_vga_state->vram_ptr = vram;
+ xen_vga_state->vram_mfns = pfn_list;
+#ifdef CONFIG_STUBDOM
+ xenfb_pv_display_start(vram);
+#endif
+}
+
+/* Called at boot time when the BIOS has allocated video RAM */
+void xen_vga_stolen_vram_addr(uint64_t stolen_vram_addr)
+{
+ fprintf(logfile, "stolen video RAM at %lx\n", stolen_vram_addr);
+
+ xen_vga_state->stolen_vram_addr = stolen_vram_addr;
+
+ /* And copy from the initialization value */
+ xen_vga_vram_map(stolen_vram_addr, 1);
+}
+
/* when used on xen environment, the vga_ram_base is not used */
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size)
vga_reset(s);
- /* Video RAM must be page-aligned for PVFB memory sharing */
- s->vram_ptr = s->vram_alloc = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size);
-
-#ifdef CONFIG_STUBDOM
- if (!cirrus_vga_enabled)
- xenfb_pv_display_start(s->vram_ptr);
-#endif
+ s->vram_ptr = qemu_malloc(vga_ram_size);
+ s->vram_mfns = NULL;
+ xen_vga_state = s;
s->vram_offset = vga_ram_offset;
s->vram_size = vga_ram_size;
{
int vga_io_memory;
- register_savevm("vga", 0, 3, vga_save, vga_load, s);
+ register_savevm("vga", 0, 4, vga_save, vga_load, s);
register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
return 0;
}
-void *vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size)
-{
- uint8_t *old_pointer;
-
- if (s->vram_size != vga_ram_size) {
- fprintf(stderr, "No support to change vga_ram_size\n");
- return NULL;
- }
-
- if (!vga_ram_base) {
- vga_ram_base = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size + TARGET_PAGE_SIZE + 1);
- if (!vga_ram_base) {
- fprintf(stderr, "reallocate error\n");
- return NULL;
- }
- }
-
- /* XXX lock needed? */
- old_pointer = s->vram_alloc;
- s->vram_alloc = vga_ram_base;
- vga_ram_base = (uint8_t *)((long)(vga_ram_base + 15) & ~15L);
- memcpy(vga_ram_base, s->vram_ptr, vga_ram_size);
- s->vram_ptr = vga_ram_base;
-
- return old_pointer;
-}
-
/********************************************************/
/* vga screen dump */