xen: Use host-provided E820 map
authorIan Campbell <ian.campbell@citrix.com>
Sat, 7 Feb 2009 03:09:48 +0000 (19:09 -0800)
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Fri, 22 Oct 2010 19:57:27 +0000 (12:57 -0700)
Rather than simply using a flat memory map from Xen, use its provided
E820 map.  This allows the domain builder to tell the domain to reserve
space for more pages than those initially provided at domain-build time.

It also allows the host to specify holes in the address space (for
PCI-passthrough, for example).

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
arch/x86/xen/setup.c
include/xen/interface/memory.h

index 328b003054267d074610fdce51c39b063fae48e6..dd2eb2a9303f668f5e21b71644685b9f66f96ec8 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <xen/page.h>
 #include <xen/interface/callback.h>
+#include <xen/interface/memory.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/memory.h>
 #include <xen/features.h>
@@ -107,13 +108,46 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
 
 char * __init xen_memory_setup(void)
 {
+       static struct e820entry map[E820MAX] __initdata;
+
        unsigned long max_pfn = xen_start_info->nr_pages;
+       unsigned long long mem_end;
+       int rc;
+       struct xen_memory_map memmap;
+       int i;
 
        max_pfn = min(MAX_DOMAIN_PAGES, max_pfn);
+       mem_end = PFN_PHYS(max_pfn);
+
+       memmap.nr_entries = E820MAX;
+       set_xen_guest_handle(memmap.buffer, map);
+
+       rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
+       if (rc == -ENOSYS) {
+               memmap.nr_entries = 1;
+               map[0].addr = 0ULL;
+               map[0].size = mem_end;
+               /* 8MB slack (to balance backend allocations). */
+               map[0].size += 8ULL << 20;
+               map[0].type = E820_RAM;
+               rc = 0;
+       }
+       BUG_ON(rc);
 
        e820.nr_map = 0;
-
-       e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM);
+       for (i = 0; i < memmap.nr_entries; i++) {
+               unsigned long long end = map[i].addr + map[i].size;
+               if (map[i].type == E820_RAM) {
+                       if (map[i].addr > mem_end)
+                               continue;
+                       if (end > mem_end) {
+                               /* Truncate region to max_mem. */
+                               map[i].size -= end - mem_end;
+                       }
+               }
+               if (map[i].size > 0)
+                       e820_add_region(map[i].addr, map[i].size, map[i].type);
+       }
 
        /*
         * Even though this is normal, usable memory under Xen, reserve
index d3938d3e71f822c01956cdb6fbe93bc90cfb1363..d7a6c13bde69cf505bef40027bcd555a4463d57f 100644 (file)
@@ -186,6 +186,35 @@ struct xen_translate_gpfn_list {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
 
+/*
+ * Returns the pseudo-physical memory map as it was when the domain
+ * was started (specified by XENMEM_set_memory_map).
+ * arg == addr of struct xen_memory_map.
+ */
+#define XENMEM_memory_map           9
+struct xen_memory_map {
+    /*
+     * On call the number of entries which can be stored in buffer. On
+     * return the number of entries which have been stored in
+     * buffer.
+     */
+    unsigned int nr_entries;
+
+    /*
+     * Entries in the buffer are in the same format as returned by the
+     * BIOS INT 0x15 EAX=0xE820 call.
+     */
+    GUEST_HANDLE(void) buffer;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map);
+
+/*
+ * Returns the real physical memory map. Passes the same structure as
+ * XENMEM_memory_map.
+ * arg == addr of struct xen_memory_map.
+ */
+#define XENMEM_machine_memory_map   10
+
 
 /*
  * Prevent the balloon driver from changing the memory reservation