c2f7a5e
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
c2f7a5e
From: Peter Jones <pjones@redhat.com>
e153146
Date: Thu, 11 Jul 2019 14:38:57 +0200
c2f7a5e
Subject: [PATCH] arm/arm64 loader: Better memory allocation and error
c2f7a5e
 messages.
c2f7a5e
c2f7a5e
On mustang, our memory map looks like:
c2f7a5e
c2f7a5e
Type      Physical start  - end             #Pages        Size Attributes
c2f7a5e
reserved  0000004000000000-00000040001fffff 00000200      2MiB UC WC WT WB
c2f7a5e
conv-mem  0000004000200000-0000004393ffffff 00393e00  14654MiB UC WC WT WB
c2f7a5e
ldr-code  0000004394000000-00000043f7ffffff 00064000   1600MiB UC WC WT WB
c2f7a5e
BS-data   00000043f8000000-00000043f801ffff 00000020    128KiB UC WC WT WB
c2f7a5e
conv-mem  00000043f8020000-00000043fa15bfff 0000213c  34032KiB UC WC WT WB
c2f7a5e
ldr-code  00000043fa15c000-00000043fa2a1fff 00000146   1304KiB UC WC WT WB
c2f7a5e
ldr-data  00000043fa2a2000-00000043fa3e8fff 00000147   1308KiB UC WC WT WB
c2f7a5e
conv-mem  00000043fa3e9000-00000043fa3e9fff 00000001      4KiB UC WC WT WB
c2f7a5e
ldr-data  00000043fa3ea000-00000043fa3eafff 00000001      4KiB UC WC WT WB
c2f7a5e
ldr-code  00000043fa3eb000-00000043fa4affff 000000c5    788KiB UC WC WT WB
c2f7a5e
BS-code   00000043fa4b0000-00000043fa59ffff 000000f0    960KiB UC WC WT WB
c2f7a5e
RT-code   00000043fa5a0000-00000043fa5affff 00000010     64KiB RT UC WC WT WB
c2f7a5e
RT-data   00000043fa5b0000-00000043fa5bffff 00000010     64KiB RT UC WC WT WB
c2f7a5e
RT-code   00000043fa5c0000-00000043fa5cffff 00000010     64KiB RT UC WC WT WB
c2f7a5e
ldr-data  00000043fa5d0000-00000043fa5d0fff 00000001      4KiB UC WC WT WB
c2f7a5e
BS-code   00000043fa5d1000-00000043fa5ddfff 0000000d     52KiB UC WC WT WB
c2f7a5e
reserved  00000043fa5de000-00000043fa60ffff 00000032    200KiB UC WC WT WB
c2f7a5e
ACPI-rec  00000043fa610000-00000043fa6affff 000000a0    640KiB UC WC WT WB
c2f7a5e
ACPI-nvs  00000043fa6b0000-00000043fa6bffff 00000010     64KiB UC WC WT WB
c2f7a5e
ACPI-rec  00000043fa6c0000-00000043fa70ffff 00000050    320KiB UC WC WT WB
c2f7a5e
RT-code   00000043fa710000-00000043fa72ffff 00000020    128KiB RT UC WC WT WB
c2f7a5e
RT-data   00000043fa730000-00000043fa78ffff 00000060    384KiB RT UC WC WT WB
c2f7a5e
RT-code   00000043fa790000-00000043fa79ffff 00000010     64KiB RT UC WC WT WB
c2f7a5e
RT-data   00000043fa7a0000-00000043fa99ffff 00000200      2MiB RT UC WC WT WB
c2f7a5e
RT-code   00000043fa9a0000-00000043fa9affff 00000010     64KiB RT UC WC WT WB
c2f7a5e
RT-data   00000043fa9b0000-00000043fa9cffff 00000020    128KiB RT UC WC WT WB
c2f7a5e
BS-code   00000043fa9d0000-00000043fa9d9fff 0000000a     40KiB UC WC WT WB
c2f7a5e
reserved  00000043fa9da000-00000043fa9dbfff 00000002      8KiB UC WC WT WB
c2f7a5e
conv-mem  00000043fa9dc000-00000043fc29dfff 000018c2  25352KiB UC WC WT WB
c2f7a5e
BS-data   00000043fc29e000-00000043fc78afff 000004ed   5044KiB UC WC WT WB
c2f7a5e
conv-mem  00000043fc78b000-00000043fca01fff 00000277   2524KiB UC WC WT WB
c2f7a5e
BS-data   00000043fca02000-00000043fcea3fff 000004a2   4744KiB UC WC WT WB
c2f7a5e
conv-mem  00000043fcea4000-00000043fcea4fff 00000001      4KiB UC WC WT WB
c2f7a5e
BS-data   00000043fcea5000-00000043fd192fff 000002ee   3000KiB UC WC WT WB
c2f7a5e
conv-mem  00000043fd193000-00000043fd2b0fff 0000011e   1144KiB UC WC WT WB
c2f7a5e
BS-data   00000043fd2b1000-00000043ff80ffff 0000255f  38268KiB UC WC WT WB
c2f7a5e
BS-code   00000043ff810000-00000043ff99ffff 00000190   1600KiB UC WC WT WB
c2f7a5e
RT-code   00000043ff9a0000-00000043ff9affff 00000010     64KiB RT UC WC WT WB
c2f7a5e
conv-mem  00000043ff9b0000-00000043ff9bffff 00000010     64KiB UC WC WT WB
c2f7a5e
RT-data   00000043ff9c0000-00000043ff9effff 00000030    192KiB RT UC WC WT WB
c2f7a5e
conv-mem  00000043ff9f0000-00000043ffa05fff 00000016     88KiB UC WC WT WB
c2f7a5e
BS-data   00000043ffa06000-00000043ffffffff 000005fa   6120KiB UC WC WT WB
c2f7a5e
MMIO      0000000010510000-0000000010510fff 00000001      4KiB RT
c2f7a5e
MMIO      0000000010548000-0000000010549fff 00000002      8KiB RT
c2f7a5e
MMIO      0000000017000000-0000000017001fff 00000002      8KiB RT
c2f7a5e
MMIO      000000001c025000-000000001c025fff 00000001      4KiB RT
c2f7a5e
e153146
This patch adds a requirement when we're trying to find the base of ram, that
e153146
the memory we choose is actually /allocatable/ conventional memory, not merely
c2f7a5e
write-combining.  On this machine that means we wind up with an allocation
c2f7a5e
around 0x4392XXXXXX, which is a reasonable address.
c2f7a5e
c2f7a5e
This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it
c2f7a5e
tries to allocate again starting with the same max address it did the first
c2f7a5e
time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any
c2f7a5e
per-platform constraints on its given address are maintained.
c2f7a5e
c2f7a5e
Signed-off-by: Peter Jones <pjones@redhat.com>
c2f7a5e
---
46968b6
 grub-core/kern/efi/mm.c        | 33 +++++++++++++++-----
46968b6
 grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++-----------
46968b6
 2 files changed, 76 insertions(+), 25 deletions(-)
c2f7a5e
c2f7a5e
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
e622855
index f6aef0ef64..85ad4b4494 100644
c2f7a5e
--- a/grub-core/kern/efi/mm.c
c2f7a5e
+++ b/grub-core/kern/efi/mm.c
c2f7a5e
@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
c2f7a5e
 {
c2f7a5e
   grub_efi_status_t status;
c2f7a5e
   grub_efi_boot_services_t *b;
c2f7a5e
+  grub_efi_physical_address_t ret = address;
c2f7a5e
 
c2f7a5e
   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
c2f7a5e
   if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
13985b0
@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
c2f7a5e
     }
c2f7a5e
 
c2f7a5e
   b = grub_efi_system_table->boot_services;
c2f7a5e
-  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
c2f7a5e
+  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret;;
c2f7a5e
   if (status != GRUB_EFI_SUCCESS)
c2f7a5e
     {
7531222
+      grub_dprintf ("efi",
7531222
+		    "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n",
7531222
+		    alloctype, memtype, pages, address, status);
c2f7a5e
       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
c2f7a5e
       return NULL;
c2f7a5e
     }
c2f7a5e
 
c2f7a5e
-  if (address == 0)
c2f7a5e
+  if (ret == 0)
c2f7a5e
     {
c2f7a5e
       /* Uggh, the address 0 was allocated... This is too annoying,
c2f7a5e
 	 so reallocate another one.  */
c2f7a5e
-      address = GRUB_EFI_MAX_USABLE_ADDRESS;
c2f7a5e
-      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
c2f7a5e
+      ret = address;
c2f7a5e
+      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret;;
c2f7a5e
       grub_efi_free_pages (0, pages);
c2f7a5e
       if (status != GRUB_EFI_SUCCESS)
c2f7a5e
 	{
13985b0
@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
c2f7a5e
 	}
c2f7a5e
     }
c2f7a5e
 
c2f7a5e
-  grub_efi_store_alloc (address, pages);
c2f7a5e
+  grub_efi_store_alloc (ret, pages);
c2f7a5e
 
c2f7a5e
-  return (void *) ((grub_addr_t) address);
c2f7a5e
+  return (void *) ((grub_addr_t) ret);
c2f7a5e
 }
c2f7a5e
 
c2f7a5e
 void *
13985b0
@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
e153146
   for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS;
c2f7a5e
        (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size);
c2f7a5e
        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
c2f7a5e
-    if (desc->attribute & GRUB_EFI_MEMORY_WB)
c2f7a5e
-      *base_addr = grub_min (*base_addr, desc->physical_start);
c2f7a5e
+    {
c2f7a5e
+      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY &&
e153146
+          (desc->attribute & GRUB_EFI_MEMORY_WB))
e153146
+        {
e153146
+          *base_addr = grub_min (*base_addr, desc->physical_start);
e153146
+          grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr);
e153146
+        }
c2f7a5e
+      else
e153146
+        {
e153146
+          grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start);
e153146
+        }
c2f7a5e
+    }
c2f7a5e
+
c2f7a5e
+  if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS)
c2f7a5e
+    grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr);
c2f7a5e
 
c2f7a5e
   grub_free(memory_map);
c2f7a5e
 
c2f7a5e
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
e622855
index 04994d5c67..70a0075ec5 100644
c2f7a5e
--- a/grub-core/loader/arm64/linux.c
c2f7a5e
+++ b/grub-core/loader/arm64/linux.c
46968b6
@@ -71,20 +71,25 @@ finalize_params_linux (void)
c2f7a5e
 {
c2f7a5e
   grub_efi_loaded_image_t *loaded_image = NULL;
c2f7a5e
   int node, retval, len;
c2f7a5e
-
c2f7a5e
+  grub_err_t err = GRUB_ERR_NONE;
c2f7a5e
   void *fdt;
c2f7a5e
 
e153146
   fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE);
c2f7a5e
-
c2f7a5e
   if (!fdt)
c2f7a5e
-    goto failure;
c2f7a5e
+    {
c2f7a5e
+      err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT");
c2f7a5e
+      goto failure;
c2f7a5e
+    }
c2f7a5e
 
c2f7a5e
   node = grub_fdt_find_subnode (fdt, 0, "chosen");
c2f7a5e
   if (node < 0)
46968b6
     node = grub_fdt_add_subnode (fdt, 0, "chosen");
c2f7a5e
 
c2f7a5e
   if (node < 1)
c2f7a5e
-    goto failure;
c2f7a5e
+    {
c2f7a5e
+      err = grub_error(grub_errno, "failed to load chosen fdt node.");
c2f7a5e
+      goto failure;
c2f7a5e
+    }
c2f7a5e
 
c2f7a5e
   /* Set initrd info */
c2f7a5e
   if (initrd_start && initrd_end > initrd_start)
46968b6
@@ -95,15 +100,26 @@ finalize_params_linux (void)
c2f7a5e
       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start",
c2f7a5e
 				    initrd_start);
c2f7a5e
       if (retval)
c2f7a5e
-	goto failure;
c2f7a5e
+	{
c2f7a5e
+	  err = grub_error(retval, "Failed to set linux,initrd-start property");
c2f7a5e
+	  goto failure;
c2f7a5e
+	}
c2f7a5e
+
c2f7a5e
       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end",
c2f7a5e
 				    initrd_end);
c2f7a5e
       if (retval)
c2f7a5e
-	goto failure;
c2f7a5e
+	{
c2f7a5e
+	  err = grub_error(retval, "Failed to set linux,initrd-end property");
c2f7a5e
+	  goto failure;
c2f7a5e
+	}
c2f7a5e
     }
c2f7a5e
 
c2f7a5e
-  if (grub_fdt_install() != GRUB_ERR_NONE)
c2f7a5e
-    goto failure;
c2f7a5e
+  retval = grub_fdt_install();
c2f7a5e
+  if (retval != GRUB_ERR_NONE)
c2f7a5e
+    {
c2f7a5e
+      err = grub_error(retval, "Failed to install fdt");
c2f7a5e
+      goto failure;
c2f7a5e
+    }
c2f7a5e
 
c2f7a5e
   grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
e153146
                 fdt);
46968b6
@@ -111,14 +127,20 @@ finalize_params_linux (void)
c2f7a5e
   /* Convert command line to UCS-2 */
c2f7a5e
   loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
c2f7a5e
   if (!loaded_image)
c2f7a5e
-    goto failure;
c2f7a5e
+    {
c2f7a5e
+      err = grub_error(grub_errno, "Failed to install fdt");
c2f7a5e
+      goto failure;
c2f7a5e
+    }
c2f7a5e
 
c2f7a5e
   loaded_image->load_options_size = len =
c2f7a5e
     (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
c2f7a5e
   loaded_image->load_options =
c2f7a5e
     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
c2f7a5e
   if (!loaded_image->load_options)
c2f7a5e
-    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
c2f7a5e
+    {
c2f7a5e
+      err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
c2f7a5e
+      goto failure;
c2f7a5e
+    }
c2f7a5e
 
c2f7a5e
   loaded_image->load_options_size =
c2f7a5e
     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
46968b6
@@ -128,7 +150,7 @@ finalize_params_linux (void)
c2f7a5e
 
c2f7a5e
 failure:
c2f7a5e
   grub_fdt_unload();
c2f7a5e
-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
c2f7a5e
+  return err;
c2f7a5e
 }
c2f7a5e
 
c2f7a5e
 static void
46968b6
@@ -212,16 +234,28 @@ grub_linux_unload (void)
c2f7a5e
 static void *
c2f7a5e
 allocate_initrd_mem (int initrd_pages)
c2f7a5e
 {
c2f7a5e
-  grub_addr_t max_addr;
c2f7a5e
+  grub_addr_t max_addr = 0;
c2f7a5e
+  grub_err_t err;
c2f7a5e
+  void *ret;
c2f7a5e
 
c2f7a5e
-  if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE)
c2f7a5e
-    return NULL;
c2f7a5e
+  err = grub_efi_get_ram_base (&max_addr);
c2f7a5e
+  if (err != GRUB_ERR_NONE)
c2f7a5e
+    {
c2f7a5e
+      grub_error (err, "grub_efi_get_ram_base() failed");
c2f7a5e
+      return NULL;
c2f7a5e
+    }
c2f7a5e
+
c2f7a5e
+  grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n",
c2f7a5e
+		max_addr, INITRD_MAX_ADDRESS_OFFSET);
c2f7a5e
 
c2f7a5e
   max_addr += INITRD_MAX_ADDRESS_OFFSET - 1;
c2f7a5e
+  grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages);
c2f7a5e
 
c2f7a5e
-  return grub_efi_allocate_pages_real (max_addr, initrd_pages,
c2f7a5e
-				       GRUB_EFI_ALLOCATE_MAX_ADDRESS,
c2f7a5e
-				       GRUB_EFI_LOADER_DATA);
c2f7a5e
+  ret = grub_efi_allocate_pages_real (max_addr, initrd_pages,
c2f7a5e
+				      GRUB_EFI_ALLOCATE_MAX_ADDRESS,
c2f7a5e
+				      GRUB_EFI_LOADER_DATA);
c2f7a5e
+  grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret);
c2f7a5e
+  return ret;
c2f7a5e
 }
c2f7a5e
 
c2f7a5e
 static grub_err_t