From 9be4c45dbe3c877d1f4856e99ee15133c6cd2261 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 3 Mar 2012 20:06:41 +0100 Subject: [PATCH] boot services avoid code based on the patch by Matthew Garrett --- grub-core/lib/i386/reboot.c | 3 +- grub-core/lib/i386/relocator.c | 12 ++- grub-core/lib/relocator.c | 10 ++- grub-core/loader/i386/bsd.c | 15 ++-- grub-core/loader/i386/coreboot/chainloader.c | 2 +- grub-core/loader/i386/linux.c | 77 ++++++++++++++++++-- grub-core/loader/i386/multiboot_mbi.c | 2 +- grub-core/loader/i386/pc/linux.c | 2 +- grub-core/loader/i386/pc/plan9.c | 2 +- grub-core/loader/i386/xnu.c | 4 +- grub-core/loader/multiboot.c | 4 +- grub-core/loader/multiboot_elfxx.c | 3 +- grub-core/loader/multiboot_mbi2.c | 2 +- grub-core/loader/xnu_resume.c | 2 +- grub-core/mmap/efi/mmap.c | 24 +++++- include/grub/efi/efi.h | 3 + include/grub/i386/relocator.h | 3 +- include/grub/relocator.h | 3 +- 18 files changed, 136 insertions(+), 37 deletions(-) diff --git a/grub-core/lib/i386/reboot.c b/grub-core/lib/i386/reboot.c index 45a2259cf..0587f1477 100644 --- a/grub-core/lib/i386/reboot.c +++ b/grub-core/lib/i386/reboot.c @@ -38,7 +38,8 @@ grub_reboot (void) while (1); err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000, 0x1000, grub_reboot_end - grub_reboot_start, - 16, GRUB_RELOCATOR_PREFERENCE_NONE); + 16, GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) while (1); buf = get_virtual_current_address (ch); diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c index 90af4035a..df25b30fa 100644 --- a/grub-core/lib/i386/relocator.c +++ b/grub-core/lib/i386/relocator.c @@ -155,7 +155,8 @@ grub_cpu_relocator_forward (void *ptr, void *src, void *dest, grub_err_t grub_relocator32_boot (struct grub_relocator *rel, - struct grub_relocator32_state state) + struct grub_relocator32_state state, + int avoid_efi_bootservices) { grub_err_t err; void *relst; @@ -164,7 +165,8 @@ grub_relocator32_boot (struct grub_relocator *rel, err = grub_relocator_alloc_chunk_align (rel, &ch, 0, (0xffffffff - RELOCATOR_SIZEOF (32)) + 1, RELOCATOR_SIZEOF (32), 16, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + avoid_efi_bootservices); if (err) return err; @@ -207,7 +209,8 @@ grub_relocator16_boot (struct grub_relocator *rel, - GRUB_RELOCATOR16_STACK_SIZE, RELOCATOR_SIZEOF (16) + GRUB_RELOCATOR16_STACK_SIZE, 16, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) return err; @@ -261,7 +264,8 @@ grub_relocator64_boot (struct grub_relocator *rel, err = grub_relocator_alloc_chunk_align (rel, &ch, min_addr, max_addr - RELOCATOR_SIZEOF (64), RELOCATOR_SIZEOF (64), 16, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) return err; diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index b391f0575..aa4a39ebc 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -1319,7 +1319,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, grub_phys_addr_t min_addr, grub_phys_addr_t max_addr, grub_size_t size, grub_size_t align, - int preference) + int preference, + int avoid_efi_boot_services) { grub_addr_t min_addr2 = 0, max_addr2; struct grub_relocator_chunk *chunk; @@ -1406,7 +1407,12 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, return 0; } - grub_machine_mmap_iterate (hook); +#ifdef GRUB_MACHINE_EFI + grub_efi_mmap_iterate (hook, avoid_efi_boot_services); +#else + (void) avoid_efi_boot_services; + grub_mmap_iterate (hook); +#endif if (!found) return grub_error (GRUB_ERR_BAD_OS, "couldn't find suitable memory target"); } diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index dc05c67f5..299cedc48 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -723,7 +723,8 @@ grub_freebsd_boot (void) 0x10000, 0x90000, 3 * sizeof (grub_uint32_t) + sizeof (bi), 4, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) return err; stack = get_virtual_current_address (ch); @@ -760,7 +761,8 @@ grub_freebsd_boot (void) 0x10000, 0x90000, 9 * sizeof (grub_uint32_t) + sizeof (bi), 4, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) return err; stack = get_virtual_current_address (ch); @@ -786,7 +788,7 @@ grub_freebsd_boot (void) stack[6] = stack_target + 9 * sizeof (grub_uint32_t); stack[7] = bi.tags; stack[8] = kern_end; - return grub_relocator32_boot (relocator, state); + return grub_relocator32_boot (relocator, state, 0); } /* Not reached. */ @@ -873,7 +875,7 @@ grub_openbsd_boot (void) stack[7] = (grub_uint8_t *) curarg - (grub_uint8_t *) arg0; stack[8] = ((grub_uint8_t *) arg0 - (grub_uint8_t *) buf0) + buf_target; - return grub_relocator32_boot (relocator, state); + return grub_relocator32_boot (relocator, state, 0); } static grub_err_t @@ -1144,7 +1146,8 @@ grub_netbsd_boot (void) grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x10000, 0x90000, 7 * sizeof (grub_uint32_t), 4, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) return err; stack = get_virtual_current_address (ch); @@ -1168,7 +1171,7 @@ grub_netbsd_boot (void) stack[5] = grub_mmap_get_upper () >> 10; stack[6] = grub_mmap_get_lower () >> 10; - return grub_relocator32_boot (relocator, state); + return grub_relocator32_boot (relocator, state, 0); } static grub_err_t diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c index a66033b9a..df4e276fd 100644 --- a/grub-core/loader/i386/coreboot/chainloader.c +++ b/grub-core/loader/i386/coreboot/chainloader.c @@ -43,7 +43,7 @@ grub_chain_boot (void) grub_video_set_mode ("text", 0, 0); state.eip = entry; - return grub_relocator32_boot (relocator, state); + return grub_relocator32_boot (relocator, state, 0); } static grub_err_t diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index e2a988a50..15f4bac3a 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -189,7 +189,9 @@ free_pages (void) /* Allocate pages for the real mode code and the protected mode code for linux as well as a memory map buffer. */ static grub_err_t -allocate_pages (grub_size_t prot_size) +allocate_pages (grub_size_t prot_size, grub_size_t *align, + grub_size_t min_align, int relocatable, + grub_uint64_t prefered_address) { grub_size_t real_size, mmap_size; grub_err_t err; @@ -254,7 +256,11 @@ allocate_pages (grub_size_t prot_size) return 0; } +#ifdef GRUB_MACHINE_EFI + grub_efi_mmap_iterate (hook, 1); +#else grub_mmap_iterate (hook); +#endif if (! real_mode_target) { err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); @@ -273,15 +279,36 @@ allocate_pages (grub_size_t prot_size) } efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size + mmap_size; - prot_mode_target = GRUB_LINUX_BZIMAGE_ADDR; - { grub_relocator_chunk_t ch; - err = grub_relocator_alloc_chunk_addr (relocator, &ch, - prot_mode_target, prot_size); + if (relocatable) + { + err = grub_relocator_alloc_chunk_align (relocator, &ch, + prefered_address, + prefered_address, + prot_size, 1, + GRUB_RELOCATOR_PREFERENCE_LOW, + 1); + for (; err && *align >= min_align; (*align)--) + { + grub_errno = GRUB_ERR_NONE; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x1000000, 0xffffffff, + prot_size, 1 << *align, + GRUB_RELOCATOR_PREFERENCE_LOW, + 1); + } + if (err) + goto fail; + } + else + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + prefered_address, + prot_size); if (err) goto fail; prot_mode_mem = get_virtual_current_address (ch); + prot_mode_target = get_physical_target_address (ch); } grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, " @@ -612,7 +639,7 @@ grub_linux_boot (void) state.esi = real_mode_target; state.esp = real_mode_target; state.eip = params->code32_start; - return grub_relocator32_boot (relocator, state); + return grub_relocator32_boot (relocator, state, 0); } static grub_err_t @@ -634,6 +661,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_size_t real_size, prot_size; grub_ssize_t len; int i; + grub_size_t align, min_align; + int relocatable; + grub_uint64_t preffered_address = GRUB_LINUX_BZIMAGE_ADDR; grub_dl_ref (my_mod); @@ -707,7 +737,37 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), real_size = setup_sects << GRUB_DISK_SECTOR_BITS; prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - if (allocate_pages (prot_size)) + if (grub_le_to_cpu16 (lh.version) >= 0x205 + && lh.kernel_alignment != 0 + && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0) + { + for (align = 0; align < 32; align++) + if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align)) + break; + relocatable = grub_le_to_cpu32 (lh.relocatable); + } + else + { + align = 0; + relocatable = 0; + } + + if (grub_le_to_cpu16 (lh.version) >= 0x020a) + { + min_align = lh.min_alignment; + prot_size = grub_le_to_cpu32 (lh.init_size); + preffered_address = grub_le_to_cpu64 (lh.pref_address); + } + else + { + min_align = 0; + prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; + preffered_address = grub_le_to_cpu32 (lh.code32_start); + } + + if (allocate_pages (prot_size, &align, + min_align, relocatable, + preffered_address)) goto fail; params = (struct linux_kernel_params *) real_mode_mem; @@ -1021,7 +1081,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (relocator, &ch, addr_min, addr, size, 0x1000, - GRUB_RELOCATOR_PREFERENCE_HIGH); + GRUB_RELOCATOR_PREFERENCE_HIGH, + 1); if (err) return err; initrd_mem = get_virtual_current_address (ch); diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index e41a4d895..8fc40d713 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -454,7 +454,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target) err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0x10000, 0x100000 - bufsize, bufsize, 4, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; ptrorig = get_virtual_current_address (ch); diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index dfa6e6f30..90497c0cc 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -429,7 +429,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), err = grub_relocator_alloc_chunk_align (relocator, &ch, addr_min, addr_max - size, size, 0x1000, - GRUB_RELOCATOR_PREFERENCE_HIGH); + GRUB_RELOCATOR_PREFERENCE_HIGH, 0); if (err) return err; initrd_chunk = get_virtual_current_address (ch); diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c index 1c021b22b..b41dfd29f 100644 --- a/grub-core/loader/i386/pc/plan9.c +++ b/grub-core/loader/i386/pc/plan9.c @@ -90,7 +90,7 @@ grub_plan9_boot (void) }; grub_video_set_mode ("text", 0, 0); - return grub_relocator32_boot (rel, state); + return grub_relocator32_boot (rel, state, 0); } static grub_err_t diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index 7fcb6e11a..0e4d38f4f 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -842,7 +842,7 @@ grub_xnu_boot_resume (void) state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; - return grub_relocator32_boot (grub_xnu_relocator, state); + return grub_relocator32_boot (grub_xnu_relocator, state, 0); } /* Setup video for xnu. */ @@ -1150,7 +1150,7 @@ grub_xnu_boot (void) grub_outb (0xff, 0x21); grub_outb (0xff, 0xa1); - return grub_relocator32_boot (grub_xnu_relocator, state); + return grub_relocator32_boot (grub_xnu_relocator, state, 0); } static grub_command_t cmd_devprop_load; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index f656cf530..dd5057241 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -134,7 +134,7 @@ grub_multiboot_boot (void) return err; #endif - grub_relocator32_boot (grub_multiboot_relocator, state); + grub_relocator32_boot (grub_multiboot_relocator, state, 0); /* Not reached. */ return GRUB_ERR_NONE; @@ -307,7 +307,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, (0xffffffff - size) + 1, size, MULTIBOOT_MOD_ALIGN, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) { grub_file_close (file); diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index f38f37262..26984f49a 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -200,7 +200,8 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, const char *filename, voi (0xffffffff - sh->sh_size) + 1, sh->sh_size, sh->sh_addralign, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, + 0); if (err) { grub_dprintf ("multiboot_loader", "Error loading shdr %d\n", i); diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 62510288c..a48f02076 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -588,7 +588,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target) err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, 0xffffffff - bufsize, bufsize, MULTIBOOT_TAG_ALIGN, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index d7f9adaaf..e99ea142e 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -125,7 +125,7 @@ grub_xnu_resume (char *imagename) (0xffffffff - hibhead.image_size) + 1, hibhead.image_size, GRUB_XNU_PAGESIZE, - GRUB_RELOCATOR_PREFERENCE_NONE); + GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) { grub_file_close (file); diff --git a/grub-core/mmap/efi/mmap.c b/grub-core/mmap/efi/mmap.c index 773559753..a34a7ac53 100644 --- a/grub-core/mmap/efi/mmap.c +++ b/grub-core/mmap/efi/mmap.c @@ -29,7 +29,7 @@ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) grub_err_t -grub_machine_mmap_iterate (grub_memory_hook_t hook) +grub_efi_mmap_iterate (grub_memory_hook_t hook, int avoid_efi_boot_services) { grub_efi_uintn_t mmap_size = 0; grub_efi_memory_descriptor_t *map_buf = 0; @@ -65,6 +65,13 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) + desc->num_pages * 4096, desc->type); switch (desc->type) { + case GRUB_EFI_BOOT_SERVICES_CODE: + if (!avoid_efi_boot_services) + { + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_AVAILABLE); + break; + } case GRUB_EFI_RUNTIME_SERVICES_CODE: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_CODE); @@ -79,6 +86,13 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) grub_printf ("Unknown memory type %d, considering reserved\n", desc->type); + case GRUB_EFI_BOOT_SERVICES_DATA: + if (!avoid_efi_boot_services) + { + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_AVAILABLE); + break; + } case GRUB_EFI_RESERVED_MEMORY_TYPE: case GRUB_EFI_RUNTIME_SERVICES_DATA: case GRUB_EFI_MEMORY_MAPPED_IO: @@ -90,8 +104,6 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) case GRUB_EFI_LOADER_CODE: case GRUB_EFI_LOADER_DATA: - case GRUB_EFI_BOOT_SERVICES_CODE: - case GRUB_EFI_BOOT_SERVICES_DATA: case GRUB_EFI_CONVENTIONAL_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_AVAILABLE); @@ -112,6 +124,12 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) return GRUB_ERR_NONE; } +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook, int avoid_efi_boot_services) +{ + return grub_efi_mmap_iterate (hook, 0); +} + static inline grub_efi_memory_type_t make_efi_memtype (int type) { diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 067e3bdac..811dc3d6c 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -85,4 +85,7 @@ extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); extern int EXPORT_VAR(grub_efi_is_finished); +grub_err_t +grub_efi_mmap_iterate (grub_memory_hook_t hook, int avoid_efi_boot_services); + #endif /* ! GRUB_EFI_EFI_HEADER */ diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h index b2fe900b6..46becb8ea 100644 --- a/include/grub/i386/relocator.h +++ b/include/grub/i386/relocator.h @@ -68,7 +68,8 @@ grub_err_t grub_relocator16_boot (struct grub_relocator *rel, struct grub_relocator16_state state); grub_err_t grub_relocator32_boot (struct grub_relocator *rel, - struct grub_relocator32_state state); + struct grub_relocator32_state state, + int avoid_efi_bootservices); grub_err_t grub_relocator64_boot (struct grub_relocator *rel, struct grub_relocator64_state state, diff --git a/include/grub/relocator.h b/include/grub/relocator.h index 653a00eba..24d8672d2 100644 --- a/include/grub/relocator.h +++ b/include/grub/relocator.h @@ -46,7 +46,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, grub_phys_addr_t min_addr, grub_phys_addr_t max_addr, grub_size_t size, grub_size_t align, - int preference); + int preference, + int avoid_efi_boot_services); #define GRUB_RELOCATOR_PREFERENCE_NONE 0 #define GRUB_RELOCATOR_PREFERENCE_LOW 1