nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0280-efi-make-the-default-arena-most-of-ram.patch

d3c3ab
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
d3c3ab
From: Peter Jones <pjones@redhat.com>
d3c3ab
Date: Fri, 29 Jul 2022 15:57:57 -0400
d3c3ab
Subject: [PATCH] efi: make the default arena most of ram
d3c3ab
d3c3ab
Currently when populating the initial memory arena on EFI systems, we
d3c3ab
count the available regions below GRUB_EFI_MAX_ALLOCATION_ADDRESS from
d3c3ab
the EFI memory map and then allocates one quarter of that for our arena.
d3c3ab
d3c3ab
Because many systems come up without IOMMUs, we currently set
d3c3ab
GRUB_EFI_MAX_ALLOCATION_ADDRESS to 0x7fffffff, i.e. all addresses
d3c3ab
allocated must be below 2G[0].  Due to firmware and other
d3c3ab
considerations, this makes the most memory we can possibly have in our
d3c3ab
arena 512M.
d3c3ab
d3c3ab
Because our EFI loader doesn't get kernel and initrd memory from grub's
d3c3ab
allocator, but rather reserves it directly from UEFI and then simply
d3c3ab
marks those as allocated if they're within grub's arena, it was
d3c3ab
historically possible to have initrds that are larger than 512M, because
d3c3ab
we could use any memory region below 4G, without concern for grub's
d3c3ab
choice of arena size.
d3c3ab
d3c3ab
Unfortunately, when we switched to using the "verifiers" API (and thus
d3c3ab
the file_filter_t API) to do measurement of kernel and initrd, this
d3c3ab
introduced a pattern that allocates the entire file when we call
d3c3ab
grub_file_open(), and buffers it to pass to the filter.  This results in
d3c3ab
needing to have enough space for the initramfs in the grub arena.
d3c3ab
d3c3ab
This is bad.
d3c3ab
d3c3ab
Since it's unlikely you're going to do anything *other* than loading a
d3c3ab
kernel and initramfs that takes much of the available free memory from
d3c3ab
UEFI, this patch introduces a workaround by changing the amount we give
d3c3ab
to the arena be three quarters of the available memory, rather than one
d3c3ab
quarter, thus changing our theoretical initrd limit to 1.5G.  In
d3c3ab
practice, it may still be smaller than that depending on allocation
d3c3ab
fragmentation, but generally it will be most of it.
d3c3ab
d3c3ab
Note that this doesn't fix the underlying flaw, which is that there is
d3c3ab
no safe way to do the validation correctly using the "verifiers" system
d3c3ab
with the current file API without buffering the whole file before
d3c3ab
grub_file_read() is ever called, and thus you can't set an allocation
d3c3ab
policy for the initial buffer of the file at all, so unless we raise the
d3c3ab
allocation limit to >4G, it can't be allocated in the big region.
d3c3ab
d3c3ab
[0] I'm not sure there was a good reason not to pick 4G, but even if we
d3c3ab
    had, at least one common firmware routes the first 2G of physical
d3c3ab
    RAM to 0x0, and any additional memory starting at 0x100000000.
d3c3ab
d3c3ab
Related: rhbz#2112134
d3c3ab
d3c3ab
Signed-off-by: Peter Jones <pjones@redhat.com>
d3c3ab
(cherry picked from commit 005a0aaaad2a00a1fa1e60d94cc4fd5407c22e7d)
d3c3ab
---
d3c3ab
 grub-core/kern/efi/mm.c | 4 ++--
d3c3ab
 1 file changed, 2 insertions(+), 2 deletions(-)
d3c3ab
d3c3ab
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
d3c3ab
index 88364d764c..0288eab361 100644
d3c3ab
--- a/grub-core/kern/efi/mm.c
d3c3ab
+++ b/grub-core/kern/efi/mm.c
d3c3ab
@@ -738,10 +738,10 @@ grub_efi_mm_init (void)
d3c3ab
   filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
d3c3ab
 					       desc_size, memory_map_end);
d3c3ab
 
d3c3ab
-  /* By default, request a quarter of the available memory.  */
d3c3ab
+  /* By default, request three quarters of the available memory.  */
d3c3ab
   total_pages = get_total_pages (filtered_memory_map, desc_size,
d3c3ab
 				 filtered_memory_map_end);
d3c3ab
-  required_pages = (total_pages >> 2);
d3c3ab
+  required_pages = (total_pages >> 1) + (total_pages >> 2);
d3c3ab
   if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
d3c3ab
     required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
d3c3ab
   else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))