|
|
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))
|