File grub-0.97-relocatable-kernel-on-x86_64-uefi.patch of Package grub
This patch fixes the problem that UEFI boot fains on systems that
have the memory region starting at 1MB in use.
The strategy is as follows:
- Loading temporarily vmlinuz image to the address which AllocatePages()
function returned.
- After calling ExitBootServices() function, copy its reagion to the
address which params->hdr.code32_start points to.
Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
---
Index: grub-0.97/efi/efimm.c
===================================================================
--- grub-0.97.orig/efi/efimm.c
+++ grub-0.97/efi/efimm.c
@@ -78,6 +78,45 @@ grub_efi_free_pool (void *buffer)
Call_Service_1(b->free_pool, buffer);
}
+void *
+grub_efi_allocate_anypages(grub_efi_uintn_t pages)
+{
+ grub_efi_boot_services_t *b;
+ grub_efi_status_t status;
+ grub_efi_physical_address_t address;
+
+ b = grub_efi_system_table->boot_services;
+ status = Call_Service_4 (b->allocate_pages,
+ GRUB_EFI_ALLOCATE_ANY_PAGES,
+ GRUB_EFI_LOADER_DATA,
+ pages,
+ &address);
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+
+ if (allocated_pages)
+ {
+ unsigned i;
+
+ for (i = 0; i < MAX_ALLOCATED_PAGES; i++)
+ if (allocated_pages[i].addr == 0)
+ {
+ allocated_pages[i].addr = address;
+ allocated_pages[i].num_pages = pages;
+ break;
+ }
+
+ if (i == MAX_ALLOCATED_PAGES)
+ {
+ grub_printf ("too many page allocations");
+ return NULL;
+ }
+ }
+
+ return (void *) ((grub_addr_t) address);
+
+}
+
/* Allocate pages. Return the pointer to the first of allocated pages. */
void *
grub_efi_allocate_pages (grub_efi_physical_address_t address,
Index: grub-0.97/efi/grub/efi/efi.h
===================================================================
--- grub-0.97.orig/efi/grub/efi/efi.h
+++ grub-0.97/efi/grub/efi/efi.h
@@ -45,6 +45,7 @@ int grub_efi_set_text_mode (int on);
void grub_efi_stall (grub_efi_uintn_t microseconds);
void *grub_efi_allocate_pool (grub_efi_uintn_t size);
void grub_efi_free_pool (void *buffer);
+void *grub_efi_allocate_anypages (grub_efi_uintn_t pages);
void *grub_efi_allocate_pages (grub_efi_physical_address_t address,
grub_efi_uintn_t pages);
void
Index: grub-0.97/efi/x86_64/loader/linux.c
===================================================================
--- grub-0.97.orig/efi/x86_64/loader/linux.c
+++ grub-0.97/efi/x86_64/loader/linux.c
@@ -40,6 +40,8 @@
static unsigned long linux_mem_size;
static int loaded;
static void *real_mode_mem;
+static void *prot_mode_mem;
+static grub_size_t prot_kernel_size;
static void *initrd_mem;
static void *mmap_buf;
static grub_efi_uintn_t real_mode_pages;
@@ -143,6 +145,7 @@ allocate_pages (grub_size_t real_size, g
/* Initialize the memory pointers with NULL for convenience. */
real_mode_mem = 0;
+ prot_mode_mem = 0;
mmap_buf = 0;
/* Read the memory map temporarily, to find free space. */
@@ -205,6 +208,13 @@ allocate_pages (grub_size_t real_size, g
goto fail;
}
+ grub_printf("Trying to allocate %u pages for VMLINUZ\n",
+ (unsigned) prot_mode_pages);
+ prot_mode_mem = grub_efi_allocate_anypages(prot_mode_pages);
+
+ if (!prot_mode_mem)
+ grub_fatal("Cannot allocate pages for VMLINUZ");
+
mmap_buf = grub_efi_allocate_pages (0, mmap_pages);
if (! mmap_buf)
{
@@ -259,6 +269,11 @@ big_linux_boot (void)
grub_fatal ("cannot exit boot services");
/* Note that no boot services are available from here. */
+
+ /* copy vmlinuz image to hdr.code32_start */
+ memcpy ((char *)(unsigned long)(params->hdr.code32_start), (char *)prot_mode_mem,
+ prot_kernel_size);
+ /* copy switch image */
memcpy ((void *) 0x700, switch_image, switch_size);
lh = ¶ms->hdr;
@@ -370,6 +385,7 @@ grub_load_linux (char *kernel, char *arg
real_size = 0x1000 + grub_strlen(arg);
prot_size = grub_file_size () - (setup_sects << SECTOR_BITS) - SECTOR_SIZE;
+ prot_kernel_size = prot_size;
if (! allocate_pages (real_size, prot_size))
goto fail;
@@ -501,7 +517,7 @@ grub_load_linux (char *kernel, char *arg
grub_seek ((setup_sects << SECTOR_BITS) + SECTOR_SIZE);
len = prot_size;
- if (grub_read ((char *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
+ if (grub_read ((char *)prot_mode_mem, len) != len)
grub_printf ("Couldn't read file");
if (errnum == ERR_NONE)