From 384763d7990f769839ca74d6756fbd85580873d4 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 11 Jul 2019 17:17:02 +0200
Subject: [PATCH 04/11] Try to pick better locations for kernel and initrd

- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if
  we're using the "large" code model ; use __UINTPTR_MAX__.
- Get the comparison right to check the address we've allocated.
- Fix the allocation for the command line as well.

*But*, when we did this some systems started failing badly; coudln't
parse partition tables, etc.  What's going on here is the disk controller
is silently failing DMAs to addresses above 4GB, so we're trying to parse
uninitialized (or HW zeroed) ram when looking for the partition table,
etc.

So to limit this, we make grub_malloc() pick addresses below 4GB on
x86_64, but the direct EFI page allocation functions can get addresses
above that.

Additionally, we now try to locate kernel+initrd+cmdline+etc below
0x7fffffff, and if they're too big to fit any memory window there, then
we try a higher address.

Signed-off-by: Peter Jones <pjones@redhat.com>
---
 grub-core/kern/efi/mm.c           |  8 ++++----
 grub-core/loader/i386/efi/linux.c | 25 +++++++++++++++++--------
 include/grub/arm/efi/memory.h     |  1 +
 include/grub/arm64/efi/memory.h   |  1 +
 include/grub/i386/efi/memory.h    |  1 +
 include/grub/ia64/efi/memory.h    |  1 +
 include/grub/x86_64/efi/memory.h  |  4 +++-
 7 files changed, 28 insertions(+), 13 deletions(-)

--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -121,7 +121,7 @@
   grub_efi_boot_services_t *b;
   grub_efi_physical_address_t address = max;
 
-  if (max > 0xffffffff)
+  if (max > GRUB_EFI_MAX_USABLE_ADDRESS)
     return 0;
 
   b = grub_efi_system_table->boot_services;
@@ -481,7 +481,7 @@
     {
       if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
 #if 1
-	  && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS
+	  && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS
 #endif
 	  && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
 	  && desc->num_pages != 0)
@@ -499,9 +499,9 @@
 #if 1
 	  if (BYTES_TO_PAGES (filtered_desc->physical_start)
 	      + filtered_desc->num_pages
-	      > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS))
+	      > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS))
 	    filtered_desc->num_pages
-	      = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)
+	      = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)
 		 - BYTES_TO_PAGES (filtered_desc->physical_start));
 #endif
 
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -27,6 +27,7 @@
 #include <grub/lib/cmdline.h>
 #include <grub/efi/efi.h>
 #include <grub/efi/linux.h>
+#include <grub/cpu/efi/memory.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -102,8 +103,9 @@
       size += ALIGN_UP (grub_file_size (files[i]), 4);
     }
 
-  initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
-
+  initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size));
+  if (!initrd_mem)
+    initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size));
   if (!initrd_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
@@ -187,8 +189,11 @@
       goto fail;
     }
 
-  params = grub_efi_allocate_pages_max (0x3fffffff,
+  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
 					BYTES_TO_PAGES(sizeof(*params)));
+  if (!params)
+    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
+					  BYTES_TO_PAGES(sizeof(*params)));
   if (! params)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
@@ -258,8 +263,11 @@
 #endif
 
   grub_dprintf ("linux", "setting up cmdline\n");
-  linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
-					 BYTES_TO_PAGES(lh->cmdline_size + 1));
+  linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+					      BYTES_TO_PAGES(lh->cmdline_size + 1));
+  if (!linux_cmdline)
+    linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
+						BYTES_TO_PAGES(lh->cmdline_size + 1));
   if (!linux_cmdline)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
@@ -285,11 +293,12 @@
 
   kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
 					   BYTES_TO_PAGES(lh->init_size));
-
   if (!kernel_mem)
-    kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
+    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+					     BYTES_TO_PAGES(lh->init_size));
+  if (!kernel_mem)
+    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
 					     BYTES_TO_PAGES(lh->init_size));
-
   if (!kernel_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
--- a/include/grub/arm/efi/memory.h
+++ b/include/grub/arm/efi/memory.h
@@ -2,5 +2,6 @@
 #include <grub/efi/memory.h>
 
 #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
 
 #endif /* ! GRUB_MEMORY_CPU_HEADER */
--- a/include/grub/arm64/efi/memory.h
+++ b/include/grub/arm64/efi/memory.h
@@ -2,5 +2,6 @@
 #include <grub/efi/memory.h>
 
 #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
 
 #endif /* ! GRUB_MEMORY_CPU_HEADER */
--- a/include/grub/i386/efi/memory.h
+++ b/include/grub/i386/efi/memory.h
@@ -2,5 +2,6 @@
 #include <grub/efi/memory.h>
 
 #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
 
 #endif /* ! GRUB_MEMORY_CPU_HEADER */
--- a/include/grub/ia64/efi/memory.h
+++ b/include/grub/ia64/efi/memory.h
@@ -2,5 +2,6 @@
 #include <grub/efi/memory.h>
 
 #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
 
 #endif /* ! GRUB_MEMORY_CPU_HEADER */
--- a/include/grub/x86_64/efi/memory.h
+++ b/include/grub/x86_64/efi/memory.h
@@ -2,9 +2,11 @@
 #include <grub/efi/memory.h>
 
 #if defined (__code_model_large__)
-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
+#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff
 #else
 #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
 #endif
 
 #endif /* ! GRUB_MEMORY_CPU_HEADER */
