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);
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;
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;
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;
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));
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);
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;
|| (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)
&stack_target,
0x10000, 0x90000,
3 * sizeof (grub_uint32_t)
- + sizeof (bi), 4);
+ + sizeof (bi), 4,
+ GRUB_RELOCATOR_PREFERENCE_NONE);
if (err)
return err;
&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));
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;
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;
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;
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;
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;
&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);