grub2/0162-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
Javier Martinez Canillas 7e98da058f
Cleanup our patchset to reduce the number of patches
This change reorganizes and cleanups our patches to reduce the patch number
from 314 patches to 187. That's achieved by dropping patches that are later
reverted and squashing fixes for earlier patches that introduced features.

There are no code changes and the diff with upstream is the same before and
after the cleanup. Having fewer patches makes easier to manage the patchset
and also will ease to rebase them on top of the latest grub-2.04 release.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
2019-07-16 12:30:06 +02:00

172 lines
6.2 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Wed, 12 Sep 2018 16:12:27 -0400
Subject: [PATCH] x86-efi: Allow initrd+params+cmdline allocations above 4GB.
This enables everything except the kernel itself to be above 4GB.
Putting the kernel up there still doesn't work, because of the way
params->code32_start is used.
Signed-off-by: Peter Jones <pjones@redhat.com>
---
grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++++++++++----
include/grub/i386/linux.h | 6 +++-
2 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 1811f4b3d56..65d1b5cc034 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -53,13 +53,22 @@ struct allocation_choice {
grub_efi_allocate_type_t alloc_type;
};
-static struct allocation_choice max_addresses[] =
+static struct allocation_choice max_addresses[4] =
{
+ /* the kernel overrides this one with pref_address and
+ * GRUB_EFI_ALLOCATE_ADDRESS */
{ GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+ /* this one is always below 4GB, which we still *prefer* even if the flag
+ * is set. */
{ GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+ /* If the flag in params is set, this one gets changed to be above 4GB. */
{ GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
{ 0, 0 }
};
+static struct allocation_choice saved_addresses[4];
+
+#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses))
+#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses))
static inline void
kernel_free(void *addr, grub_efi_uintn_t size)
@@ -81,6 +90,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
grub_uint64_t max = max_addresses[i].addr;
grub_efi_uintn_t pages;
+ /*
+ * When we're *not* loading the kernel, or >4GB allocations aren't
+ * supported, these entries are basically all the same, so don't re-try
+ * the same parameters.
+ */
if (max == prev_max)
continue;
@@ -169,6 +183,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
return bufpos;
}
+#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull))
+#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
+
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
@@ -209,8 +226,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
- params->ramdisk_size = size;
- params->ramdisk_image = initrd_mem;
+ params->ramdisk_size = LOW_U32(size);
+ params->ramdisk_image = LOW_U32(initrd_mem);
+#if defined(__x86_64__)
+ params->ext_ramdisk_size = HIGH_U32(size);
+ params->ext_ramdisk_image = HIGH_U32(initrd_mem);
+#endif
ptr = initrd_mem;
@@ -345,6 +366,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
#endif
+#if defined(__x86_64__)
+ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
+ {
+ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
+ max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
+ }
+ else
+ {
+ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n");
+ }
+#endif
+
params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
if (!params)
goto fail;
@@ -378,21 +411,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
- linux_cmdline);
- lh->cmd_line_ptr = linux_cmdline;
+ LOW_U32(linux_cmdline));
+ lh->cmd_line_ptr = LOW_U32(linux_cmdline);
+#if defined(__x86_64__)
+ if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
+ {
+ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n",
+ HIGH_U32(linux_cmdline));
+ params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline);
+ }
+#endif
handover_offset = lh->handover_offset;
grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset);
start = (lh->setup_sects + 1) * 512;
+ /*
+ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being
+ * 32-bit and getting called unconditionally in head_64.S from either entry
+ * point.
+ *
+ * so nerf that out here...
+ */
+ save_addresses();
grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
{
max_addresses[0].addr = lh->pref_address;
max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
}
+ max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+ max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
+ restore_addresses();
if (!kernel_mem)
goto fail;
grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
@@ -401,8 +453,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
loaded = 1;
- grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem);
- lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
+ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
+ LOW_U32(kernel_mem));
+ lh->code32_start = LOW_U32(kernel_mem);
grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
index 8474a857ed2..a4b37dcced5 100644
--- a/include/grub/i386/linux.h
+++ b/include/grub/i386/linux.h
@@ -230,7 +230,11 @@ struct linux_kernel_params
grub_uint32_t ofw_cif_handler; /* b8 */
grub_uint32_t ofw_idt; /* bc */
- grub_uint8_t padding7[0x1b8 - 0xc0];
+ grub_uint32_t ext_ramdisk_image; /* 0xc0 */
+ grub_uint32_t ext_ramdisk_size; /* 0xc4 */
+ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */
+
+ grub_uint8_t padding7[0x1b8 - 0xcc];
union
{