diff --git a/include/grub/relocator.h b/include/grub/relocator.h index 2ea74b775..32bab7053 100644 --- a/include/grub/relocator.h +++ b/include/grub/relocator.h @@ -34,7 +34,12 @@ grub_err_t grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, grub_addr_t *target, grub_addr_t min_addr, grub_addr_t max_addr, - grub_size_t size, grub_size_t align); + grub_size_t size, grub_size_t align, + int preference); + +#define GRUB_RELOCATOR_PREFERENCE_NONE 0 +#define GRUB_RELOCATOR_PREFERENCE_LOW 1 +#define GRUB_RELOCATOR_PREFERENCE_HIGH 2 void grub_relocator_unload (struct grub_relocator *rel); diff --git a/lib/i386/relocator.c b/lib/i386/relocator.c index e81dd8e1e..6e1e13b04 100644 --- a/lib/i386/relocator.c +++ b/lib/i386/relocator.c @@ -129,7 +129,8 @@ grub_relocator32_boot (struct grub_relocator *rel, err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0, (0xffffffff - RELOCATOR_SIZEOF (32)) - + 1, RELOCATOR_SIZEOF (32), 16); + + 1, RELOCATOR_SIZEOF (32), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; @@ -166,7 +167,8 @@ grub_relocator64_boot (struct grub_relocator *rel, err = grub_relocator_alloc_chunk_align (rel, &src, &target, min_addr, max_addr - RELOCATOR_SIZEOF (64), - RELOCATOR_SIZEOF (64), 16); + RELOCATOR_SIZEOF (64), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; diff --git a/lib/relocator.c b/lib/relocator.c index 3085932c5..a5b3c6daf 100644 --- a/lib/relocator.c +++ b/lib/relocator.c @@ -446,7 +446,8 @@ grub_err_t grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, grub_addr_t *target, grub_addr_t min_addr, grub_addr_t max_addr, - grub_size_t size, grub_size_t align) + grub_size_t size, grub_size_t align, + int preference) { grub_addr_t min_addr2 = 0, max_addr2; struct grub_relocator_chunk *chunk; @@ -455,6 +456,11 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, if (max_addr > ~size) max_addr = ~size; +#ifdef GRUB_MACHINE_PCBIOS + if (min_addr < 0x1000) + min_addr = 0x1000; +#endif + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); @@ -462,7 +468,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, return grub_errno; if (malloc_in_range (rel, min_addr, max_addr, align, - size, &start, 1, 1)) + size, &start, + preference != GRUB_RELOCATOR_PREFERENCE_HIGH, 1)) { grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", (unsigned long long) start, (unsigned long long) start); @@ -500,7 +507,10 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, while (0); /* FIXME: check memory map. */ - chunk->target = ALIGN_UP (min_addr, align); + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + chunk->target = ALIGN_DOWN (max_addr, align); + else + chunk->target = ALIGN_UP (min_addr, align); while (1) { struct grub_relocator_chunk *chunk2; @@ -514,7 +524,10 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src, || (chunk->target <= chunk2->target + chunk2->size && chunk2->target + chunk2->size < chunk->target + size)) { - chunk->target = ALIGN_UP (chunk2->target + chunk2->size, align); + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + chunk->target = ALIGN_DOWN (chunk2->target, align); + else + chunk->target = ALIGN_UP (chunk2->target + chunk2->size, align); break; } if (!chunk2) diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index 90cd8a9a4..28bcde15e 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -550,7 +550,8 @@ grub_freebsd_boot (void) &stack_target, 0x10000, 0x90000, 3 * sizeof (grub_uint32_t) - + sizeof (bi), 4); + + sizeof (bi), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; @@ -575,7 +576,8 @@ grub_freebsd_boot (void) &stack_target, 0x10000, 0x90000, 9 * sizeof (grub_uint32_t) - + sizeof (bi), 4); + + sizeof (bi), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; grub_memcpy (&stack[8], &bi, sizeof (bi)); @@ -798,7 +800,8 @@ grub_netbsd_boot (void) err = grub_relocator_alloc_chunk_align (relocator, (void **) &stack, &stack_target, 0x10000, 0x90000, - 7 * sizeof (grub_uint32_t), 4); + 7 * sizeof (grub_uint32_t), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; diff --git a/loader/i386/linux.c b/loader/i386/linux.c index e8d06b0e7..b6298d0bb 100644 --- a/loader/i386/linux.c +++ b/loader/i386/linux.c @@ -943,9 +943,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), addr_min = (grub_addr_t) prot_mode_target + ((prot_mode_pages * 3) << 12) + page_align (size); - if (addr_max > grub_os_area_addr + grub_os_area_size) - addr_max = grub_os_area_addr + grub_os_area_size; - /* Put the initrd as high as possible, 4KiB aligned. */ addr = (addr_max - size) & ~0xFFF; @@ -957,7 +954,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), err = grub_relocator_alloc_chunk_align (relocator, &initrd_mem, &initrd_mem_target, - addr_min, addr, size, 0x1000); + addr_min, addr, size, 0x1000, + GRUB_RELOCATOR_PREFERENCE_HIGH); if (err) return err; diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index c5a7f7f9d..2f9cc73c9 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -259,7 +259,8 @@ grub_module (int argc, char *argv[]) err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &module, &target, 0, (0xffffffff - size) + 1, - size, MULTIBOOT_MOD_ALIGN); + size, MULTIBOOT_MOD_ALIGN, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) goto fail; diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index ddaca7a1b..4fc9a7ac1 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -125,7 +125,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, (void **) &ptrorig, &ptrdest, 0, 0xffffffff - bufsize, - bufsize, 4); + bufsize, 4, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; diff --git a/loader/xnu_resume.c b/loader/xnu_resume.c index a7d5fbad8..2d47df601 100644 --- a/loader/xnu_resume.c +++ b/loader/xnu_resume.c @@ -115,7 +115,8 @@ grub_xnu_resume (char *imagename) &target_image, 0, (0xffffffff - hibhead.image_size) + 1, hibhead.image_size, - GRUB_XNU_PAGESIZE); + GRUB_XNU_PAGESIZE, + GRUB_RELOCATOR_PREFERENCE_NONE); if (err) { grub_file_close (file);