diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 5852a47..996b545 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -37,9 +37,22 @@ void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, grub_efi_uint32_t attributes); int EXPORT_FUNC(grub_efi_set_text_mode) (int on); void EXPORT_FUNC(grub_efi_stall) (grub_efi_uintn_t microseconds); + +void * +EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages, + grub_efi_memory_type_t memtype); +void * +EXPORT_FUNC(grub_efi_allocate_pages_before) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages, + grub_efi_memory_type_t memtype); void * EXPORT_FUNC(grub_efi_allocate_pages) (grub_efi_physical_address_t address, grub_efi_uintn_t pages); +void * +EXPORT_FUNC(grub_efi_typed_allocate_pages) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages, + grub_efi_allocate_type_t type, + grub_efi_memory_type_t memtype); void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, grub_efi_uintn_t pages); int diff --git a/kern/efi/mm.c b/kern/efi/mm.c index ceb8fc9..0138ed3 100644 --- a/kern/efi/mm.c +++ b/kern/efi/mm.c @@ -49,6 +49,20 @@ static struct allocated_page *allocated_pages = 0; #define MIN_HEAP_SIZE 0x100000 #define MAX_HEAP_SIZE (1600 * 0x100000) +void * +grub_efi_allocate_any_pages (grub_efi_uintn_t pages, + grub_efi_memory_type_t memtype) +{ + return grub_efi_typed_allocate_pages (0, pages, GRUB_EFI_ALLOCATE_ANY_PAGES, memtype); +} + +void * +grub_efi_allocate_pages_before (grub_efi_physical_address_t address, + grub_efi_uintn_t pages, + grub_efi_memory_type_t memtype) +{ + return grub_efi_typed_allocate_pages (address, pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, memtype); +} /* Allocate pages. Return the pointer to the first of allocated pages. */ void * @@ -56,14 +70,6 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, grub_efi_uintn_t pages) { grub_efi_allocate_type_t type; - grub_efi_status_t status; - grub_efi_boot_services_t *b; - -#if GRUB_TARGET_SIZEOF_VOID_P < 8 - /* Limit the memory access to less than 4GB for 32-bit platforms. */ - if (address > 0xffffffff) - return 0; -#endif #if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL) if (address == 0) @@ -80,20 +86,40 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, type = GRUB_EFI_ALLOCATE_ADDRESS; #endif + return grub_efi_typed_allocate_pages (address, pages, type, GRUB_EFI_LOADER_DATA); +} + +void * +grub_efi_typed_allocate_pages (grub_efi_physical_address_t address, + grub_efi_uintn_t pages, + grub_efi_allocate_type_t type, + grub_efi_memory_type_t memtype) +{ + grub_efi_status_t status; + grub_efi_boot_services_t *b; + +#if GRUB_TARGET_SIZEOF_VOID_P < 8 + /* Limit the memory access to less than 4GB for 32-bit platforms. */ + if (address > 0xffffffff) + return 0; +#endif + b = grub_efi_system_table->boot_services; - status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address); - if (status != GRUB_EFI_SUCCESS) + status = efi_call_4 (b->allocate_pages, type, memtype, pages, &address); + if (status != GRUB_EFI_SUCCESS) { return 0; + } if (address == 0) { /* Uggh, the address 0 was allocated... This is too annoying, so reallocate another one. */ address = 0xffffffff; - status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address); + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, memtype, pages, &address); grub_efi_free_pages (0, pages); - if (status != GRUB_EFI_SUCCESS) - return 0; + if (status != GRUB_EFI_SUCCESS) { + return 0; + } } if (allocated_pages) diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c index a6db22e..fda4362 100644 --- a/loader/i386/efi/linux.c +++ b/loader/i386/efi/linux.c @@ -161,10 +161,8 @@ free_pages (void) static int allocate_pages (grub_size_t prot_size) { - grub_efi_uintn_t desc_size; - grub_efi_memory_descriptor_t *mmap, *mmap_end; - grub_efi_uintn_t mmap_size, tmp_mmap_size; - grub_efi_memory_descriptor_t *desc; + grub_efi_memory_descriptor_t *mmap; + grub_efi_uintn_t mmap_size; grub_size_t real_size; /* Make sure that each size is aligned to a page boundary. */ @@ -184,53 +182,7 @@ allocate_pages (grub_size_t prot_size) real_mode_mem = 0; prot_mode_mem = 0; - /* Read the memory map temporarily, to find free space. */ - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - tmp_mmap_size = mmap_size; - if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0) - grub_fatal ("cannot get memory map"); - - mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size); - - /* First, find free pages for the real mode code - and the memory map buffer. */ - for (desc = mmap; - desc < mmap_end; - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - /* Probably it is better to put the real mode code in the traditional - space for safety. */ - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->physical_start <= 0x90000 - && desc->num_pages >= real_mode_pages) - { - grub_efi_physical_address_t physical_end; - grub_efi_physical_address_t addr; - - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > 0x90000) - physical_end = 0x90000; - - grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n", - (unsigned) desc->physical_start, - (unsigned) physical_end); - addr = physical_end - real_size - mmap_size; - if (addr < 0x10000) - continue; - - grub_dprintf ("linux", "trying to allocate %u pages at %lx\n", - (unsigned) real_mode_pages, (unsigned long) addr); - real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages); - if (! real_mode_mem) - grub_fatal ("cannot allocate pages"); - - desc->num_pages -= real_mode_pages; - break; - } - } + real_mode_mem = grub_efi_allocate_pages_before (0x90000, real_mode_pages, GRUB_EFI_LOADER_DATA); if (! real_mode_mem) { @@ -242,7 +194,7 @@ allocate_pages (grub_size_t prot_size) /* Next, find free pages for the protected mode code. */ /* XXX what happens if anything is using this address? */ - prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1); + prot_mode_mem = grub_efi_allocate_any_pages(prot_mode_pages + 1, GRUB_EFI_LOADER_DATA); if (! prot_mode_mem) { grub_error (GRUB_ERR_OUT_OF_MEMORY, @@ -900,11 +852,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - grub_addr_t addr_min, addr_max; - grub_addr_t addr; - grub_efi_uintn_t mmap_size; - grub_efi_memory_descriptor_t *desc; - grub_efi_uintn_t desc_size; + grub_addr_t addr_max; struct linux_kernel_header *lh; if (argc == 0) @@ -938,48 +886,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), worse than that of Linux 2.3.xx, so avoid the last 64kb. */ addr_max -= 0x10000; - /* Usually, the compression ratio is about 50%. */ - addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) - + page_align (size); - - /* Find the highest address to put the initrd. */ - mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0) - grub_fatal ("cannot get memory map"); - - addr = 0; - for (desc = mmap_buf; - desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->num_pages >= initrd_pages) - { - grub_efi_physical_address_t physical_end; - - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > addr_max) - physical_end = addr_max; - - if (physical_end < page_align (size)) - continue; - - physical_end -= page_align (size); - - if ((physical_end >= addr_min) && - (physical_end >= desc->physical_start) && - (physical_end > addr)) - addr = physical_end; - } - } - - if (addr == 0) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available"); - goto fail; - } - - initrd_mem = grub_efi_allocate_pages (addr, initrd_pages); + initrd_mem = grub_efi_allocate_pages_before (addr_max, initrd_pages, GRUB_EFI_LOADER_DATA); if (! initrd_mem) grub_fatal ("cannot allocate pages"); @@ -989,10 +896,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n", - (unsigned) addr, (unsigned) size); + grub_printf (" [Initrd, addr=0x%lx, size=0x%x]\n", + (grub_addr_t) initrd_mem, (unsigned) size); - lh->ramdisk_image = addr; + lh->ramdisk_image = (grub_addr_t) initrd_mem; lh->ramdisk_size = size; lh->root_dev = 0x0100; /* XXX */