]> xenbits.xensource.com Git - qemu-xen-4.0-testing.git/commitdiff
hvm: Use main memory for video memory.
authorIan Jackson <ian.jackson@eu.citrix.com>
Thu, 11 Sep 2008 11:41:14 +0000 (12:41 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Thu, 11 Sep 2008 11:41:14 +0000 (12:41 +0100)
qemu allocates video memory, the extra 8MB memory ballooning is not
available any more, because it got consumed by the other domain.

This fixes it by taking video memory from the main memory:

- make hvmloader use e820_malloc to reserve some of the main memory
  and notify ioemu of its address through the Xen platform PCI card.
- add XENMAPSPACE_mfn to the xen_add_to_physmap memory op, to allow
  ioemu to move the MFNs between the original position and the PCI
  mapping, when LFB acceleration is disabled/enabled
- add a remove_from_physmap memory op, to allow ioemu to unmap it
  completely for the case of old guests with acceleration disabled.
- add xc_domain_memory_translate_gpfn_list to libxc to allow ioemu to
  get the MFNs of the video memory.
- have xend save the PCI memory space instead of ioemu: if a memory
  page is there, the guest can access it like usual memory, so xend
  can safely be responsible to save it.  The extra benefit is that
  live migration will apply the logdirty optimization there too.
- handle old saved images, populating the video memory from ioemu if
  really needed.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
Cross-ported from xen-unstable
 18383:dade7f0bdc8d6b36b1914598d83c616ee5ce97cb
using patch -l, with only one fixup needed: [un]set_mm_mapping needed
to be removed from hw/cirrus_vga.c rather than vl.c

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
hw/cirrus_vga.c
hw/vga.c
hw/vga_int.h
hw/xen_platform.c
qemu-xen.h

index 14618763804df39fb7d6f6a9bb5eafb20df4e38d..37d2fe5c2ea27cd7aaf2abb747670929ad4341a9 100644 (file)
@@ -2641,65 +2641,28 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
 };
 
 
-/* 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(
@@ -2707,61 +2670,42 @@ static void *set_vram_mapping(unsigned long begin, unsigned long end)
         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 */
@@ -2783,17 +2727,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
        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;
             }
@@ -2803,14 +2737,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
         } 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;
@@ -3169,36 +3096,6 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = {
     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)
@@ -3247,7 +3144,10 @@ 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)
@@ -3256,7 +3156,7 @@ 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) {
@@ -3302,9 +3202,20 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
     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 */
@@ -3426,7 +3337,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     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);
 }
 
 /***************************************
index fd66c086d3b155258d80b54b23ed79db67071dc3..8fbc4e5bdd23cbaf2076c11d7a3d534d654907df 100644 (file)
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -26,6 +26,7 @@
 #include "pc.h"
 #include "pci.h"
 #include "vga_int.h"
+#include <sys/mman.h>
 
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
@@ -1779,7 +1780,10 @@ static void vga_save(QEMUFile *f, void *opaque)
 #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)
@@ -1791,7 +1795,7 @@ 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) {
@@ -1842,7 +1846,14 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id)
        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 */
@@ -1997,6 +2008,100 @@ void vga_bios_init(VGAState *s)
     /* 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)
@@ -2028,13 +2133,9 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
 
     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;
@@ -2054,7 +2155,7 @@ static void vga_init(VGAState *s)
 {
     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);
 
@@ -2166,33 +2267,6 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
     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 */
 
index 06267746aa785aef0b4671e2ae0286e38784d877..188a7553c70f5fc0e3c7d84675c799e3d5cc555a 100644 (file)
@@ -80,9 +80,9 @@
 #define VGA_MAX_HEIGHT 2048
 
 #define VGA_STATE_COMMON                                                \
-    uint8_t *vram_alloc;                                                \
     uint8_t *vram_ptr;                                                  \
-    uint8_t *vram_shadow;                                               \
+    xen_pfn_t *vram_mfns;                                               \
+    uint64_t stolen_vram_addr; /* Address of stolen RAM */              \
     unsigned long vram_offset;                                          \
     unsigned int vram_size;                                             \
     unsigned long bios_offset;                                          \
index 430e603054309483d8bd4ffc33f6cd2daa3c3b4a..75a0a28cd83b375171b6b070ea7cb8faff5d9f2e 100644 (file)
@@ -37,6 +37,7 @@ typedef struct PCIXenPlatformState
 {
   PCIDevice  pci_dev;
   uint8_t    platform_flags;
+  uint64_t   vga_stolen_ram;
 } PCIXenPlatformState;
 
 static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
@@ -72,11 +73,46 @@ static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val
 }
 
 
+static uint32_t xen_platform_ioport_readl(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *d = opaque;
+
+    addr  &= 0xff;
+
+    switch (addr) {
+    case 4: /* VGA stolen memory address */
+        return d->vga_stolen_ram;
+    default:
+        return ~0u;
+    }
+}
+
+static void xen_platform_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *d = opaque;
+
+    addr &= 0xff;
+    val  &= 0xffffffff;
+
+    switch (addr) {
+    case 4: /* VGA stolen memory address */
+        d->vga_stolen_ram = val;
+        xen_vga_stolen_vram_addr(val);
+        break;
+    default:
+        break;
+    }
+}
+
+
+
 static void platform_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type)
 {
     PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev;
     register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
+    register_ioport_write(addr, size, 4, xen_platform_ioport_writel, d);
     register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
+    register_ioport_read(addr, size, 4, xen_platform_ioport_readl, d);
 }
 
 static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr)
@@ -158,6 +194,7 @@ void xen_pci_save(QEMUFile *f, void *opaque)
 
     pci_device_save(&d->pci_dev, f);
     qemu_put_8s(f, &d->platform_flags);
+    qemu_put_be64s(f, &d->vga_stolen_ram);
 }
 
 int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
@@ -176,6 +213,7 @@ int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
         uint8_t flags;
         qemu_get_8s(f, &flags);
         xen_platform_ioport_writeb(d, 0, flags);
+        qemu_get_be64s(f, &d->vga_stolen_ram);
     }
 
     return 0;
index 06d8ec9f4c41695dba08cf8c68500878f0d051d5..2598c15151018d860cfd270594fe5b2bc2aa30d5 100644 (file)
@@ -21,6 +21,9 @@ void timeoffset_get(void);
 /* xen_platform.c */
 #ifndef QEMU_TOOL
 void pci_xen_platform_init(PCIBus *bus);
+void xen_vga_stolen_vram_addr(uint64_t vram_addr);
+void xen_vga_populate_vram(uint64_t vram_addr);
+void xen_vga_vram_map(uint64_t vram_addr, int copy);
 #endif