x86: Don't use the EFI reboot method by default
[pandora-kernel.git] / arch / x86 / platform / efi / efi.c
index b30aa26..899e393 100644 (file)
@@ -304,6 +304,61 @@ static void __init print_efi_memmap(void)
 }
 #endif  /*  EFI_DEBUG  */
 
+void __init efi_reserve_boot_services(void)
+{
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               efi_memory_desc_t *md = p;
+               u64 start = md->phys_addr;
+               u64 size = md->num_pages << EFI_PAGE_SHIFT;
+
+               if (md->type != EFI_BOOT_SERVICES_CODE &&
+                   md->type != EFI_BOOT_SERVICES_DATA)
+                       continue;
+               /* Only reserve where possible:
+                * - Not within any already allocated areas
+                * - Not over any memory area (really needed, if above?)
+                * - Not within any part of the kernel
+                * - Not the bios reserved area
+               */
+               if ((start+size >= virt_to_phys(_text)
+                               && start <= virt_to_phys(_end)) ||
+                       !e820_all_mapped(start, start+size, E820_RAM) ||
+                       memblock_x86_check_reserved_size(&start, &size,
+                                                       1<<EFI_PAGE_SHIFT)) {
+                       /* Could not reserve, skip it */
+                       md->num_pages = 0;
+                       memblock_dbg(PFX "Could not reserve boot range "
+                                       "[0x%010llx-0x%010llx]\n",
+                                               start, start+size-1);
+               } else
+                       memblock_x86_reserve_range(start, start+size,
+                                                       "EFI Boot");
+       }
+}
+
+static void __init efi_free_boot_services(void)
+{
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               efi_memory_desc_t *md = p;
+               unsigned long long start = md->phys_addr;
+               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+
+               if (md->type != EFI_BOOT_SERVICES_CODE &&
+                   md->type != EFI_BOOT_SERVICES_DATA)
+                       continue;
+
+               /* Could not reserve boot area */
+               if (!size)
+                       continue;
+
+               free_bootmem_late(start, size);
+       }
+}
+
 void __init efi_init(void)
 {
        efi_config_table_t *config_tables;
@@ -449,9 +504,6 @@ void __init efi_init(void)
        x86_platform.set_wallclock = efi_set_rtc_mmss;
 #endif
 
-       /* Setup for EFI runtime service */
-       reboot_type = BOOT_EFI;
-
 #if EFI_DEBUG
        print_efi_memmap();
 #endif
@@ -536,7 +588,9 @@ void __init efi_enter_virtual_mode(void)
 
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+               if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+                   md->type != EFI_BOOT_SERVICES_CODE &&
+                   md->type != EFI_BOOT_SERVICES_DATA)
                        continue;
 
                size = md->num_pages << EFI_PAGE_SHIFT;
@@ -592,6 +646,13 @@ void __init efi_enter_virtual_mode(void)
                panic("EFI call to SetVirtualAddressMap() failed!");
        }
 
+       /*
+        * Thankfully, it does seem that no runtime services other than
+        * SetVirtualAddressMap() will touch boot services code, so we can
+        * get rid of it all at this point
+        */
+       efi_free_boot_services();
+
        /*
         * Now that EFI is in virtual mode, update the function
         * pointers in the runtime service table to the new virtual addresses.