hvmloader: Change memory relocation loop when overlap with PCI hole
authorJean Guyader <jean.guyader@eu.citrix.com>
Fri, 18 Nov 2011 13:42:46 +0000 (13:42 +0000)
committerJean Guyader <jean.guyader@eu.citrix.com>
Fri, 18 Nov 2011 13:42:46 +0000 (13:42 +0000)
Change the way we relocate the memory page if they overlap with pci
hole.  Use new map space (XENMAPSPACE_gmfn_range) to move the loop
into xen.

This code usually get triggered when a device is pass through to a
guest and the PCI hole has to be extended to have enough room to map
the device BARs.  The PCI hole will starts lower and it might overlap
with some RAM that has been alocated for the guest. That usually
happen if the guest has more than 4G of RAM.  We have to relocate
those pages in high mem otherwise they won't be accessible.

Signed-off-by: Jean Guyader <jean.guyader@eu.citrix.com>
Committed-by: Keir Fraser <keir@xen.org>
tools/firmware/hvmloader/pci.c

index 29ec01160bceb3cba34942a399d6dc126c783a01..62aeff2fac93ab49ed17a7308fa696d530953b53 100644 (file)
@@ -50,6 +50,7 @@ void pci_setup(void)
         uint32_t devfn, bar_reg, bar_sz;
     } *bars = (struct bars *)scratch_start;
     unsigned int i, nr_bars = 0;
+    unsigned long pci_mem_reloc_pg;
 
     /* Program PCI-ISA bridge with appropriate link routes. */
     isa_irq = 0;
@@ -185,18 +186,25 @@ void pci_setup(void)
             ((pci_mem_start << 1) != 0) )
         pci_mem_start <<= 1;
 
-    while ( (pci_mem_start >> PAGE_SHIFT) < hvm_info->low_mem_pgend )
+    /* Relocate RAM that overlaps (in 64K chunks) */
+    pci_mem_reloc_pg = (pci_mem_start >> PAGE_SHIFT);
+    while (pci_mem_reloc_pg < hvm_info->low_mem_pgend)
     {
         struct xen_add_to_physmap xatp;
-        if ( hvm_info->high_mem_pgend == 0 )
-            hvm_info->high_mem_pgend = 1ull << (32 - PAGE_SHIFT);
+        unsigned int size = hvm_info->low_mem_pgend - pci_mem_reloc_pg;
         xatp.domid = DOMID_SELF;
-        xatp.space = XENMAPSPACE_gmfn;
-        xatp.idx   = --hvm_info->low_mem_pgend;
-        xatp.gpfn  = hvm_info->high_mem_pgend++;
+        xatp.space = XENMAPSPACE_gmfn_range;
+        xatp.idx = pci_mem_reloc_pg;
+        xatp.gpfn = hvm_info->high_mem_pgend;
+        size = size > ((1 << 16) - 1) ? ((1 << 16) - 1) : size;
+        xatp.size = size;
+
         if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
             BUG();
+        pci_mem_reloc_pg += size;
+        hvm_info->high_mem_pgend += size;
     }
+    hvm_info->low_mem_pgend = pci_mem_start >> PAGE_SHIFT;
 
     mem_resource.base = pci_mem_start;
     mem_resource.max = pci_mem_end;