x86: replace hard coded reservations in 64-bit early boot code with dynamic table
[pandora-kernel.git] / arch / x86 / kernel / e820_64.c
index 1512368..f8b7beb 100644 (file)
@@ -47,56 +47,65 @@ unsigned long end_pfn_map;
  */
 static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
 
-/* Check for some hardcoded bad areas that early boot is not allowed to touch */
-static inline int bad_addr(unsigned long *addrp, unsigned long size)
-{
-       unsigned long addr = *addrp, last = addr + size;
+/*
+ * Early reserved memory areas.
+ */
+#define MAX_EARLY_RES 20
+
+struct early_res {
+       unsigned long start, end;
+};
+static struct early_res early_res[MAX_EARLY_RES] __initdata = {
+       { 0, PAGE_SIZE },                       /* BIOS data page */
+#ifdef CONFIG_SMP
+       { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE },
+#endif
+       {}
+};
 
-       /* various gunk below that needed for SMP startup */
-       if (addr < 0x8000) {
-               *addrp = PAGE_ALIGN(0x8000);
-               return 1;
+void __init reserve_early(unsigned long start, unsigned long end)
+{
+       int i;
+       struct early_res *r;
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+               r = &early_res[i];
+               if (end > r->start && start < r->end)
+                       panic("Duplicated early reservation %lx-%lx\n",
+                             start, end);
        }
+       if (i >= MAX_EARLY_RES)
+               panic("Too many early reservations");
+       r = &early_res[i];
+       r->start = start;
+       r->end = end;
+}
 
-       /* direct mapping tables of the kernel */
-       if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) {
-               *addrp = PAGE_ALIGN(table_end << PAGE_SHIFT);
-               return 1;
+void __init early_res_to_bootmem(void)
+{
+       int i;
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+               struct early_res *r = &early_res[i];
+               reserve_bootmem_generic(r->start, r->end - r->start);
        }
+}
 
-       /* initrd */
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
-               unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
-               unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
-               unsigned long ramdisk_end   = ramdisk_image+ramdisk_size;
-
-               if (last >= ramdisk_image && addr < ramdisk_end) {
-                       *addrp = PAGE_ALIGN(ramdisk_end);
-                       return 1;
+/* Check for already reserved areas */
+static inline int bad_addr(unsigned long *addrp, unsigned long size)
+{
+       int i;
+       unsigned long addr = *addrp, last;
+       int changed = 0;
+again:
+       last = addr + size;
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+               struct early_res *r = &early_res[i];
+               if (last >= r->start && addr < r->end) {
+                       *addrp = addr = r->end;
+                       changed = 1;
+                       goto again;
                }
        }
-#endif
-       /* kernel code */
-       if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) {
-               *addrp = PAGE_ALIGN(__pa_symbol(&_end));
-               return 1;
-       }
-
-       if (last >= ebda_addr && addr < ebda_addr + ebda_size) {
-               *addrp = PAGE_ALIGN(ebda_addr + ebda_size);
-               return 1;
-       }
-
-#ifdef CONFIG_NUMA
-       /* NUMA memory to node map */
-       if (last >= nodemap_addr && addr < nodemap_addr + nodemap_size) {
-               *addrp = nodemap_addr + nodemap_size;
-               return 1;
-       }
-#endif
-       /* XXX ramdisk image here? */
-       return 0;
+       return changed;
 }
 
 /*
@@ -638,8 +647,10 @@ static void early_panic(char *msg)
        panic(msg);
 }
 
-void __init setup_memory_region(void)
+/* We're not void only for x86 32-bit compat */
+char * __init machine_specific_memory_setup(void)
 {
+       char *who = "BIOS-e820";
        /*
         * Try to copy the BIOS-supplied E820-map.
         *
@@ -650,7 +661,10 @@ void __init setup_memory_region(void)
        if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0)
                early_panic("Cannot find a valid memory map");
        printk(KERN_INFO "BIOS-provided physical RAM map:\n");
-       e820_print_map("BIOS-e820");
+       e820_print_map(who);
+
+       /* In case someone cares... */
+       return who;
 }
 
 static int __init parse_memopt(char *p)
@@ -691,6 +705,8 @@ static int __init parse_memmap_opt(char *p)
        mem_size = memparse(p, &p);
        if (p == oldp)
                return -EINVAL;
+
+       userdef = 1;
        if (*p == '@') {
                start_at = memparse(p+1, &p);
                add_memory_region(start_at, mem_size, E820_RAM);
@@ -710,11 +726,29 @@ early_param("memmap", parse_memmap_opt);
 void __init finish_e820_parsing(void)
 {
        if (userdef) {
+               char nr = e820.nr_map;
+
+               if (sanitize_e820_map(e820.map, &nr) < 0)
+                       early_panic("Invalid user supplied memory map");
+               e820.nr_map = nr;
+
                printk(KERN_INFO "user-defined physical RAM map:\n");
                e820_print_map("user");
        }
 }
 
+void __init update_e820(void)
+{
+       u8 nr_map;
+
+       nr_map = e820.nr_map;
+       if (sanitize_e820_map(e820.map, &nr_map))
+               return;
+       e820.nr_map = nr_map;
+       printk(KERN_INFO "modified physical RAM map:\n");
+       e820_print_map("modified");
+}
+
 unsigned long pci_mem_start = 0xaeedbabe;
 EXPORT_SYMBOL(pci_mem_start);