nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0498-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch

23a3f0
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
23a3f0
From: Peter Jones <pjones@redhat.com>
23a3f0
Date: Wed, 12 Sep 2018 16:03:55 -0400
23a3f0
Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff
23a3f0
23a3f0
This helps enable allocations above 4GB.
23a3f0
23a3f0
Signed-off-by: Peter Jones <pjones@redhat.com>
23a3f0
(cherry picked from commit cfea4ae780f8860d472cd2d5a9765ec2fe2adc83)
23a3f0
---
23a3f0
 grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++-----------------
23a3f0
 1 file changed, 94 insertions(+), 73 deletions(-)
23a3f0
23a3f0
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
23a3f0
index c9650561f..5eed2014c 100644
23a3f0
--- a/grub-core/loader/i386/efi/linux.c
23a3f0
+++ b/grub-core/loader/i386/efi/linux.c
23a3f0
@@ -49,6 +49,65 @@ static char *linux_cmdline;
23a3f0
 
23a3f0
 #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
23a3f0
 
23a3f0
+struct allocation_choice {
23a3f0
+    grub_efi_physical_address_t addr;
23a3f0
+    grub_efi_allocate_type_t alloc_type;
23a3f0
+};
23a3f0
+
23a3f0
+static struct allocation_choice max_addresses[] =
23a3f0
+  {
23a3f0
+    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
23a3f0
+    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
23a3f0
+    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
23a3f0
+    { 0, 0 }
23a3f0
+  };
23a3f0
+
23a3f0
+static inline void
23a3f0
+kernel_free(void *addr, grub_efi_uintn_t size)
23a3f0
+{
23a3f0
+  if (addr && size)
23a3f0
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr,
23a3f0
+			 BYTES_TO_PAGES(size));
23a3f0
+}
23a3f0
+
23a3f0
+static void *
23a3f0
+kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
23a3f0
+{
23a3f0
+  void *addr = 0;
23a3f0
+  unsigned int i;
23a3f0
+  grub_efi_physical_address_t prev_max = 0;
23a3f0
+
23a3f0
+  for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++)
23a3f0
+    {
23a3f0
+      grub_uint64_t max = max_addresses[i].addr;
23a3f0
+      grub_efi_uintn_t pages;
23a3f0
+
23a3f0
+      if (max == prev_max)
23a3f0
+	continue;
23a3f0
+
23a3f0
+      pages = BYTES_TO_PAGES(size);
23a3f0
+      grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
23a3f0
+		    pages, (void *)max);
23a3f0
+
23a3f0
+      prev_max = max;
23a3f0
+      addr = grub_efi_allocate_pages_real (max, pages,
23a3f0
+					   max_addresses[i].alloc_type,
23a3f0
+					   GRUB_EFI_LOADER_DATA);
23a3f0
+      if (addr)
23a3f0
+	grub_dprintf ("linux", "Allocated at %p\n", addr);
23a3f0
+    }
23a3f0
+
23a3f0
+  while (grub_error_pop ())
23a3f0
+    {
23a3f0
+      ;
23a3f0
+    }
23a3f0
+
23a3f0
+  if (addr == NULL)
23a3f0
+    grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg);
23a3f0
+
23a3f0
+  return addr;
23a3f0
+}
23a3f0
+
23a3f0
 static grub_err_t
23a3f0
 grub_linuxefi_boot (void)
23a3f0
 {
23a3f0
@@ -64,19 +123,12 @@ grub_linuxefi_unload (void)
23a3f0
 {
23a3f0
   grub_dl_unref (my_mod);
23a3f0
   loaded = 0;
23a3f0
-  if (initrd_mem)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
23a3f0
-			 BYTES_TO_PAGES(params->ramdisk_size));
23a3f0
-  if (linux_cmdline)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
23a3f0
-			 linux_cmdline,
23a3f0
-			 BYTES_TO_PAGES(params->cmdline_size + 1));
23a3f0
-  if (kernel_mem)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
23a3f0
-			 BYTES_TO_PAGES(kernel_size));
23a3f0
-  if (params)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
23a3f0
-			 BYTES_TO_PAGES(16384));
23a3f0
+
23a3f0
+  kernel_free(initrd_mem, params->ramdisk_size);
23a3f0
+  kernel_free(linux_cmdline, params->cmdline_size + 1);
23a3f0
+  kernel_free(kernel_mem, kernel_size);
23a3f0
+  kernel_free(params, sizeof(*params));
23a3f0
+
23a3f0
   return GRUB_ERR_NONE;
23a3f0
 }
23a3f0
 
23a3f0
@@ -157,19 +209,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
23a3f0
 	}
23a3f0
     }
23a3f0
 
23a3f0
-  initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size));
23a3f0
-  if (!initrd_mem)
23a3f0
-    initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size));
23a3f0
-  if (!initrd_mem)
23a3f0
-    {
23a3f0
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
23a3f0
-      goto fail;
23a3f0
-    }
23a3f0
-
23a3f0
-  grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
23a3f0
+  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
23a3f0
+  if (initrd_mem == NULL)
23a3f0
+    goto fail;
23a3f0
+  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
23a3f0
 
23a3f0
   params->ramdisk_size = size;
23a3f0
-  params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
23a3f0
+  params->ramdisk_image = initrd_mem;
23a3f0
 
23a3f0
   ptr = initrd_mem;
23a3f0
 
23a3f0
@@ -230,7 +276,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
23a3f0
   filelen = grub_file_size (file);
23a3f0
 
23a3f0
   kernel = grub_malloc(filelen);
23a3f0
-
23a3f0
   if (!kernel)
23a3f0
     {
23a3f0
       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
23a3f0
@@ -289,7 +334,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
23a3f0
       goto fail;
23a3f0
     }
23a3f0
 
23a3f0
-#if defined(__x86_64__) || defined(__aarch64__)
23a3f0
+#if defined(__x86_64__)
23a3f0
   grub_dprintf ("linux", "checking lh->xloadflags\n");
23a3f0
   if (!(lh->xloadflags & LINUX_XLF_KERNEL_64))
23a3f0
     {
23a3f0
@@ -308,17 +353,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
23a3f0
     }
23a3f0
 #endif
23a3f0
 
23a3f0
-  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
23a3f0
-					BYTES_TO_PAGES(sizeof(*params)));
23a3f0
+  params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
23a3f0
   if (!params)
23a3f0
-    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
23a3f0
-					  BYTES_TO_PAGES(sizeof(*params)));
23a3f0
-  if (! params)
23a3f0
-    {
23a3f0
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
23a3f0
-      goto fail;
23a3f0
-    }
23a3f0
-
23a3f0
+    goto fail;
23a3f0
   grub_dprintf ("linux", "params = %p\n", params);
23a3f0
 
23a3f0
   grub_memset (params, 0, sizeof(*params));
23a3f0
@@ -337,19 +374,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
23a3f0
   grub_dprintf ("linux", "new lh is at %p\n", lh);
23a3f0
 
23a3f0
   grub_dprintf ("linux", "setting up cmdline\n");
23a3f0
-  linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
23a3f0
-					      BYTES_TO_PAGES(lh->cmdline_size + 1));
23a3f0
+  linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
23a3f0
   if (!linux_cmdline)
23a3f0
-    linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
23a3f0
-						BYTES_TO_PAGES(lh->cmdline_size + 1));
23a3f0
-  if (!linux_cmdline)
23a3f0
-    {
23a3f0
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
23a3f0
-      goto fail;
23a3f0
-    }
23a3f0
-
23a3f0
-  grub_dprintf ("linux", "linux_cmdline = %lx\n",
23a3f0
-		(unsigned long)linux_cmdline);
23a3f0
+    goto fail;
23a3f0
+  grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
23a3f0
 
23a3f0
   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
23a3f0
   grub_create_loader_cmdline (argc, argv,
23a3f0
@@ -358,27 +386,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
23a3f0
 			      GRUB_VERIFY_KERNEL_CMDLINE);
23a3f0
 
23a3f0
   grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
23a3f0
-  grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
23a3f0
-  lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
23a3f0
+  grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
23a3f0
+		linux_cmdline);
23a3f0
+  lh->cmd_line_ptr = linux_cmdline;
23a3f0
 
23a3f0
   handover_offset = lh->handover_offset;
23a3f0
-  grub_dprintf("linux", "handover_offset: %08x\n", handover_offset);
23a3f0
+  grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset);
23a3f0
 
23a3f0
   start = (lh->setup_sects + 1) * 512;
23a3f0
 
23a3f0
-  kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
23a3f0
-					   BYTES_TO_PAGES(lh->init_size));
23a3f0
-  if (!kernel_mem)
23a3f0
-    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
23a3f0
-					     BYTES_TO_PAGES(lh->init_size));
23a3f0
-  if (!kernel_mem)
23a3f0
-    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
23a3f0
-					     BYTES_TO_PAGES(lh->init_size));
23a3f0
-  if (!kernel_mem)
23a3f0
+  grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
23a3f0
+  if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
23a3f0
     {
23a3f0
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
23a3f0
-      goto fail;
23a3f0
+      max_addresses[0].addr = lh->pref_address;
23a3f0
+      max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
23a3f0
     }
23a3f0
+  kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
23a3f0
+  if (!kernel_mem)
23a3f0
+    goto fail;
23a3f0
   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
23a3f0
 
23a3f0
   grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
23a3f0
@@ -413,18 +438,14 @@ fail:
23a3f0
       loaded = 0;
23a3f0
     }
23a3f0
 
23a3f0
-  if (linux_cmdline && lh && !loaded)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
23a3f0
-			 linux_cmdline,
23a3f0
-			 BYTES_TO_PAGES(lh->cmdline_size + 1));
23a3f0
+  if (!loaded)
23a3f0
+    {
23a3f0
+      if (lh)
23a3f0
+	kernel_free (linux_cmdline, lh->cmdline_size + 1);
23a3f0
 
23a3f0
-  if (kernel_mem && !loaded)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
23a3f0
-			 BYTES_TO_PAGES(kernel_size));
23a3f0
-
23a3f0
-  if (params && !loaded)
23a3f0
-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
23a3f0
-			 BYTES_TO_PAGES(16384));
23a3f0
+      kernel_free (kernel_mem, kernel_size);
23a3f0
+      kernel_free (params, sizeof(*params));
23a3f0
+    }
23a3f0
 
23a3f0
   return grub_errno;
23a3f0
 }