ia64/xen-unstable

changeset 18394:dade7f0bdc8d

hvm: Use main memory for video memory.

When creating an HVM domain, if e.g. another domain is created before
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>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 14:53:39 2008 +0100 (2008-08-27)
parents 2397555ebcc2
children 03bdbb7e7add
files tools/firmware/hvmloader/32bitbios_support.c tools/firmware/hvmloader/acpi/build.c tools/firmware/hvmloader/hvmloader.c tools/firmware/hvmloader/util.c tools/firmware/hvmloader/util.h tools/ioemu/hw/cirrus_vga.c tools/ioemu/hw/vga.c tools/ioemu/hw/vga_int.h tools/ioemu/hw/xen_platform.c tools/ioemu/vl.c tools/ioemu/vl.h tools/libxc/xc_domain.c tools/libxc/xc_domain_save.c tools/libxc/xenctrl.h xen/arch/ia64/xen/mm.c xen/arch/x86/mm.c xen/arch/x86/x86_64/compat/mm.c xen/include/public/memory.h xen/include/xlat.lst xen/include/xsm/xsm.h xen/xsm/dummy.c xen/xsm/flask/hooks.c
line diff
     1.1 --- a/tools/firmware/hvmloader/32bitbios_support.c	Wed Aug 27 13:31:01 2008 +0100
     1.2 +++ b/tools/firmware/hvmloader/32bitbios_support.c	Wed Aug 27 14:53:39 2008 +0100
     1.3 @@ -76,7 +76,7 @@ static void relocate_32bitbios(char *elf
     1.4       */
     1.5      reloc_size = reloc_off;
     1.6      printf("%d bytes of ROMBIOS high-memory extensions:\n", reloc_size);
     1.7 -    highbiosarea = (char *)(long)e820_malloc(reloc_size);
     1.8 +    highbiosarea = (char *)(long)e820_malloc(reloc_size, 0);
     1.9      BUG_ON(highbiosarea == NULL);
    1.10      printf("  Relocating to 0x%x-0x%x ... ",
    1.11             (uint32_t)&highbiosarea[0],
     2.1 --- a/tools/firmware/hvmloader/acpi/build.c	Wed Aug 27 13:31:01 2008 +0100
     2.2 +++ b/tools/firmware/hvmloader/acpi/build.c	Wed Aug 27 14:53:39 2008 +0100
     2.3 @@ -233,7 +233,7 @@ static int construct_secondary_tables(ui
     2.4          tcpa->header.oem_revision = ACPI_OEM_REVISION;
     2.5          tcpa->header.creator_id   = ACPI_CREATOR_ID;
     2.6          tcpa->header.creator_revision = ACPI_CREATOR_REVISION;
     2.7 -        tcpa->lasa = e820_malloc(ACPI_2_0_TCPA_LAML_SIZE);
     2.8 +        tcpa->lasa = e820_malloc(ACPI_2_0_TCPA_LAML_SIZE, 0);
     2.9          if ( tcpa->lasa )
    2.10          {
    2.11              tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE;
    2.12 @@ -363,7 +363,7 @@ void acpi_build_tables(void)
    2.13      memset(buf, 0, high_sz);
    2.14  
    2.15      /* Allocate data area and set up ACPI tables there. */
    2.16 -    buf = (uint8_t *)e820_malloc(high_sz);
    2.17 +    buf = (uint8_t *)e820_malloc(high_sz, 0);
    2.18      __acpi_build_tables(buf, &low_sz, &high_sz);
    2.19  
    2.20      printf(" - Lo data: %08lx-%08lx\n"
     3.1 --- a/tools/firmware/hvmloader/hvmloader.c	Wed Aug 27 13:31:01 2008 +0100
     3.2 +++ b/tools/firmware/hvmloader/hvmloader.c	Wed Aug 27 14:53:39 2008 +0100
     3.3 @@ -430,12 +430,14 @@ static void cmos_write_memory_size(void)
     3.4      cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
     3.5  }
     3.6  
     3.7 -static void init_xen_platform_io_base(void)
     3.8 +static uint16_t init_xen_platform_io_base(void)
     3.9  {
    3.10      struct bios_info *bios_info = (struct bios_info *)ACPI_PHYSICAL_ADDRESS;
    3.11      uint32_t devfn, bar_data;
    3.12      uint16_t vendor_id, device_id;
    3.13  
    3.14 +    bios_info->xen_pfiob = 0;
    3.15 +
    3.16      for ( devfn = 0; devfn < 128; devfn++ )
    3.17      {
    3.18          vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
    3.19 @@ -445,12 +447,16 @@ static void init_xen_platform_io_base(vo
    3.20          bar_data = pci_readl(devfn, PCI_BASE_ADDRESS_0);
    3.21          bios_info->xen_pfiob = bar_data & PCI_BASE_ADDRESS_IO_MASK;
    3.22      }
    3.23 +
    3.24 +    return bios_info->xen_pfiob;
    3.25  }
    3.26  
    3.27  int main(void)
    3.28  {
    3.29      int vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
    3.30      int extboot_sz = 0;
    3.31 +    uint32_t vga_ram = 0;
    3.32 +    uint16_t xen_pfiob;
    3.33  
    3.34      printf("HVM Loader\n");
    3.35  
    3.36 @@ -497,6 +503,12 @@ int main(void)
    3.37          break;
    3.38      }
    3.39  
    3.40 +    if ( virtual_vga != VGA_none )
    3.41 +    {
    3.42 +        vga_ram = e820_malloc(8 << 20, 4096);
    3.43 +        printf("VGA RAM at %08x\n", vga_ram);
    3.44 +    }
    3.45 +
    3.46      etherboot_sz = scan_etherboot_nic((void*)ETHERBOOT_PHYSICAL_ADDRESS);
    3.47  
    3.48      if ( must_load_extboot() )
    3.49 @@ -537,7 +549,9 @@ int main(void)
    3.50                 ROMBIOS_PHYSICAL_ADDRESS,
    3.51                 ROMBIOS_PHYSICAL_ADDRESS + rombios_sz - 1);
    3.52  
    3.53 -    init_xen_platform_io_base();
    3.54 +    xen_pfiob = init_xen_platform_io_base();
    3.55 +    if ( xen_pfiob && vga_ram )
    3.56 +        outl(xen_pfiob + 4, vga_ram);
    3.57  
    3.58      printf("Invoking ROMBIOS ...\n");
    3.59      return 0;
     4.1 --- a/tools/firmware/hvmloader/util.c	Wed Aug 27 13:31:01 2008 +0100
     4.2 +++ b/tools/firmware/hvmloader/util.c	Wed Aug 27 14:53:39 2008 +0100
     4.3 @@ -325,35 +325,34 @@ static void e820_collapse(void)
     4.4      }
     4.5  }
     4.6  
     4.7 -uint32_t e820_malloc(uint32_t size)
     4.8 +uint32_t e820_malloc(uint32_t size, uint32_t align)
     4.9  {
    4.10      uint32_t addr;
    4.11      int i;
    4.12      struct e820entry *ent = (struct e820entry *)HVM_E820;
    4.13  
    4.14 -    /* Align allocation request to a reasonable boundary (1kB). */
    4.15 -    size = (size + 1023) & ~1023;
    4.16 +    /* Align to at leats one kilobyte. */
    4.17 +    if ( align < 1024 )
    4.18 +        align = 1024;
    4.19  
    4.20      for ( i = *HVM_E820_NR - 1; i >= 0; i-- )
    4.21      {
    4.22 -        addr = ent[i].addr;
    4.23 +        addr = (ent[i].size - size) & ~(align-1);
    4.24          if ( (ent[i].type != E820_RAM) || /* not ram? */
    4.25 -             (ent[i].size < size) ||      /* too small? */
    4.26 -             (addr != ent[i].addr) ||     /* starts above 4gb? */
    4.27 +             (addr < ent[i].addr) ||      /* too small or starts above 4gb? */
    4.28               ((addr + size) < addr) )     /* ends above 4gb? */
    4.29              continue;
    4.30  
    4.31 -        if ( ent[i].size != size )
    4.32 +        if ( addr != ent[i].addr )
    4.33          {
    4.34              memmove(&ent[i+1], &ent[i], (*HVM_E820_NR-i) * sizeof(*ent));
    4.35              (*HVM_E820_NR)++;
    4.36 -            ent[i].size -= size;
    4.37 -            addr += ent[i].size;
    4.38 +            ent[i].size = addr - ent[i].addr;
    4.39 +            ent[i+1].addr = addr;
    4.40 +            ent[i+1].size -= ent[i].size;
    4.41              i++;
    4.42          }
    4.43  
    4.44 -        ent[i].addr = addr;
    4.45 -        ent[i].size = size;
    4.46          ent[i].type = E820_RESERVED;
    4.47  
    4.48          e820_collapse();
     5.1 --- a/tools/firmware/hvmloader/util.h	Wed Aug 27 13:31:01 2008 +0100
     5.2 +++ b/tools/firmware/hvmloader/util.h	Wed Aug 27 14:53:39 2008 +0100
     5.3 @@ -132,7 +132,7 @@ int printf(const char *fmt, ...) __attri
     5.4  int vprintf(const char *fmt, va_list ap);
     5.5  
     5.6  /* Reserve a RAM region in the e820 table. */
     5.7 -uint32_t e820_malloc(uint32_t size);
     5.8 +uint32_t e820_malloc(uint32_t size, uint32_t align);
     5.9  
    5.10  /* Prepare the 32bit BIOS */
    5.11  void highbios_setup(void);
     6.1 --- a/tools/ioemu/hw/cirrus_vga.c	Wed Aug 27 13:31:01 2008 +0100
     6.2 +++ b/tools/ioemu/hw/cirrus_vga.c	Wed Aug 27 14:53:39 2008 +0100
     6.3 @@ -2543,34 +2543,28 @@ static CPUWriteMemoryFunc *cirrus_linear
     6.4      cirrus_linear_bitblt_writel,
     6.5  };
     6.6  
     6.7 -static void *set_vram_mapping(unsigned long begin, unsigned long end)
     6.8 +static void set_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
     6.9  {
    6.10 -    xen_pfn_t *extent_start = NULL;
    6.11 -    unsigned long nr_extents;
    6.12 -    void *vram_pointer = NULL;
    6.13 -    int i;
    6.14 -
    6.15 -    /* align begin and end address */
    6.16 -    begin = begin & TARGET_PAGE_MASK;
    6.17 -    end = begin + VGA_RAM_SIZE;
    6.18 -    end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK;
    6.19 -    nr_extents = (end - begin) >> TARGET_PAGE_BITS;
    6.20 -
    6.21 -    extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
    6.22 -    if (extent_start == NULL) {
    6.23 -        fprintf(stderr, "Failed malloc on set_vram_mapping\n");
    6.24 -        return NULL;
    6.25 -    }
    6.26 -
    6.27 -    memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
    6.28 -
    6.29 -    for (i = 0; i < nr_extents; i++)
    6.30 -        extent_start[i] = (begin + i * TARGET_PAGE_SIZE) >> TARGET_PAGE_BITS;
    6.31 -
    6.32 -    if (set_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start) < 0) {
    6.33 -        fprintf(logfile, "Failed set_mm_mapping\n");
    6.34 -        free(extent_start);
    6.35 -        return NULL;
    6.36 +    unsigned long i;
    6.37 +    struct xen_add_to_physmap xatp;
    6.38 +    int rc;
    6.39 +
    6.40 +    if (end > begin + VGA_RAM_SIZE)
    6.41 +        end = begin + VGA_RAM_SIZE;
    6.42 +
    6.43 +    fprintf(logfile,"mapping vram to %lx - %lx\n", begin, end);
    6.44 +
    6.45 +    xatp.domid = domid;
    6.46 +    xatp.space = XENMAPSPACE_mfn;
    6.47 +
    6.48 +    for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) {
    6.49 +        xatp.idx = s->vram_mfns[i];
    6.50 +        xatp.gpfn = (begin >> TARGET_PAGE_BITS) + i;
    6.51 +        rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
    6.52 +        if (rc) {
    6.53 +            fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"PRI_xen_pfn" failed: %d\n", xatp.idx, xatp.gpfn, rc);
    6.54 +            return;
    6.55 +        }
    6.56      }
    6.57  
    6.58      (void)xc_domain_pin_memory_cacheattr(
    6.59 @@ -2578,61 +2572,42 @@ static void *set_vram_mapping(unsigned l
    6.60          begin >> TARGET_PAGE_BITS,
    6.61          end >> TARGET_PAGE_BITS,
    6.62          XEN_DOMCTL_MEM_CACHEATTR_WB);
    6.63 -
    6.64 -    vram_pointer = xc_map_foreign_pages(xc_handle, domid,
    6.65 -                                        PROT_READ|PROT_WRITE,
    6.66 -                                        extent_start, nr_extents);
    6.67 -    if (vram_pointer == NULL) {
    6.68 -        fprintf(logfile, "xc_map_foreign_batch vgaram returned error %d\n",
    6.69 -                errno);
    6.70 -        free(extent_start);
    6.71 -        return NULL;
    6.72 -    }
    6.73 -
    6.74 -    memset(vram_pointer, 0, nr_extents * TARGET_PAGE_SIZE);
    6.75 -
    6.76 -#ifdef CONFIG_STUBDOM
    6.77 -    xenfb_pv_display_start(vram_pointer);
    6.78 -#endif
    6.79 -
    6.80 -    free(extent_start);
    6.81 -
    6.82 -    return vram_pointer;
    6.83  }
    6.84  
    6.85 -static int unset_vram_mapping(unsigned long begin, unsigned long end, 
    6.86 -                              void *mapping)
    6.87 +static void unset_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
    6.88  {
    6.89 -    xen_pfn_t *extent_start = NULL;
    6.90 -    unsigned long nr_extents;
    6.91 -    int i;
    6.92 -
    6.93 -    /* align begin and end address */
    6.94 -
    6.95 -    end = begin + VGA_RAM_SIZE;
    6.96 -    begin = begin & TARGET_PAGE_MASK;
    6.97 -    end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK;
    6.98 -    nr_extents = (end - begin) >> TARGET_PAGE_BITS;
    6.99 -
   6.100 -    extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
   6.101 -
   6.102 -    if (extent_start == NULL) {
   6.103 -        fprintf(stderr, "Failed malloc on set_mm_mapping\n");
   6.104 -        return -1;
   6.105 +    if (s->stolen_vram_addr) {
   6.106 +        /* We can put it there for xend to save it efficiently */
   6.107 +        set_vram_mapping(s, s->stolen_vram_addr, s->stolen_vram_addr + VGA_RAM_SIZE);
   6.108 +    } else {
   6.109 +        /* Old image, we have to unmap them completely */
   6.110 +        struct xen_remove_from_physmap xrfp;
   6.111 +        unsigned long i;
   6.112 +        int rc;
   6.113 +
   6.114 +        if (end > begin + VGA_RAM_SIZE)
   6.115 +            end = begin + VGA_RAM_SIZE;
   6.116 +
   6.117 +        fprintf(logfile,"unmapping vram from %lx - %lx\n", begin, end);
   6.118 +
   6.119 +        xrfp.domid = domid;
   6.120 +
   6.121 +        for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) {
   6.122 +            xrfp.gpfn = (begin >> TARGET_PAGE_BITS) + i;
   6.123 +            rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp);
   6.124 +            if (rc) {
   6.125 +                fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc);
   6.126 +                return;
   6.127 +            }
   6.128 +        }
   6.129      }
   6.130 -
   6.131 -    /* Drop our own references to the vram pages */
   6.132 -    munmap(mapping, nr_extents * TARGET_PAGE_SIZE);
   6.133 -
   6.134 -    /* Now drop the guest's mappings */
   6.135 -    memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
   6.136 -    for (i = 0; i < nr_extents; i++)
   6.137 -        extent_start[i] = (begin + (i * TARGET_PAGE_SIZE)) >> TARGET_PAGE_BITS;
   6.138 -    unset_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start);
   6.139 -
   6.140 -    free(extent_start);
   6.141 -
   6.142 -    return 0;
   6.143 +}
   6.144 +
   6.145 +void cirrus_restart_acc(CirrusVGAState *s)
   6.146 +{
   6.147 +    set_vram_mapping(s, s->lfb_addr, s->lfb_end);
   6.148 +    s->map_addr = s->lfb_addr;
   6.149 +    s->map_end = s->lfb_end;
   6.150  }
   6.151  
   6.152  /* Compute the memory access functions */
   6.153 @@ -2654,17 +2629,7 @@ static void cirrus_update_memory_access(
   6.154  	mode = s->gr[0x05] & 0x7;
   6.155  	if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
   6.156              if (s->lfb_addr && s->lfb_end && !s->map_addr) {
   6.157 -                void *vram_pointer, *old_vram;
   6.158 -
   6.159 -                vram_pointer = set_vram_mapping(s->lfb_addr,
   6.160 -                                                s->lfb_end);
   6.161 -                if (!vram_pointer)
   6.162 -                    fprintf(stderr, "NULL vram_pointer\n");
   6.163 -                else {
   6.164 -                    old_vram = vga_update_vram((VGAState *)s, vram_pointer,
   6.165 -                                               VGA_RAM_SIZE);
   6.166 -                    qemu_free(old_vram);
   6.167 -                }
   6.168 +                set_vram_mapping(s, s->lfb_addr, s->lfb_end);
   6.169                  s->map_addr = s->lfb_addr;
   6.170                  s->map_end = s->lfb_end;
   6.171              }
   6.172 @@ -2674,14 +2639,7 @@ static void cirrus_update_memory_access(
   6.173          } else {
   6.174          generic_io:
   6.175              if (s->lfb_addr && s->lfb_end && s->map_addr) {
   6.176 -                void *old_vram;
   6.177 -
   6.178 -                old_vram = vga_update_vram((VGAState *)s, NULL, VGA_RAM_SIZE);
   6.179 -
   6.180 -                unset_vram_mapping(s->lfb_addr,
   6.181 -                                   s->lfb_end, 
   6.182 -                                   old_vram);
   6.183 -
   6.184 +                unset_vram_mapping(s, s->map_addr, s->map_end);
   6.185                  s->map_addr = s->map_end = 0;
   6.186              }
   6.187              s->cirrus_linear_write[0] = cirrus_linear_writeb;
   6.188 @@ -3040,36 +2998,6 @@ static CPUWriteMemoryFunc *cirrus_mmio_w
   6.189      cirrus_mmio_writel,
   6.190  };
   6.191  
   6.192 -void cirrus_stop_acc(CirrusVGAState *s)
   6.193 -{
   6.194 -    if (s->map_addr){
   6.195 -        int error;
   6.196 -        s->map_addr = 0;
   6.197 -        error = unset_vram_mapping(s->lfb_addr,
   6.198 -                s->lfb_end, s->vram_ptr);
   6.199 -        fprintf(stderr, "cirrus_stop_acc:unset_vram_mapping.\n");
   6.200 -    }
   6.201 -}
   6.202 -
   6.203 -void cirrus_restart_acc(CirrusVGAState *s)
   6.204 -{
   6.205 -    if (s->lfb_addr && s->lfb_end) {
   6.206 -        void *vram_pointer, *old_vram;
   6.207 -        fprintf(stderr, "cirrus_vga_load:re-enable vga acc.lfb_addr=0x%lx, lfb_end=0x%lx.\n",
   6.208 -                s->lfb_addr, s->lfb_end);
   6.209 -        vram_pointer = set_vram_mapping(s->lfb_addr ,s->lfb_end);
   6.210 -        if (!vram_pointer){
   6.211 -            fprintf(stderr, "cirrus_vga_load:NULL vram_pointer\n");
   6.212 -        } else {
   6.213 -            old_vram = vga_update_vram((VGAState *)s, vram_pointer,
   6.214 -                    VGA_RAM_SIZE);
   6.215 -            qemu_free(old_vram);
   6.216 -            s->map_addr = s->lfb_addr;
   6.217 -            s->map_end = s->lfb_end;
   6.218 -        }
   6.219 -    }
   6.220 -}
   6.221 -
   6.222  /* load/save state */
   6.223  
   6.224  static void cirrus_vga_save(QEMUFile *f, void *opaque)
   6.225 @@ -3118,7 +3046,10 @@ static void cirrus_vga_save(QEMUFile *f,
   6.226      qemu_put_8s(f, &vga_acc);
   6.227      qemu_put_be64s(f, (uint64_t*)&s->lfb_addr);
   6.228      qemu_put_be64s(f, (uint64_t*)&s->lfb_end);
   6.229 -    qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE); 
   6.230 +    qemu_put_be64s(f, &s->stolen_vram_addr);
   6.231 +    if (!s->stolen_vram_addr && !vga_acc)
   6.232 +        /* Old guest: VRAM is not mapped, we have to save it ourselves */
   6.233 +        qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
   6.234  }
   6.235  
   6.236  static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
   6.237 @@ -3127,7 +3058,7 @@ static int cirrus_vga_load(QEMUFile *f, 
   6.238      uint8_t vga_acc = 0;
   6.239      int ret;
   6.240  
   6.241 -    if (version_id > 2)
   6.242 +    if (version_id > 3)
   6.243          return -EINVAL;
   6.244  
   6.245      if (s->pci_dev && version_id >= 2) {
   6.246 @@ -3173,9 +3104,20 @@ static int cirrus_vga_load(QEMUFile *f, 
   6.247      qemu_get_8s(f, &vga_acc);
   6.248      qemu_get_be64s(f, (uint64_t*)&s->lfb_addr);
   6.249      qemu_get_be64s(f, (uint64_t*)&s->lfb_end);
   6.250 -    qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE); 
   6.251 -    if (vga_acc){
   6.252 -        cirrus_restart_acc(s);
   6.253 +    if (version_id >= 3) {
   6.254 +        qemu_get_be64s(f, &s->stolen_vram_addr);
   6.255 +        if (!s->stolen_vram_addr && !vga_acc) {
   6.256 +            /* Old guest, VRAM is not mapped, we have to restore it ourselves */
   6.257 +            qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
   6.258 +            xen_vga_populate_vram(s->lfb_addr);
   6.259 +        } else
   6.260 +            xen_vga_vram_map(vga_acc ? s->lfb_addr : s->stolen_vram_addr, 0);
   6.261 +    } else {
   6.262 +        /* Old image, we have to populate and restore VRAM ourselves */
   6.263 +        xen_vga_populate_vram(s->lfb_addr);
   6.264 +        qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE); 
   6.265 +        if (vga_acc)
   6.266 +            cirrus_restart_acc(s);
   6.267      }
   6.268  
   6.269      /* force refresh */
   6.270 @@ -3297,7 +3239,7 @@ static void cirrus_init_common(CirrusVGA
   6.271      s->cursor_invalidate = cirrus_cursor_invalidate;
   6.272      s->cursor_draw_line = cirrus_cursor_draw_line;
   6.273  
   6.274 -    register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);
   6.275 +    register_savevm("cirrus_vga", 0, 3, cirrus_vga_save, cirrus_vga_load, s);
   6.276  }
   6.277  
   6.278  /***************************************
     7.1 --- a/tools/ioemu/hw/vga.c	Wed Aug 27 13:31:01 2008 +0100
     7.2 +++ b/tools/ioemu/hw/vga.c	Wed Aug 27 14:53:39 2008 +0100
     7.3 @@ -23,6 +23,7 @@
     7.4   */
     7.5  #include "vl.h"
     7.6  #include "vga_int.h"
     7.7 +#include <sys/mman.h>
     7.8  
     7.9  //#define DEBUG_VGA
    7.10  //#define DEBUG_VGA_MEM
    7.11 @@ -1776,7 +1777,10 @@ static void vga_save(QEMUFile *f, void *
    7.12  #endif
    7.13      vram_size = s->vram_size;
    7.14      qemu_put_be32s(f, &vram_size); 
    7.15 -    qemu_put_buffer(f, s->vram_ptr, s->vram_size); 
    7.16 +    qemu_put_be64s(f, &s->stolen_vram_addr);
    7.17 +    if (!s->stolen_vram_addr)
    7.18 +        /* Old guest: VRAM is not mapped, we have to save it ourselves */
    7.19 +        qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
    7.20  }
    7.21  
    7.22  static int vga_load(QEMUFile *f, void *opaque, int version_id)
    7.23 @@ -1788,7 +1792,7 @@ static int vga_load(QEMUFile *f, void *o
    7.24      int i;
    7.25  #endif
    7.26  
    7.27 -    if (version_id > 3)
    7.28 +    if (version_id > 4)
    7.29          return -EINVAL;
    7.30  
    7.31      if (s->pci_dev && version_id >= 2) {
    7.32 @@ -1839,7 +1843,14 @@ static int vga_load(QEMUFile *f, void *o
    7.33  	qemu_get_be32s(f, &vram_size);
    7.34  	if (vram_size != s->vram_size)
    7.35  	    return -EINVAL;
    7.36 -	qemu_get_buffer(f, s->vram_ptr, s->vram_size); 
    7.37 +        if (version_id >= 4) {
    7.38 +            qemu_get_be64s(f, &s->stolen_vram_addr);
    7.39 +            if (s->stolen_vram_addr)
    7.40 +                xen_vga_vram_map(s->stolen_vram_addr, 0);
    7.41 +        }
    7.42 +        /* Old guest, VRAM is not mapped, we have to restore it ourselves */
    7.43 +        if (!s->stolen_vram_addr)
    7.44 +            qemu_get_buffer(f, s->vram_ptr, s->vram_size); 
    7.45      }
    7.46  
    7.47      /* force refresh */
    7.48 @@ -1994,6 +2005,100 @@ void vga_bios_init(VGAState *s)
    7.49      /* TODO: add vbe support if enabled */
    7.50  }
    7.51  
    7.52 +
    7.53 +static VGAState *xen_vga_state;
    7.54 +
    7.55 +/* When loading old images we have to populate the video ram ourselves */
    7.56 +void xen_vga_populate_vram(uint64_t vram_addr)
    7.57 +{
    7.58 +    unsigned long nr_pfn;
    7.59 +    struct xen_remove_from_physmap xrfp;
    7.60 +    xen_pfn_t *pfn_list;
    7.61 +    int i;
    7.62 +    int rc;
    7.63 +
    7.64 +    fprintf(logfile, "populating video RAM at %lx\n", vram_addr);
    7.65 +
    7.66 +    nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS;
    7.67 +
    7.68 +    pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
    7.69 +
    7.70 +    for (i = 0; i < nr_pfn; i++)
    7.71 +        pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
    7.72 +
    7.73 +    if (xc_domain_memory_populate_physmap(xc_handle, domid, nr_pfn, 0, 0, pfn_list)) {
    7.74 +        fprintf(stderr, "Failed to populate video ram\n");
    7.75 +        exit(1);
    7.76 +    }
    7.77 +    free(pfn_list);
    7.78 +
    7.79 +    xen_vga_vram_map(vram_addr, 0);
    7.80 +
    7.81 +    /* Unmap them from the guest for now. */
    7.82 +    xrfp.domid = domid;
    7.83 +    for (i = 0; i < nr_pfn; i++) {
    7.84 +        xrfp.gpfn = (vram_addr >> TARGET_PAGE_BITS) + i;
    7.85 +        rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp);
    7.86 +        if (rc) {
    7.87 +            fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc);
    7.88 +            break;
    7.89 +        }
    7.90 +    }
    7.91 +}
    7.92 +
    7.93 +/* Called once video memory has been allocated in the GPFN space */
    7.94 +void xen_vga_vram_map(uint64_t vram_addr, int copy)
    7.95 +{
    7.96 +    unsigned long nr_pfn;
    7.97 +    xen_pfn_t *pfn_list;
    7.98 +    int i;
    7.99 +    void *vram;
   7.100 +
   7.101 +    fprintf(logfile, "mapping video RAM from %lx\n", vram_addr);
   7.102 +
   7.103 +    nr_pfn = VGA_RAM_SIZE >> TARGET_PAGE_BITS;
   7.104 +
   7.105 +    pfn_list = malloc(sizeof(*pfn_list) * nr_pfn);
   7.106 +
   7.107 +    for (i = 0; i < nr_pfn; i++)
   7.108 +        pfn_list[i] = (vram_addr >> TARGET_PAGE_BITS) + i;
   7.109 +
   7.110 +    vram = xc_map_foreign_pages(xc_handle, domid,
   7.111 +                                        PROT_READ|PROT_WRITE,
   7.112 +                                        pfn_list, nr_pfn);
   7.113 +
   7.114 +    if (!vram) {
   7.115 +        fprintf(stderr, "Failed to map vram\n");
   7.116 +        exit(1);
   7.117 +    }
   7.118 +
   7.119 +    if (xc_domain_memory_translate_gpfn_list(xc_handle, domid, nr_pfn,
   7.120 +                pfn_list, pfn_list)) {
   7.121 +        fprintf(stderr, "Failed translation in xen_vga_vram_addr\n");
   7.122 +        exit(1);
   7.123 +    }
   7.124 +
   7.125 +    if (copy)
   7.126 +        memcpy(vram, xen_vga_state->vram_ptr, VGA_RAM_SIZE);
   7.127 +    qemu_free(xen_vga_state->vram_ptr);
   7.128 +    xen_vga_state->vram_ptr = vram;
   7.129 +    xen_vga_state->vram_mfns = pfn_list;
   7.130 +#ifdef CONFIG_STUBDOM
   7.131 +    xenfb_pv_display_start(vram);
   7.132 +#endif
   7.133 +}
   7.134 +
   7.135 +/* Called at boot time when the BIOS has allocated video RAM */
   7.136 +void xen_vga_stolen_vram_addr(uint64_t stolen_vram_addr)
   7.137 +{
   7.138 +    fprintf(logfile, "stolen video RAM at %lx\n", stolen_vram_addr);
   7.139 +
   7.140 +    xen_vga_state->stolen_vram_addr = stolen_vram_addr;
   7.141 +
   7.142 +    /* And copy from the initialization value */
   7.143 +    xen_vga_vram_map(stolen_vram_addr, 1);
   7.144 +}
   7.145 +
   7.146  /* when used on xen environment, the vga_ram_base is not used */
   7.147  void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
   7.148                       unsigned long vga_ram_offset, int vga_ram_size)
   7.149 @@ -2025,13 +2130,9 @@ void vga_common_init(VGAState *s, Displa
   7.150  
   7.151      vga_reset(s);
   7.152  
   7.153 -    /* Video RAM must be page-aligned for PVFB memory sharing */
   7.154 -    s->vram_ptr = s->vram_alloc = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size);
   7.155 -
   7.156 -#ifdef CONFIG_STUBDOM
   7.157 -    if (!cirrus_vga_enabled)
   7.158 -        xenfb_pv_display_start(s->vram_ptr);
   7.159 -#endif
   7.160 +    s->vram_ptr = qemu_malloc(vga_ram_size);
   7.161 +    s->vram_mfns = NULL;
   7.162 +    xen_vga_state = s;
   7.163  
   7.164      s->vram_offset = vga_ram_offset;
   7.165      s->vram_size = vga_ram_size;
   7.166 @@ -2051,7 +2152,7 @@ static void vga_init(VGAState *s)
   7.167  {
   7.168      int vga_io_memory;
   7.169  
   7.170 -    register_savevm("vga", 0, 3, vga_save, vga_load, s);
   7.171 +    register_savevm("vga", 0, 4, vga_save, vga_load, s);
   7.172  
   7.173      register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
   7.174  
   7.175 @@ -2163,33 +2264,6 @@ int pci_vga_init(PCIBus *bus, DisplaySta
   7.176      return 0;
   7.177  }
   7.178  
   7.179 -void *vga_update_vram(VGAState *s, void *vga_ram_base, int vga_ram_size)
   7.180 -{
   7.181 -    uint8_t *old_pointer;
   7.182 -
   7.183 -    if (s->vram_size != vga_ram_size) {
   7.184 -        fprintf(stderr, "No support to change vga_ram_size\n");
   7.185 -        return NULL;
   7.186 -    }
   7.187 -
   7.188 -    if (!vga_ram_base) {
   7.189 -        vga_ram_base = qemu_memalign(TARGET_PAGE_SIZE, vga_ram_size + TARGET_PAGE_SIZE + 1);
   7.190 -        if (!vga_ram_base) {
   7.191 -            fprintf(stderr, "reallocate error\n");
   7.192 -            return NULL;
   7.193 -        }
   7.194 -    }
   7.195 -
   7.196 -    /* XXX lock needed? */
   7.197 -    old_pointer = s->vram_alloc;
   7.198 -    s->vram_alloc = vga_ram_base;
   7.199 -    vga_ram_base = (uint8_t *)((long)(vga_ram_base + 15) & ~15L);
   7.200 -    memcpy(vga_ram_base, s->vram_ptr, vga_ram_size);
   7.201 -    s->vram_ptr = vga_ram_base;
   7.202 -
   7.203 -    return old_pointer;
   7.204 -}
   7.205 -
   7.206  /********************************************************/
   7.207  /* vga screen dump */
   7.208  
     8.1 --- a/tools/ioemu/hw/vga_int.h	Wed Aug 27 13:31:01 2008 +0100
     8.2 +++ b/tools/ioemu/hw/vga_int.h	Wed Aug 27 14:53:39 2008 +0100
     8.3 @@ -80,9 +80,9 @@
     8.4  #define VGA_MAX_HEIGHT 2048
     8.5  
     8.6  #define VGA_STATE_COMMON                                                \
     8.7 -    uint8_t *vram_alloc;                                                \
     8.8      uint8_t *vram_ptr;                                                  \
     8.9 -    uint8_t *vram_shadow;                                               \
    8.10 +    xen_pfn_t *vram_mfns;                                               \
    8.11 +    uint64_t stolen_vram_addr; /* Address of stolen RAM */              \
    8.12      unsigned long vram_offset;                                          \
    8.13      unsigned int vram_size;                                             \
    8.14      unsigned long bios_offset;                                          \
     9.1 --- a/tools/ioemu/hw/xen_platform.c	Wed Aug 27 13:31:01 2008 +0100
     9.2 +++ b/tools/ioemu/hw/xen_platform.c	Wed Aug 27 14:53:39 2008 +0100
     9.3 @@ -34,6 +34,7 @@ typedef struct PCIXenPlatformState
     9.4  {
     9.5    PCIDevice  pci_dev;
     9.6    uint8_t    platform_flags;
     9.7 +  uint64_t   vga_stolen_ram;
     9.8  } PCIXenPlatformState;
     9.9  
    9.10  static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
    9.11 @@ -69,11 +70,46 @@ static void xen_platform_ioport_writeb(v
    9.12  }
    9.13  
    9.14  
    9.15 +static uint32_t xen_platform_ioport_readl(void *opaque, uint32_t addr)
    9.16 +{
    9.17 +    PCIXenPlatformState *d = opaque;
    9.18 +
    9.19 +    addr  &= 0xff;
    9.20 +
    9.21 +    switch (addr) {
    9.22 +    case 4: /* VGA stolen memory address */
    9.23 +        return d->vga_stolen_ram;
    9.24 +    default:
    9.25 +        return ~0u;
    9.26 +    }
    9.27 +}
    9.28 +
    9.29 +static void xen_platform_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
    9.30 +{
    9.31 +    PCIXenPlatformState *d = opaque;
    9.32 +
    9.33 +    addr &= 0xff;
    9.34 +    val  &= 0xffffffff;
    9.35 +
    9.36 +    switch (addr) {
    9.37 +    case 4: /* VGA stolen memory address */
    9.38 +        d->vga_stolen_ram = val;
    9.39 +        xen_vga_stolen_vram_addr(val);
    9.40 +        break;
    9.41 +    default:
    9.42 +        break;
    9.43 +    }
    9.44 +}
    9.45 +
    9.46 +
    9.47 +
    9.48  static void platform_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type)
    9.49  {
    9.50      PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev;
    9.51      register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
    9.52 +    register_ioport_write(addr, size, 4, xen_platform_ioport_writel, d);
    9.53      register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
    9.54 +    register_ioport_read(addr, size, 4, xen_platform_ioport_readl, d);
    9.55  }
    9.56  
    9.57  static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr)
    9.58 @@ -155,6 +191,7 @@ void xen_pci_save(QEMUFile *f, void *opa
    9.59  
    9.60      pci_device_save(&d->pci_dev, f);
    9.61      qemu_put_8s(f, &d->platform_flags);
    9.62 +    qemu_put_be64s(f, &d->vga_stolen_ram);
    9.63  }
    9.64  
    9.65  int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
    9.66 @@ -173,6 +210,7 @@ int xen_pci_load(QEMUFile *f, void *opaq
    9.67          uint8_t flags;
    9.68          qemu_get_8s(f, &flags);
    9.69          xen_platform_ioport_writeb(d, 0, flags);
    9.70 +        qemu_get_be64s(f, &d->vga_stolen_ram);
    9.71      }
    9.72  
    9.73      return 0;
    10.1 --- a/tools/ioemu/vl.c	Wed Aug 27 13:31:01 2008 +0100
    10.2 +++ b/tools/ioemu/vl.c	Wed Aug 27 14:53:39 2008 +0100
    10.3 @@ -7023,38 +7023,6 @@ static BOOL WINAPI qemu_ctrl_handler(DWO
    10.4  
    10.5  #include <xg_private.h>
    10.6  
    10.7 -/* FIXME Flush the shadow page */
    10.8 -int unset_mm_mapping(int xc_handle, uint32_t domid,
    10.9 -                     unsigned long nr_pages, unsigned int address_bits,
   10.10 -                     xen_pfn_t *extent_start)
   10.11 -{
   10.12 -    int err = 0;
   10.13 -
   10.14 -    err = xc_domain_memory_decrease_reservation(xc_handle, domid,
   10.15 -                                                nr_pages, 0, extent_start);
   10.16 -    if (err)
   10.17 -        fprintf(stderr, "Failed to decrease physmap\n");
   10.18 -
   10.19 -    return err;
   10.20 -}
   10.21 -
   10.22 -int set_mm_mapping(int xc_handle, uint32_t domid,
   10.23 -                   unsigned long nr_pages, unsigned int address_bits,
   10.24 -                   xen_pfn_t *extent_start)
   10.25 -{
   10.26 -    int err = 0;
   10.27 -
   10.28 -    err = xc_domain_memory_populate_physmap(
   10.29 -        xc_handle, domid, nr_pages, 0,
   10.30 -        XENMEMF_address_bits(address_bits), extent_start);
   10.31 -    if (err) {
   10.32 -        fprintf(stderr, "Failed to populate physmap\n");
   10.33 -        return -1;
   10.34 -    }
   10.35 -
   10.36 -    return 0;
   10.37 -}
   10.38 -
   10.39  
   10.40  int main(int argc, char **argv)
   10.41  {
    11.1 --- a/tools/ioemu/vl.h	Wed Aug 27 13:31:01 2008 +0100
    11.2 +++ b/tools/ioemu/vl.h	Wed Aug 27 14:53:39 2008 +0100
    11.3 @@ -1560,6 +1560,9 @@ void timeoffset_get(void);
    11.4  /* xen_platform.c */
    11.5  #ifndef QEMU_TOOL
    11.6  void pci_xen_platform_init(PCIBus *bus);
    11.7 +void xen_vga_stolen_vram_addr(uint64_t vram_addr);
    11.8 +void xen_vga_populate_vram(uint64_t vram_addr);
    11.9 +void xen_vga_vram_map(uint64_t vram_addr, int copy);
   11.10  #endif
   11.11  
   11.12  /* pci_emulation.c */
    12.1 --- a/tools/libxc/xc_domain.c	Wed Aug 27 13:31:01 2008 +0100
    12.2 +++ b/tools/libxc/xc_domain.c	Wed Aug 27 14:53:39 2008 +0100
    12.3 @@ -537,6 +537,33 @@ int xc_domain_memory_populate_physmap(in
    12.4      return err;
    12.5  }
    12.6  
    12.7 +int xc_domain_memory_translate_gpfn_list(int xc_handle,
    12.8 +                                         uint32_t domid,
    12.9 +                                         unsigned long nr_gpfns,
   12.10 +                                         xen_pfn_t *gpfn_list,
   12.11 +                                         xen_pfn_t *mfn_list)
   12.12 +{
   12.13 +    int err;
   12.14 +    struct xen_translate_gpfn_list translate_gpfn_list = {
   12.15 +        .domid    = domid,
   12.16 +        .nr_gpfns = nr_gpfns,
   12.17 +    };
   12.18 +    set_xen_guest_handle(translate_gpfn_list.gpfn_list, gpfn_list);
   12.19 +    set_xen_guest_handle(translate_gpfn_list.mfn_list, mfn_list);
   12.20 +
   12.21 +    err = xc_memory_op(xc_handle, XENMEM_translate_gpfn_list, &translate_gpfn_list);
   12.22 +
   12.23 +    if ( err != 0 )
   12.24 +    {
   12.25 +        DPRINTF("Failed translation for dom %d (%ld PFNs)\n",
   12.26 +                domid, nr_gpfns);
   12.27 +        errno = -err;
   12.28 +        err = -1;
   12.29 +    }
   12.30 +
   12.31 +    return err;
   12.32 +}
   12.33 +
   12.34  int xc_domain_max_vcpus(int xc_handle, uint32_t domid, unsigned int max)
   12.35  {
   12.36      DECLARE_DOMCTL;
    13.1 --- a/tools/libxc/xc_domain_save.c	Wed Aug 27 13:31:01 2008 +0100
    13.2 +++ b/tools/libxc/xc_domain_save.c	Wed Aug 27 14:53:39 2008 +0100
    13.3 @@ -1111,12 +1111,6 @@ int xc_domain_save(int xc_handle, int io
    13.4                         (test_bit(n, to_fix)  && last_iter)) )
    13.5                      continue;
    13.6  
    13.7 -                /* Skip PFNs that aren't really there */
    13.8 -                if ( hvm && ((n >= 0xa0 && n < 0xc0) /* VGA hole */
    13.9 -                             || (n >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT) 
   13.10 -                                 && n < (1ULL<<32) >> PAGE_SHIFT)) /* MMIO */ )
   13.11 -                    continue;
   13.12 -
   13.13                  /*
   13.14                  ** we get here if:
   13.15                  **  1. page is marked to_send & hasn't already been re-dirtied
    14.1 --- a/tools/libxc/xenctrl.h	Wed Aug 27 13:31:01 2008 +0100
    14.2 +++ b/tools/libxc/xenctrl.h	Wed Aug 27 14:53:39 2008 +0100
    14.3 @@ -628,6 +628,12 @@ int xc_domain_memory_populate_physmap(in
    14.4                                        unsigned int mem_flags,
    14.5                                        xen_pfn_t *extent_start);
    14.6  
    14.7 +int xc_domain_memory_translate_gpfn_list(int xc_handle,
    14.8 +                                         uint32_t domid,
    14.9 +                                         unsigned long nr_gpfns,
   14.10 +                                         xen_pfn_t *gpfn_list,
   14.11 +                                         xen_pfn_t *mfn_list);
   14.12 +
   14.13  int xc_domain_ioport_permission(int xc_handle,
   14.14                                  uint32_t domid,
   14.15                                  uint32_t first_port,
    15.1 --- a/xen/arch/ia64/xen/mm.c	Wed Aug 27 13:31:01 2008 +0100
    15.2 +++ b/xen/arch/ia64/xen/mm.c	Wed Aug 27 14:53:39 2008 +0100
    15.3 @@ -2698,6 +2698,20 @@ void put_page_type(struct page_info *pag
    15.4  }
    15.5  
    15.6  
    15.7 +static int get_page_from_pagenr(unsigned long page_nr, struct domain *d)
    15.8 +{
    15.9 +    struct page_info *page = mfn_to_page(page_nr);
   15.10 +
   15.11 +    if ( unlikely(!mfn_valid(page_nr)) || unlikely(!get_page(page, d)) )
   15.12 +    {
   15.13 +        MEM_LOG("Could not get page ref for pfn %lx", page_nr);
   15.14 +        return 0;
   15.15 +    }
   15.16 +
   15.17 +    return 1;
   15.18 +}
   15.19 +
   15.20 +
   15.21  int get_page_type(struct page_info *page, u32 type)
   15.22  {
   15.23      u64 nx, x, y = page->u.inuse.type_info;
   15.24 @@ -2792,6 +2806,8 @@ int memory_is_conventional_ram(paddr_t p
   15.25  long
   15.26  arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
   15.27  {
   15.28 +    struct page_info *page = NULL;
   15.29 +
   15.30      switch (op) {
   15.31      case XENMEM_add_to_physmap:
   15.32      {
   15.33 @@ -2836,11 +2852,21 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(
   15.34  
   15.35              spin_unlock(&d->grant_table->lock);
   15.36              break;
   15.37 +        case XENMAPSPACE_mfn:
   15.38 +        {
   15.39 +            if ( get_page_from_pagenr(xatp.idx, d) ) {
   15.40 +                mfn = xatp.idx;
   15.41 +                page = mfn_to_page(mfn);
   15.42 +            }
   15.43 +            break;
   15.44 +        }
   15.45          default:
   15.46              break;
   15.47          }
   15.48  
   15.49          if (mfn == 0) {
   15.50 +            if ( page )
   15.51 +                put_page(page);
   15.52              rcu_unlock_domain(d);
   15.53              return -EINVAL;
   15.54          }
   15.55 @@ -2872,12 +2898,54 @@ arch_memory_op(int op, XEN_GUEST_HANDLE(
   15.56  
   15.57      out:
   15.58          domain_unlock(d);
   15.59 -        
   15.60 +
   15.61 +        if ( page )
   15.62 +            put_page(page);
   15.63 +
   15.64          rcu_unlock_domain(d);
   15.65  
   15.66          break;
   15.67      }
   15.68  
   15.69 +    case XENMEM_remove_from_physmap:
   15.70 +    {
   15.71 +        struct xen_remove_from_physmap xrfp;
   15.72 +        unsigned long mfn;
   15.73 +        struct domain *d;
   15.74 +
   15.75 +        if ( copy_from_guest(&xrfp, arg, 1) )
   15.76 +            return -EFAULT;
   15.77 +
   15.78 +        if ( xrfp.domid == DOMID_SELF )
   15.79 +        {
   15.80 +            d = rcu_lock_current_domain();
   15.81 +        }
   15.82 +        else
   15.83 +        {
   15.84 +            if ( (d = rcu_lock_domain_by_id(xrfp.domid)) == NULL )
   15.85 +                return -ESRCH;
   15.86 +            if ( !IS_PRIV_FOR(current->domain, d) )
   15.87 +            {
   15.88 +                rcu_unlock_domain(d);
   15.89 +                return -EPERM;
   15.90 +            }
   15.91 +        }
   15.92 +
   15.93 +        domain_lock(d);
   15.94 +
   15.95 +        mfn = gmfn_to_mfn(d, xrfp.gpfn);
   15.96 +
   15.97 +        if ( mfn_valid(mfn) )
   15.98 +            guest_physmap_remove_page(d, xrfp.gpfn, mfn, 0);
   15.99 +
  15.100 +        domain_unlock(d);
  15.101 +
  15.102 +        rcu_unlock_domain(d);
  15.103 +
  15.104 +        break;
  15.105 +    }
  15.106 +
  15.107 +
  15.108      case XENMEM_machine_memory_map:
  15.109      {
  15.110          struct xen_memory_map memmap;
    16.1 --- a/xen/arch/x86/mm.c	Wed Aug 27 13:31:01 2008 +0100
    16.2 +++ b/xen/arch/x86/mm.c	Wed Aug 27 14:53:39 2008 +0100
    16.3 @@ -3339,6 +3339,7 @@ DEFINE_XEN_GUEST_HANDLE(e820entry_t);
    16.4  
    16.5  long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
    16.6  {
    16.7 +    struct page_info *page = NULL;
    16.8      switch ( op )
    16.9      {
   16.10      case XENMEM_add_to_physmap:
   16.11 @@ -3389,12 +3390,22 @@ long arch_memory_op(int op, XEN_GUEST_HA
   16.12  
   16.13              spin_unlock(&d->grant_table->lock);
   16.14              break;
   16.15 +        case XENMAPSPACE_mfn:
   16.16 +        {
   16.17 +            if ( get_page_from_pagenr(xatp.idx, d) ) {
   16.18 +                mfn = xatp.idx;
   16.19 +                page = mfn_to_page(mfn);
   16.20 +            }
   16.21 +            break;
   16.22 +        }
   16.23          default:
   16.24              break;
   16.25          }
   16.26  
   16.27          if ( !paging_mode_translate(d) || (mfn == 0) )
   16.28          {
   16.29 +            if ( page )
   16.30 +                put_page(page);
   16.31              rcu_unlock_domain(d);
   16.32              return -EINVAL;
   16.33          }
   16.34 @@ -3423,6 +3434,53 @@ long arch_memory_op(int op, XEN_GUEST_HA
   16.35  
   16.36          domain_unlock(d);
   16.37  
   16.38 +        if ( page )
   16.39 +            put_page(page);
   16.40 +
   16.41 +        rcu_unlock_domain(d);
   16.42 +
   16.43 +        break;
   16.44 +    }
   16.45 +
   16.46 +    case XENMEM_remove_from_physmap:
   16.47 +    {
   16.48 +        struct xen_remove_from_physmap xrfp;
   16.49 +        unsigned long mfn;
   16.50 +        struct domain *d;
   16.51 +
   16.52 +        if ( copy_from_guest(&xrfp, arg, 1) )
   16.53 +            return -EFAULT;
   16.54 +
   16.55 +        if ( xrfp.domid == DOMID_SELF )
   16.56 +        {
   16.57 +            d = rcu_lock_current_domain();
   16.58 +        }
   16.59 +        else
   16.60 +        {
   16.61 +            if ( (d = rcu_lock_domain_by_id(xrfp.domid)) == NULL )
   16.62 +                return -ESRCH;
   16.63 +            if ( !IS_PRIV_FOR(current->domain, d) )
   16.64 +            {
   16.65 +                rcu_unlock_domain(d);
   16.66 +                return -EPERM;
   16.67 +            }
   16.68 +        }
   16.69 +
   16.70 +        if ( xsm_remove_from_physmap(current->domain, d) )
   16.71 +        {
   16.72 +            rcu_unlock_domain(d);
   16.73 +            return -EPERM;
   16.74 +        }
   16.75 +
   16.76 +        domain_lock(d);
   16.77 +
   16.78 +        mfn = gmfn_to_mfn(d, xrfp.gpfn);
   16.79 +
   16.80 +        if ( mfn_valid(mfn) )
   16.81 +            guest_physmap_remove_page(d, xrfp.gpfn, mfn, 0);
   16.82 +
   16.83 +        domain_unlock(d);
   16.84 +
   16.85          rcu_unlock_domain(d);
   16.86  
   16.87          break;
    17.1 --- a/xen/arch/x86/x86_64/compat/mm.c	Wed Aug 27 13:31:01 2008 +0100
    17.2 +++ b/xen/arch/x86/x86_64/compat/mm.c	Wed Aug 27 14:53:39 2008 +0100
    17.3 @@ -69,6 +69,20 @@ int compat_arch_memory_op(int op, XEN_GU
    17.4          break;
    17.5      }
    17.6  
    17.7 +    case XENMEM_remove_from_physmap:
    17.8 +    {
    17.9 +        struct compat_remove_from_physmap cmp;
   17.10 +        struct xen_remove_from_physmap *nat = (void *)COMPAT_ARG_XLAT_VIRT_BASE;
   17.11 +
   17.12 +        if ( copy_from_guest(&cmp, arg, 1) )
   17.13 +            return -EFAULT;
   17.14 +
   17.15 +        XLAT_remove_from_physmap(nat, &cmp);
   17.16 +        rc = arch_memory_op(op, guest_handle_from_ptr(nat, void));
   17.17 +
   17.18 +        break;
   17.19 +    }
   17.20 +
   17.21      case XENMEM_set_memory_map:
   17.22      {
   17.23          struct compat_foreign_memory_map cmp;
    18.1 --- a/xen/include/public/memory.h	Wed Aug 27 13:31:01 2008 +0100
    18.2 +++ b/xen/include/public/memory.h	Wed Aug 27 14:53:39 2008 +0100
    18.3 @@ -204,6 +204,7 @@ struct xen_add_to_physmap {
    18.4      /* Source mapping space. */
    18.5  #define XENMAPSPACE_shared_info 0 /* shared info page */
    18.6  #define XENMAPSPACE_grant_table 1 /* grant table page */
    18.7 +#define XENMAPSPACE_mfn         2 /* usual MFN */
    18.8      unsigned int space;
    18.9  
   18.10      /* Index into source mapping space. */
   18.11 @@ -216,6 +217,22 @@ typedef struct xen_add_to_physmap xen_ad
   18.12  DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t);
   18.13  
   18.14  /*
   18.15 + * Unmaps the page appearing at a particular GPFN from the specified guest's
   18.16 + * pseudophysical address space.
   18.17 + * arg == addr of xen_remove_from_physmap_t.
   18.18 + */
   18.19 +#define XENMEM_remove_from_physmap      15
   18.20 +struct xen_remove_from_physmap {
   18.21 +    /* Which domain to change the mapping for. */
   18.22 +    domid_t domid;
   18.23 +
   18.24 +    /* GPFN of the current mapping of the page. */
   18.25 +    xen_pfn_t     gpfn;
   18.26 +};
   18.27 +typedef struct xen_remove_from_physmap xen_remove_from_physmap_t;
   18.28 +DEFINE_XEN_GUEST_HANDLE(xen_remove_from_physmap_t);
   18.29 +
   18.30 +/*
   18.31   * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
   18.32   * code on failure. This call only works for auto-translated guests.
   18.33   */
    19.1 --- a/xen/include/xlat.lst	Wed Aug 27 13:31:01 2008 +0100
    19.2 +++ b/xen/include/xlat.lst	Wed Aug 27 14:53:39 2008 +0100
    19.3 @@ -33,6 +33,7 @@
    19.4  !	kexec_image			kexec.h
    19.5  !	kexec_range			kexec.h
    19.6  !	add_to_physmap			memory.h
    19.7 +!	remove_from_physmap		memory.h
    19.8  !	foreign_memory_map		memory.h
    19.9  !	memory_exchange			memory.h
   19.10  !	memory_map			memory.h
    20.1 --- a/xen/include/xsm/xsm.h	Wed Aug 27 13:31:01 2008 +0100
    20.2 +++ b/xen/include/xsm/xsm.h	Wed Aug 27 14:53:39 2008 +0100
    20.3 @@ -136,6 +136,7 @@ struct xsm_operations {
    20.4      int (*mmu_machphys_update) (struct domain *d, unsigned long mfn);
    20.5      int (*update_va_mapping) (struct domain *d, l1_pgentry_t pte);
    20.6      int (*add_to_physmap) (struct domain *d1, struct domain *d2);
    20.7 +    int (*remove_from_physmap) (struct domain *d1, struct domain *d2);
    20.8  #endif
    20.9  };
   20.10  
   20.11 @@ -532,6 +533,11 @@ static inline int xsm_add_to_physmap(str
   20.12  {
   20.13      return xsm_call(add_to_physmap(d1, d2));
   20.14  }
   20.15 +
   20.16 +static inline int xsm_remove_from_physmap(struct domain *d1, struct domain *d2)
   20.17 +{
   20.18 +    return xsm_call(remove_from_physmap(d1, d2));
   20.19 +}
   20.20  #endif /* CONFIG_X86 */
   20.21  
   20.22  #endif /* __XSM_H */
    21.1 --- a/xen/xsm/dummy.c	Wed Aug 27 13:31:01 2008 +0100
    21.2 +++ b/xen/xsm/dummy.c	Wed Aug 27 14:53:39 2008 +0100
    21.3 @@ -385,6 +385,11 @@ static int dummy_add_to_physmap (struct 
    21.4  {
    21.5      return 0;
    21.6  }
    21.7 +
    21.8 +static int dummy_remove_from_physmap (struct domain *d1, struct domain *d2)
    21.9 +{
   21.10 +    return 0;
   21.11 +}
   21.12  #endif
   21.13  
   21.14  struct xsm_operations dummy_xsm_ops;
   21.15 @@ -484,5 +489,6 @@ void xsm_fixup_ops (struct xsm_operation
   21.16      set_to_dummy_if_null(ops, mmu_machphys_update);
   21.17      set_to_dummy_if_null(ops, update_va_mapping);
   21.18      set_to_dummy_if_null(ops, add_to_physmap);
   21.19 +    set_to_dummy_if_null(ops, remove_from_physmap);
   21.20  #endif
   21.21  }
    22.1 --- a/xen/xsm/flask/hooks.c	Wed Aug 27 13:31:01 2008 +0100
    22.2 +++ b/xen/xsm/flask/hooks.c	Wed Aug 27 14:53:39 2008 +0100
    22.3 @@ -1028,6 +1028,11 @@ static int flask_add_to_physmap(struct d
    22.4  {
    22.5      return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP);
    22.6  }
    22.7 +
    22.8 +static int flask_remove_from_physmap(struct domain *d1, struct domain *d2)
    22.9 +{
   22.10 +    return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP);
   22.11 +}
   22.12  #endif
   22.13  
   22.14  long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op);
   22.15 @@ -1115,6 +1120,7 @@ static struct xsm_operations flask_ops =
   22.16      .mmu_machphys_update = flask_mmu_machphys_update,
   22.17      .update_va_mapping = flask_update_va_mapping,
   22.18      .add_to_physmap = flask_add_to_physmap,
   22.19 +    .remove_from_physmap = flask_remove_from_physmap,
   22.20  #endif
   22.21  };
   22.22