7e98da058f
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>
172 lines
6.2 KiB
Diff
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
|
|
{
|