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