]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
x86: make 'mem=' option to work for efi platform
authorWen Congyang <wency@cn.fujitsu.com>
Thu, 23 May 2013 00:36:55 +0000 (10:36 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Mon, 27 May 2013 06:08:04 +0000 (16:08 +1000)
Current mem boot option only can work for non efi environment.  If the
user specifies add_efi_memmap, it cannot work for efi environment.  In the
efi environment, we call e820_add_region() to add the memory map.  So we
can modify __e820_add_region() and the mem boot option can work for efi
environment.

Note: Only E820_RAM is limited, and BOOT_SERVICES_{CODE,DATA} are always
mapped(If its address >= mem_limit, the memory won't be freed in
efi_free_boot_services()).

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Matt Fleming <matt.fleming@intel.com>
Cc: Rob Landley <rob@landley.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Yasuaki ISIMATU <isimatu.yasuaki@jp.fujitsu.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
arch/x86/include/asm/e820.h
arch/x86/kernel/e820.c
arch/x86/platform/efi/efi.c

index cccd07fa5e3a83ce79cd183b3ed94821429e40c0..b8e9224f0b4557ac995610f56616e41f19d079cd 100644 (file)
@@ -17,6 +17,8 @@ extern unsigned long pci_mem_start;
 extern int e820_any_mapped(u64 start, u64 end, unsigned type);
 extern int e820_all_mapped(u64 start, u64 end, unsigned type);
 extern void e820_add_region(u64 start, u64 size, int type);
+extern void e820_add_limit_region(u64 start, u64 size, int type);
+extern void e820_adjust_region(u64 *start, u64 *size);
 extern void e820_print_map(char *who);
 extern int
 sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, u32 *pnr_map);
index d32abeabbda556ea0c9387a331f15a129bf4a0de..0d5bb689649a86a69b4cdd2808868600de659b9f 100644 (file)
@@ -47,6 +47,7 @@ unsigned long pci_mem_start = 0xaeedbabe;
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(pci_mem_start);
 #endif
+static u64 mem_limit = ~0ULL;
 
 /*
  * This function checks if any part of the range <start,end> is mapped
@@ -108,7 +109,7 @@ int __init e820_all_mapped(u64 start, u64 end, unsigned type)
  * Add a memory region to the kernel e820 map.
  */
 static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size,
-                                        int type)
+                                        int type, bool limited)
 {
        int x = e820x->nr_map;
 
@@ -119,6 +120,22 @@ static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size,
                return;
        }
 
+       if (limited) {
+               if (start >= mem_limit) {
+                       printk(KERN_ERR "e820: ignoring [mem %#010llx-%#010llx]\n",
+                              (unsigned long long)start,
+                              (unsigned long long)(start + size - 1));
+                       return;
+               }
+
+               if (mem_limit - start < size) {
+                       printk(KERN_ERR "e820: ignoring [mem %#010llx-%#010llx]\n",
+                              (unsigned long long)mem_limit,
+                              (unsigned long long)(start + size - 1));
+                       size = mem_limit - start;
+               }
+       }
+
        e820x->map[x].addr = start;
        e820x->map[x].size = size;
        e820x->map[x].type = type;
@@ -127,7 +144,37 @@ static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size,
 
 void __init e820_add_region(u64 start, u64 size, int type)
 {
-       __e820_add_region(&e820, start, size, type);
+       __e820_add_region(&e820, start, size, type, false);
+}
+
+/*
+ * do_add_efi_memmap() calls this function().
+ *
+ * Note: BOOT_SERVICES_{CODE,DATA} regions on some efi machines are marked
+ * as E820_RAM, and they are needed to be mapped. Please use e820_add_region()
+ * to add BOOT_SERVICES_{CODE,DATA} regions.
+ */
+void __init e820_add_limit_region(u64 start, u64 size, int type)
+{
+       /*
+        * efi_init() is called after finish_e820_parsing(), so we should
+        * check whether [start, start + size) contains address above
+        * mem_limit if the type is E820_RAM.
+        */
+       __e820_add_region(&e820, start, size, type, type == E820_RAM);
+}
+
+void __init e820_adjust_region(u64 *start, u64 *size)
+{
+       if (*start >= mem_limit) {
+               *size = 0;
+               return;
+       }
+
+       if (mem_limit - *start < *size)
+               *size = mem_limit - *start;
+
+       return;
 }
 
 static void __init e820_print_type(u32 type)
@@ -455,8 +502,9 @@ static u64 __init __e820_update_range(struct e820map *e820x, u64 start,
 
                /* new range is totally covered? */
                if (ei->addr < start && ei_end > end) {
-                       __e820_add_region(e820x, start, size, new_type);
-                       __e820_add_region(e820x, end, ei_end - end, ei->type);
+                       __e820_add_region(e820x, start, size, new_type, false);
+                       __e820_add_region(e820x, end, ei_end - end, ei->type,
+                                         false);
                        ei->size = start - ei->addr;
                        real_updated_size += size;
                        continue;
@@ -469,7 +517,7 @@ static u64 __init __e820_update_range(struct e820map *e820x, u64 start,
                        continue;
 
                __e820_add_region(e820x, final_start, final_end - final_start,
-                                 new_type);
+                                 new_type, false);
 
                real_updated_size += final_end - final_start;
 
@@ -809,7 +857,7 @@ static int userdef __initdata;
 /* "mem=nopentium" disables the 4MB page tables. */
 static int __init parse_memopt(char *p)
 {
-       u64 mem_size;
+       char *oldp;
 
        if (!p)
                return -EINVAL;
@@ -825,11 +873,11 @@ static int __init parse_memopt(char *p)
        }
 
        userdef = 1;
-       mem_size = memparse(p, &p);
+       oldp = p;
+       mem_limit = memparse(p, &p);
        /* don't remove all of memory when handling "mem={invalid}" param */
-       if (mem_size == 0)
+       if (mem_limit == 0 || p == oldp)
                return -EINVAL;
-       e820_remove_range(mem_size, ULLONG_MAX - mem_size, E820_RAM, 1);
 
        return 0;
 }
@@ -895,6 +943,12 @@ early_param("memmap", parse_memmap_opt);
 
 void __init finish_e820_parsing(void)
 {
+       if (mem_limit != ~0ULL) {
+               userdef = 1;
+               e820_remove_range(mem_limit, ULLONG_MAX - mem_limit,
+                                 E820_RAM, 1);
+       }
+
        if (userdef) {
                u32 nr = e820.nr_map;
 
index 55856b2310d37d76240a2af47140f2deb97e8482..83e5cc4727520ef1ccc6e655ba9fe76f9aa35b0d 100644 (file)
@@ -419,10 +419,17 @@ static void __init do_add_efi_memmap(void)
                int e820_type;
 
                switch (md->type) {
-               case EFI_LOADER_CODE:
-               case EFI_LOADER_DATA:
                case EFI_BOOT_SERVICES_CODE:
                case EFI_BOOT_SERVICES_DATA:
+                       /* EFI_BOOT_SERVICES_{CODE,DATA} needs to be mapped */
+                       if (md->attribute & EFI_MEMORY_WB)
+                               e820_type = E820_RAM;
+                       else
+                               e820_type = E820_RESERVED;
+                       e820_add_region(start, size, e820_type);
+                       continue;
+               case EFI_LOADER_CODE:
+               case EFI_LOADER_DATA:
                case EFI_CONVENTIONAL_MEMORY:
                        if (md->attribute & EFI_MEMORY_WB)
                                e820_type = E820_RAM;
@@ -447,7 +454,7 @@ static void __init do_add_efi_memmap(void)
                        e820_type = E820_RESERVED;
                        break;
                }
-               e820_add_region(start, size, e820_type);
+               e820_add_limit_region(start, size, e820_type);
        }
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }
@@ -555,6 +562,8 @@ void __init efi_free_boot_services(void)
                    md->type != EFI_BOOT_SERVICES_DATA)
                        continue;
 
+               e820_adjust_region(&start, &size);
+
                /* Could not reserve boot area */
                if (!size)
                        continue;