EFI and OF both support firmware regions which may be in use during loading. Add support for avoiding these.
--- ChangeLog | 10 +++++++ grub-core/lib/efi/relocator.c | 47 +++++++++++++++++++++++++++++++++ grub-core/lib/ieee1275/relocator.c | 27 +++++++++++++++++++ grub-core/lib/relocator.c | 12 +++++++- grub-core/loader/i386/bsd.c | 19 +++++++----- grub-core/loader/i386/bsdXX.c | 8 +++--- grub-core/loader/i386/linux.c | 4 +- grub-core/loader/i386/multiboot_mbi.c | 2 +- grub-core/loader/i386/pc/freedos.c | 2 +- grub-core/loader/i386/pc/linux.c | 4 +- grub-core/loader/i386/pc/ntldr.c | 4 +- grub-core/loader/mips/linux.c | 6 ++-- grub-core/loader/multiboot_elfxx.c | 2 +- grub-core/loader/multiboot_mbi2.c | 2 +- grub-core/loader/xnu.c | 2 +- grub-core/loader/xnu_resume.c | 2 +- include/grub/relocator.h | 3 +- include/grub/relocator_private.h | 2 + 18 files changed, 129 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 028691d..0a94fc0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2012-02-03 Matthew Garrett <m...@redhat.com> + * grub-core/lib/efi/relocator.c (grub_relocator_alloc_chunk_addr): + Add argument to fail allocation when target address overlaps + firmware regions. All users updated. + * grub-core/lib/efi/relocator.c (grub_relocator_firmware_overlaps): + New function + * grub-core/lib/ieee1275/relocator.c (grub_relocator_firmware_overlaps): + Likewise + +2012-02-03 Matthew Garrett <m...@redhat.com> + * include/grub/i386/linux.h (linux_kernel_header): Update to boot protocol 2.10. (linux_kernel_params): Likewise diff --git a/grub-core/lib/efi/relocator.c b/grub-core/lib/efi/relocator.c index 0d346be..a8dd8c2 100644 --- a/grub-core/lib/efi/relocator.c +++ b/grub-core/lib/efi/relocator.c @@ -39,6 +39,53 @@ grub_relocator_firmware_get_max_events (void) return 2 * (mmapsize / descriptor_size + 10); } +unsigned +grub_relocator_firmware_overlaps (grub_phys_addr_t target, grub_size_t size) +{ + grub_efi_uintn_t mmapsize = 0, desc_size = 0; + grub_efi_uint32_t descriptor_version = 0; + grub_efi_memory_descriptor_t *descs = NULL; + grub_efi_uintn_t key; + int overlap = 0; + grub_efi_memory_descriptor_t *desc; + + grub_efi_get_memory_map (&mmapsize, NULL, &key, &desc_size, + &descriptor_version); + descs = grub_malloc (mmapsize); + if (!descs) + return 0; + + grub_efi_get_memory_map (&mmapsize, descs, &key, &desc_size, + &descriptor_version); + + for (desc = descs; + (char *) desc < ((char *) descs + mmapsize); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_uint64_t start = desc->physical_start; + grub_uint64_t end = desc->physical_start + (desc->num_pages << 12); + + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + + if (target >= start && target <= end) + { + overlap = 1; + break; + } + + if (target + size >= start && target + size <= end) + { + overlap = 1; + break; + } + } + + grub_free(descs); + + return overlap; +} + unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) { diff --git a/grub-core/lib/ieee1275/relocator.c b/grub-core/lib/ieee1275/relocator.c index c09f1e9..31cedcb 100644 --- a/grub-core/lib/ieee1275/relocator.c +++ b/grub-core/lib/ieee1275/relocator.c @@ -42,6 +42,33 @@ grub_relocator_firmware_get_max_events (void) return 2 * counter; } +unsigned +grub_relocator_firmware_overlaps (grub_phys_addr_t target, grub_size_t size) +{ + int overlap = 0; + auto int NESTED_FUNC_ATTR check (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type); + int NESTED_FUNC_ATTR check (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type) + { + grub_uint64_t end = addr + len; + + if (type == GRUB_MEMORY_AVAILABLE) + return 0; + + if (target >= addr && target <= end) + overlap = 1; + + if (target + size >= addr && target + size <= end) + overlap = 1; + + return 0; + } + + grub_machine_mmap_iterate (check); + return overlap; +} + unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) { diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index 6630646..7e202a5 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -1203,7 +1203,8 @@ adjust_limits (struct grub_relocator *rel, grub_err_t grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, grub_relocator_chunk_t *out, - grub_phys_addr_t target, grub_size_t size) + grub_phys_addr_t target, grub_size_t size, + int avoid_firmware) { struct grub_relocator_chunk *chunk; grub_phys_addr_t min_addr = 0, max_addr; @@ -1213,6 +1214,15 @@ grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, adjust_limits (rel, &min_addr, &max_addr, target, target); + if (avoid_firmware) + { +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + if (grub_relocator_firmware_overlaps(target, size)) + + return grub_error(GRUB_ERR_BAD_ARGUMENT, "target overlaps with firmware"); +#endif + } + for (chunk = rel->chunks; chunk; chunk = chunk->next) if ((chunk->target <= target && target < chunk->target + chunk->size) || (target <= chunk->target && chunk->target < target + size)) diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 835f146..f7b89a6 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -606,7 +606,7 @@ grub_freebsd_boot (void) { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - kern_end, p_size); + kern_end, p_size, 0); if (err) return err; p = get_virtual_current_address (ch); @@ -788,7 +788,7 @@ grub_openbsd_boot (void) err = grub_relocator_alloc_chunk_addr (relocator, &ch, buf_target, tag_buf_len + sizeof (struct grub_openbsd_bootargs) - + 9 * sizeof (grub_uint32_t)); + + 9 * sizeof (grub_uint32_t), 0); if (err) return err; buf0 = get_virtual_current_address (ch); @@ -1079,7 +1079,8 @@ grub_netbsd_boot (void) err = grub_relocator_alloc_chunk_addr (relocator, &ch, arg_target, tag_buf_len + sizeof (struct grub_netbsd_bootinfo) - + tag_count * sizeof (grub_uint32_t)); + + tag_count * sizeof (grub_uint32_t), + 0); if (err) return err; curarg = get_virtual_current_address (ch); @@ -1219,7 +1220,8 @@ grub_bsd_load_aout (grub_file_t file, const char *filename) grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - kern_start, kern_end - kern_start); + kern_start, kern_end - kern_start, + 0); if (err) return err; kern_chunk_src = get_virtual_current_address (ch); @@ -1330,7 +1332,8 @@ grub_bsd_load_elf (grub_elf_t elf) if (err) return err; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - kern_start, kern_end - kern_start); + kern_start, kern_end - kern_start, + 0); if (err) return err; @@ -1373,7 +1376,7 @@ grub_bsd_load_elf (grub_elf_t elf) grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, - kern_end - kern_start); + kern_end - kern_start, 0); if (err) return err; kern_chunk_src = get_virtual_current_address (ch); @@ -1837,7 +1840,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, - file->size); + file->size, 0); if (err) goto fail; src = get_virtual_current_address (ch); @@ -1888,7 +1891,7 @@ grub_netbsd_module_load (char *filename, grub_uint32_t type) { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, - file->size); + file->size, 0); if (err) goto fail; diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 7cec7a8..239c633 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -106,7 +106,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - module, chunk_size); + module, chunk_size, 0); if (err) return err; chunk_src = get_virtual_current_address (ch); @@ -204,7 +204,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - module, chunk_size); + module, chunk_size, 0); if (err) return err; @@ -319,7 +319,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - symtarget, chunk_size); + symtarget, chunk_size, 0); if (err) return err; sym_chunk = get_virtual_current_address (ch); @@ -434,7 +434,7 @@ SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - symtarget, chunk_size); + symtarget, chunk_size, 0); if (err) return err; sym_chunk = get_virtual_current_address (ch); diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index a5bcb24..67a4533 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -266,7 +266,7 @@ allocate_pages (grub_size_t prot_size) err = grub_relocator_alloc_chunk_addr (relocator, &ch, real_mode_target, (real_size + mmap_size - + efi_mmap_size)); + + efi_mmap_size), 0); if (err) goto fail; real_mode_mem = get_virtual_current_address (ch); @@ -278,7 +278,7 @@ allocate_pages (grub_size_t prot_size) { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, - prot_mode_target, prot_size); + prot_mode_target, prot_size, 0); if (err) goto fail; prot_mode_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 abd4ae9..a95abc9 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -119,7 +119,7 @@ grub_multiboot_load (grub_file_t file) err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, header->load_addr, - code_size); + code_size, 0); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); diff --git a/grub-core/loader/i386/pc/freedos.c b/grub-core/loader/i386/pc/freedos.c index 1f088e2..24b6dce 100644 --- a/grub-core/loader/i386/pc/freedos.c +++ b/grub-core/loader/i386/pc/freedos.c @@ -101,7 +101,7 @@ grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)), { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_SEGMENT << 4, - kernelsyssize); + kernelsyssize, 0); if (err) goto fail; kernelsys = get_virtual_current_address (ch); diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 7c4a4be..dee4126 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -273,7 +273,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), err = grub_relocator_alloc_chunk_addr (relocator, &ch, grub_linux_real_target, GRUB_LINUX_CL_OFFSET - + maximal_cmdline_size); + + maximal_cmdline_size, 0); if (err) return err; grub_linux_real_chunk = get_virtual_current_address (ch); @@ -317,7 +317,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, grub_linux_prot_target, - grub_linux16_prot_size); + grub_linux16_prot_size, 0); if (err) return err; grub_linux_prot_chunk = get_virtual_current_address (ch); diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c index 153b605..f613887 100644 --- a/grub-core/loader/i386/pc/ntldr.c +++ b/grub-core/loader/i386/pc/ntldr.c @@ -97,7 +97,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00, - GRUB_DISK_SECTOR_SIZE); + GRUB_DISK_SECTOR_SIZE, 0); if (err) goto fail; bs = get_virtual_current_address (ch); @@ -124,7 +124,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_NTLDR_SEGMENT << 4, - ntldrsize); + ntldrsize, 0); if (err) goto fail; ntldr = get_virtual_current_address (ch); diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 7fda817..8fba174 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -87,7 +87,7 @@ grub_linux_boot (void) err = grub_relocator_alloc_chunk_addr (relocator, &ch, ((16 << 20) - 264), - grub_strlen (params) + 1 + 8); + grub_strlen (params) + 1 + 8, 0); if (err) return err; memsize = get_virtual_current_address (ch); @@ -159,7 +159,7 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, target_addr & 0x1fffffff, - linux_size); + linux_size, 0); if (err) return err; playground = get_virtual_current_address (ch); @@ -214,7 +214,7 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (relocator, &ch, target_addr & 0x1fffffff, - linux_size); + linux_size, 0); if (err) return err; playground = get_virtual_current_address (ch); diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index c6c88f1..9bbc10b 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -102,7 +102,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, phdr(i)->p_paddr, - phdr(i)->p_memsz); + phdr(i)->p_memsz, 0); if (err) { grub_dprintf ("multiboot_loader", "Error loading phdr %d\n", i); diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 9a81afe..15760d0 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -227,7 +227,7 @@ grub_multiboot_load (grub_file_t file) err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, addr_tag->load_addr, - code_size); + code_size, 0); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index 44a440b..2d9482d 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -60,7 +60,7 @@ grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target) err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, grub_xnu_heap_target_start - + grub_xnu_heap_size, size); + + grub_xnu_heap_size, size, 0); if (err) return err; diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index d7f9ada..e4fdb95 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -110,7 +110,7 @@ grub_xnu_resume (char *imagename) { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, codedest, - codesize + GRUB_XNU_PAGESIZE); + codesize + GRUB_XNU_PAGESIZE, 0); if (err) { grub_file_close (file); diff --git a/include/grub/relocator.h b/include/grub/relocator.h index 653a00e..b250512 100644 --- a/include/grub/relocator.h +++ b/include/grub/relocator.h @@ -33,7 +33,8 @@ struct grub_relocator *grub_relocator_new (void); grub_err_t grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, grub_relocator_chunk_t *out, - grub_phys_addr_t target, grub_size_t size); + grub_phys_addr_t target, grub_size_t size, + int avoid_firmware); void * get_virtual_current_address (grub_relocator_chunk_t in); diff --git a/include/grub/relocator_private.h b/include/grub/relocator_private.h index 1c563cb..1948af4 100644 --- a/include/grub/relocator_private.h +++ b/include/grub/relocator_private.h @@ -104,6 +104,8 @@ struct grub_relocator_mmap_event #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS int grub_relocator_firmware_alloc_region (grub_phys_addr_t start, grub_size_t size); +unsigned grub_relocator_firmware_overlaps (grub_phys_addr_t start, + grub_size_t size); unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events); unsigned grub_relocator_firmware_get_max_events (void); void grub_relocator_firmware_free_region (grub_phys_addr_t start, -- 1.7.7.6 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel