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 = &params->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)
openSUSE Build Service is sponsored by