From 433335e50ce6d8b6500902e432c66ab560546bef Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Wed, 1 Feb 2023 19:51:45 +0000 Subject: [PATCH] Pull in allocator fixes from upstream Resolves: #2156419 Signed-off-by: Robbie Harwood --- ...i-make-the-default-arena-most-of-ram.patch | 74 ------- ...ed-array-positions-for-our-allocatio.patch | 0 ...tion-policy-for-kernel-vs-initrd-mem.patch | 0 ...-initrd-within-the-bounds-expressed-.patch | 0 ...ER_-CODE-DATA-for-kernel-and-initrd-.patch | 0 ...e-etc-kernel-cmdline-during-mkconfig.patch | 0 ...5-implement-vec5-for-cas-negotiation.patch | 0 ...sh-don-t-dup-rhgb-quiet-check-mtimes.patch | 0 ...=> 0287-squish-give-up-on-rhgb-quiet.patch | 0 ...write-etc-kernel-cmdline-if-writable.patch | 0 ...ncorrect-array-size-in-kernel-alloca.patch | 0 ...i-tpm-Refine-the-status-of-log-event.patch | 0 ...-Use-grub_strcpy-instead-of-grub_mem.patch | 0 ...-EFI_CC_MEASUREMENT_PROTOCOL-support.patch | 0 ...hs-exceeds-font-max_glyph_width-or-f.patch | 0 ...erflow-in-grub_font_get_glyph_intern.patch | 0 ...-integer-overflows-in-grub_font_cons.patch | 0 ...0296-font-Remove-grub_font_dup_glyph.patch | 0 ...nteger-overflow-in-ensure_comb_space.patch | 0 ...nt-Fix-integer-overflow-in-BMP-index.patch | 0 ...-underflow-in-binary-search-of-char-.patch | 0 ...b-Enforce-verification-of-font-files.patch | 0 ... => 0301-fbutil-Fix-integer-overflow.patch | 0 ...ix-an-integer-underflow-in-blit_comb.patch | 0 ..._font_blit_glyph-and-grub_font_blit_.patch | 0 ...l_font-to-glyphs-in-ascii_font_glyph.patch | 0 ...ix-an-integer-overflow-in-grub_unico.patch | 0 ...> 0306-Correction-in-vector-5-values.patch | 0 ...07-ppc64le-signed-boot-media-changes.patch | 0 0308-mm-Clarify-grub_real_malloc.patch | 184 ++++++++++++++++ ...loc-Make-small-allocs-comment-match-.patch | 33 +++ 0310-mm-Document-grub_free.patch | 121 +++++++++++ 0311-mm-Document-grub_mm_init_region.patch | 74 +++++++ ...-internal-memory-management-structur.patch | 79 +++++++ ...e-preserve-header-vs-region-alignmen.patch | 57 +++++ ...-region-merge-with-region-after-as-w.patch | 204 ++++++++++++++++++ ...-Debug-support-for-region-operations.patch | 72 +++++++ ...p-unused-unloading-of-modules-on-OOM.patch | 81 +++++++ ...ally-requesting-additional-memory-re.patch | 131 +++++++++++ ...ys-request-a-fixed-number-of-pages-o.patch | 104 +++++++++ ...tract-function-to-add-memory-regions.patch | 86 ++++++++ ...ss-up-errors-from-add_memory_regions.patch | 88 ++++++++ ...-Implement-runtime-addition-of-pages.patch | 76 +++++++ ...-default-memory-allocation-to-32-MiB.patch | 32 +++ ...e-disk-caches-last-when-out-of-memor.patch | 58 +++++ grub.patches | 73 ++++--- grub2.spec | 6 +- 47 files changed, 1529 insertions(+), 104 deletions(-) delete mode 100644 0280-efi-make-the-default-arena-most-of-ram.patch rename 0281-efi-use-enumerated-array-positions-for-our-allocatio.patch => 0280-efi-use-enumerated-array-positions-for-our-allocatio.patch (100%) rename 0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch => 0281-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch (100%) rename 0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch => 0282-efi-allocate-the-initrd-within-the-bounds-expressed-.patch (100%) rename 0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch => 0283-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch (100%) rename 0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch => 0284-BLS-create-etc-kernel-cmdline-during-mkconfig.patch (100%) rename 0286-ieee1275-implement-vec5-for-cas-negotiation.patch => 0285-ieee1275-implement-vec5-for-cas-negotiation.patch (100%) rename 0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch => 0286-squish-don-t-dup-rhgb-quiet-check-mtimes.patch (100%) rename 0288-squish-give-up-on-rhgb-quiet.patch => 0287-squish-give-up-on-rhgb-quiet.patch (100%) rename 0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch => 0288-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch (100%) rename 0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch => 0289-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch (100%) rename 0291-commands-efi-tpm-Refine-the-status-of-log-event.patch => 0290-commands-efi-tpm-Refine-the-status-of-log-event.patch (100%) rename 0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch => 0291-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch (100%) rename 0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch => 0292-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch (100%) rename 0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch => 0293-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch (100%) rename 0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch => 0294-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch (100%) rename 0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch => 0295-font-Fix-several-integer-overflows-in-grub_font_cons.patch (100%) rename 0297-font-Remove-grub_font_dup_glyph.patch => 0296-font-Remove-grub_font_dup_glyph.patch (100%) rename 0298-font-Fix-integer-overflow-in-ensure_comb_space.patch => 0297-font-Fix-integer-overflow-in-ensure_comb_space.patch (100%) rename 0299-font-Fix-integer-overflow-in-BMP-index.patch => 0298-font-Fix-integer-overflow-in-BMP-index.patch (100%) rename 0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch => 0299-font-Fix-integer-underflow-in-binary-search-of-char-.patch (100%) rename 0301-kern-efi-sb-Enforce-verification-of-font-files.patch => 0300-kern-efi-sb-Enforce-verification-of-font-files.patch (100%) rename 0302-fbutil-Fix-integer-overflow.patch => 0301-fbutil-Fix-integer-overflow.patch (100%) rename 0303-font-Fix-an-integer-underflow-in-blit_comb.patch => 0302-font-Fix-an-integer-underflow-in-blit_comb.patch (100%) rename 0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch => 0303-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch (100%) rename 0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch => 0304-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch (100%) rename 0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch => 0305-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch (100%) rename 0307-Correction-in-vector-5-values.patch => 0306-Correction-in-vector-5-values.patch (100%) rename 0308-ppc64le-signed-boot-media-changes.patch => 0307-ppc64le-signed-boot-media-changes.patch (100%) create mode 100644 0308-mm-Clarify-grub_real_malloc.patch create mode 100644 0309-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch create mode 100644 0310-mm-Document-grub_free.patch create mode 100644 0311-mm-Document-grub_mm_init_region.patch create mode 100644 0312-mm-Document-GRUB-internal-memory-management-structur.patch create mode 100644 0313-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch create mode 100644 0314-mm-When-adding-a-region-merge-with-region-after-as-w.patch create mode 100644 0315-mm-Debug-support-for-region-operations.patch create mode 100644 0316-mm-Drop-unused-unloading-of-modules-on-OOM.patch create mode 100644 0317-mm-Allow-dynamically-requesting-additional-memory-re.patch create mode 100644 0318-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch create mode 100644 0319-kern-efi-mm-Extract-function-to-add-memory-regions.patch create mode 100644 0320-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch create mode 100644 0321-kern-efi-mm-Implement-runtime-addition-of-pages.patch create mode 100644 0322-efi-Increase-default-memory-allocation-to-32-MiB.patch create mode 100644 0323-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch diff --git a/0280-efi-make-the-default-arena-most-of-ram.patch b/0280-efi-make-the-default-arena-most-of-ram.patch deleted file mode 100644 index 6821cde..0000000 --- a/0280-efi-make-the-default-arena-most-of-ram.patch +++ /dev/null @@ -1,74 +0,0 @@ -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)) diff --git a/0281-efi-use-enumerated-array-positions-for-our-allocatio.patch b/0280-efi-use-enumerated-array-positions-for-our-allocatio.patch similarity index 100% rename from 0281-efi-use-enumerated-array-positions-for-our-allocatio.patch rename to 0280-efi-use-enumerated-array-positions-for-our-allocatio.patch diff --git a/0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch b/0281-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch similarity index 100% rename from 0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch rename to 0281-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch diff --git a/0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch b/0282-efi-allocate-the-initrd-within-the-bounds-expressed-.patch similarity index 100% rename from 0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch rename to 0282-efi-allocate-the-initrd-within-the-bounds-expressed-.patch diff --git a/0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch b/0283-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch similarity index 100% rename from 0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch rename to 0283-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch diff --git a/0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch b/0284-BLS-create-etc-kernel-cmdline-during-mkconfig.patch similarity index 100% rename from 0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch rename to 0284-BLS-create-etc-kernel-cmdline-during-mkconfig.patch diff --git a/0286-ieee1275-implement-vec5-for-cas-negotiation.patch b/0285-ieee1275-implement-vec5-for-cas-negotiation.patch similarity index 100% rename from 0286-ieee1275-implement-vec5-for-cas-negotiation.patch rename to 0285-ieee1275-implement-vec5-for-cas-negotiation.patch diff --git a/0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch b/0286-squish-don-t-dup-rhgb-quiet-check-mtimes.patch similarity index 100% rename from 0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch rename to 0286-squish-don-t-dup-rhgb-quiet-check-mtimes.patch diff --git a/0288-squish-give-up-on-rhgb-quiet.patch b/0287-squish-give-up-on-rhgb-quiet.patch similarity index 100% rename from 0288-squish-give-up-on-rhgb-quiet.patch rename to 0287-squish-give-up-on-rhgb-quiet.patch diff --git a/0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch b/0288-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch similarity index 100% rename from 0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch rename to 0288-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch diff --git a/0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch b/0289-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch similarity index 100% rename from 0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch rename to 0289-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch diff --git a/0291-commands-efi-tpm-Refine-the-status-of-log-event.patch b/0290-commands-efi-tpm-Refine-the-status-of-log-event.patch similarity index 100% rename from 0291-commands-efi-tpm-Refine-the-status-of-log-event.patch rename to 0290-commands-efi-tpm-Refine-the-status-of-log-event.patch diff --git a/0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/0291-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch similarity index 100% rename from 0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch rename to 0291-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch diff --git a/0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/0292-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch similarity index 100% rename from 0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch rename to 0292-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch diff --git a/0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/0293-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch similarity index 100% rename from 0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch rename to 0293-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch diff --git a/0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/0294-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch similarity index 100% rename from 0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch rename to 0294-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch diff --git a/0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/0295-font-Fix-several-integer-overflows-in-grub_font_cons.patch similarity index 100% rename from 0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch rename to 0295-font-Fix-several-integer-overflows-in-grub_font_cons.patch diff --git a/0297-font-Remove-grub_font_dup_glyph.patch b/0296-font-Remove-grub_font_dup_glyph.patch similarity index 100% rename from 0297-font-Remove-grub_font_dup_glyph.patch rename to 0296-font-Remove-grub_font_dup_glyph.patch diff --git a/0298-font-Fix-integer-overflow-in-ensure_comb_space.patch b/0297-font-Fix-integer-overflow-in-ensure_comb_space.patch similarity index 100% rename from 0298-font-Fix-integer-overflow-in-ensure_comb_space.patch rename to 0297-font-Fix-integer-overflow-in-ensure_comb_space.patch diff --git a/0299-font-Fix-integer-overflow-in-BMP-index.patch b/0298-font-Fix-integer-overflow-in-BMP-index.patch similarity index 100% rename from 0299-font-Fix-integer-overflow-in-BMP-index.patch rename to 0298-font-Fix-integer-overflow-in-BMP-index.patch diff --git a/0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/0299-font-Fix-integer-underflow-in-binary-search-of-char-.patch similarity index 100% rename from 0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch rename to 0299-font-Fix-integer-underflow-in-binary-search-of-char-.patch diff --git a/0301-kern-efi-sb-Enforce-verification-of-font-files.patch b/0300-kern-efi-sb-Enforce-verification-of-font-files.patch similarity index 100% rename from 0301-kern-efi-sb-Enforce-verification-of-font-files.patch rename to 0300-kern-efi-sb-Enforce-verification-of-font-files.patch diff --git a/0302-fbutil-Fix-integer-overflow.patch b/0301-fbutil-Fix-integer-overflow.patch similarity index 100% rename from 0302-fbutil-Fix-integer-overflow.patch rename to 0301-fbutil-Fix-integer-overflow.patch diff --git a/0303-font-Fix-an-integer-underflow-in-blit_comb.patch b/0302-font-Fix-an-integer-underflow-in-blit_comb.patch similarity index 100% rename from 0303-font-Fix-an-integer-underflow-in-blit_comb.patch rename to 0302-font-Fix-an-integer-underflow-in-blit_comb.patch diff --git a/0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/0303-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch similarity index 100% rename from 0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch rename to 0303-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch diff --git a/0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/0304-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch similarity index 100% rename from 0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch rename to 0304-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch diff --git a/0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/0305-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch similarity index 100% rename from 0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch rename to 0305-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch diff --git a/0307-Correction-in-vector-5-values.patch b/0306-Correction-in-vector-5-values.patch similarity index 100% rename from 0307-Correction-in-vector-5-values.patch rename to 0306-Correction-in-vector-5-values.patch diff --git a/0308-ppc64le-signed-boot-media-changes.patch b/0307-ppc64le-signed-boot-media-changes.patch similarity index 100% rename from 0308-ppc64le-signed-boot-media-changes.patch rename to 0307-ppc64le-signed-boot-media-changes.patch diff --git a/0308-mm-Clarify-grub_real_malloc.patch b/0308-mm-Clarify-grub_real_malloc.patch new file mode 100644 index 0000000..8bbe52f --- /dev/null +++ b/0308-mm-Clarify-grub_real_malloc.patch @@ -0,0 +1,184 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:46 +1100 +Subject: [PATCH] mm: Clarify grub_real_malloc() + +When iterating through the singly linked list of free blocks, +grub_real_malloc() uses p and q for the current and previous blocks +respectively. This isn't super clear, so swap to using prev and cur. + +This makes another quirk more obvious. The comment at the top of +grub_real_malloc() might lead you to believe that the function will +allocate from *first if there is space in that block. + +It actually doesn't do that, and it can't do that with the current +data structures. If we used up all of *first, we would need to change +the ->next of the previous block to point to *first->next, but we +can't do that because it's a singly linked list and we don't have +access to *first's previous block. + +What grub_real_malloc() actually does is set *first to the initial +previous block, and *first->next is the block we try to allocate +from. That allows us to keep all the data structures consistent. + +Document that. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 246ad6a44c281bb13486ddea0a26bb661db73106) +(cherry picked from commit b590e0181a94b3d48ca0c537565c946fad8e6a4f) +--- + grub-core/kern/mm.c | 76 +++++++++++++++++++++++++++++------------------------ + 1 file changed, 41 insertions(+), 35 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index d8c8377578..fb20e93acf 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -178,13 +178,20 @@ grub_mm_init_region (void *addr, grub_size_t size) + } + + /* Allocate the number of units N with the alignment ALIGN from the ring +- buffer starting from *FIRST. ALIGN must be a power of two. Both N and +- ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful, +- otherwise return NULL. */ ++ * buffer given in *FIRST. ALIGN must be a power of two. Both N and ++ * ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful, ++ * otherwise return NULL. ++ * ++ * Note: because in certain circumstances we need to adjust the ->next ++ * pointer of the previous block, we iterate over the singly linked ++ * list with the pair (prev, cur). *FIRST is our initial previous, and ++ * *FIRST->next is our initial current pointer. So we will actually ++ * allocate from *FIRST->next first and *FIRST itself last. ++ */ + static void * + grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + { +- grub_mm_header_t p, q; ++ grub_mm_header_t cur, prev; + + /* When everything is allocated side effect is that *first will have alloc + magic marked, meaning that there is no room in this region. */ +@@ -192,24 +199,24 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + return 0; + + /* Try to search free slot for allocation in this memory region. */ +- for (q = *first, p = q->next; ; q = p, p = p->next) ++ for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next) + { + grub_off_t extra; + +- extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1); ++ extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1); + if (extra) + extra = align - extra; + +- if (! p) ++ if (! cur) + grub_fatal ("null in the ring"); + +- if (p->magic != GRUB_MM_FREE_MAGIC) +- grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic); ++ if (cur->magic != GRUB_MM_FREE_MAGIC) ++ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic); + +- if (p->size >= n + extra) ++ if (cur->size >= n + extra) + { +- extra += (p->size - extra - n) & (~(align - 1)); +- if (extra == 0 && p->size == n) ++ extra += (cur->size - extra - n) & (~(align - 1)); ++ if (extra == 0 && cur->size == n) + { + /* There is no special alignment requirement and memory block + is complete match. +@@ -222,9 +229,9 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + | alloc, size=n | | + +---------------+ v + */ +- q->next = p->next; ++ prev->next = cur->next; + } +- else if (align == 1 || p->size == n + extra) ++ else if (align == 1 || cur->size == n + extra) + { + /* There might be alignment requirement, when taking it into + account memory block fits in. +@@ -241,23 +248,22 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + | alloc, size=n | | + +---------------+ v + */ +- +- p->size -= n; +- p += p->size; ++ cur->size -= n; ++ cur += cur->size; + } + else if (extra == 0) + { + grub_mm_header_t r; + +- r = p + extra + n; ++ r = cur + extra + n; + r->magic = GRUB_MM_FREE_MAGIC; +- r->size = p->size - extra - n; +- r->next = p->next; +- q->next = r; ++ r->size = cur->size - extra - n; ++ r->next = cur->next; ++ prev->next = r; + +- if (q == p) ++ if (prev == cur) + { +- q = r; ++ prev = r; + r->next = r; + } + } +@@ -284,32 +290,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + */ + grub_mm_header_t r; + +- r = p + extra + n; ++ r = cur + extra + n; + r->magic = GRUB_MM_FREE_MAGIC; +- r->size = p->size - extra - n; +- r->next = p; ++ r->size = cur->size - extra - n; ++ r->next = cur; + +- p->size = extra; +- q->next = r; +- p += extra; ++ cur->size = extra; ++ prev->next = r; ++ cur += extra; + } + +- p->magic = GRUB_MM_ALLOC_MAGIC; +- p->size = n; ++ cur->magic = GRUB_MM_ALLOC_MAGIC; ++ cur->size = n; + + /* Mark find as a start marker for next allocation to fasten it. + This will have side effect of fragmenting memory as small + pieces before this will be un-used. */ + /* So do it only for chunks under 64K. */ + if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2) +- || *first == p) +- *first = q; ++ || *first == cur) ++ *first = prev; + +- return p + 1; ++ return cur + 1; + } + + /* Search was completed without result. */ +- if (p == *first) ++ if (cur == *first) + break; + } + diff --git a/0309-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch b/0309-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch new file mode 100644 index 0000000..64a686c --- /dev/null +++ b/0309-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:47 +1100 +Subject: [PATCH] mm: grub_real_malloc(): Make small allocs comment match code + +Small allocations move the region's *first pointer. The comment +says that this happens for allocations under 64K. The code says +it's for allocations under 32K. Commit 45bf8b3a7549 changed the +code intentionally: make the comment match. + +Fixes: 45bf8b3a7549 (* grub-core/kern/mm.c (grub_real_malloc): Decrease cut-off of moving the) + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a847895a8d000bdf27ad4d4326f883a0eed769ca) +(cherry picked from commit 16f329218ced9302554bde95084e6a2ad308733b) +--- + grub-core/kern/mm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index fb20e93acf..db7e0b2a5b 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -306,7 +306,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + /* Mark find as a start marker for next allocation to fasten it. + This will have side effect of fragmenting memory as small + pieces before this will be un-used. */ +- /* So do it only for chunks under 64K. */ ++ /* So do it only for chunks under 32K. */ + if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2) + || *first == cur) + *first = prev; diff --git a/0310-mm-Document-grub_free.patch b/0310-mm-Document-grub_free.patch new file mode 100644 index 0000000..238f410 --- /dev/null +++ b/0310-mm-Document-grub_free.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:48 +1100 +Subject: [PATCH] mm: Document grub_free() + +The grub_free() possesses a surprising number of quirks, and also +uses single-letter variable names confusingly to iterate through +the free list. + +Document what's going on. + +Use prev and cur to iterate over the free list. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1f8d0b01738e49767d662d6426af3570a64565f0) +(cherry picked from commit 6fd181e46a16f0219b586ce0bd44928a3f58dec8) +--- + grub-core/kern/mm.c | 63 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 41 insertions(+), 22 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index db7e0b2a5b..0351171cf9 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -446,54 +446,73 @@ grub_free (void *ptr) + } + else + { +- grub_mm_header_t q, s; ++ grub_mm_header_t cur, prev; + + #if 0 +- q = r->first; ++ cur = r->first; + do + { + grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n", +- GRUB_FILE, __LINE__, q, q->size, q->magic); +- q = q->next; ++ GRUB_FILE, __LINE__, cur, cur->size, cur->magic); ++ cur = cur->next; + } +- while (q != r->first); ++ while (cur != r->first); + #endif +- +- for (s = r->first, q = s->next; q <= p || q->next >= p; s = q, q = s->next) ++ /* Iterate over all blocks in the free ring. ++ * ++ * The free ring is arranged from high addresses to low ++ * addresses, modulo wraparound. ++ * ++ * We are looking for a block with a higher address than p or ++ * whose next address is lower than p. ++ */ ++ for (prev = r->first, cur = prev->next; cur <= p || cur->next >= p; ++ prev = cur, cur = prev->next) + { +- if (q->magic != GRUB_MM_FREE_MAGIC) +- grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic); ++ if (cur->magic != GRUB_MM_FREE_MAGIC) ++ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic); + +- if (q <= q->next && (q > p || q->next < p)) ++ /* Deal with wrap-around */ ++ if (cur <= cur->next && (cur > p || cur->next < p)) + break; + } + ++ /* mark p as free and insert it between cur and cur->next */ + p->magic = GRUB_MM_FREE_MAGIC; +- p->next = q->next; +- q->next = p; ++ p->next = cur->next; ++ cur->next = p; + ++ /* ++ * If the block we are freeing can be merged with the next ++ * free block, do that. ++ */ + if (p->next + p->next->size == p) + { + p->magic = 0; + + p->next->size += p->size; +- q->next = p->next; ++ cur->next = p->next; + p = p->next; + } + +- r->first = q; ++ r->first = cur; + +- if (q == p + p->size) ++ /* Likewise if can be merged with the preceeding free block */ ++ if (cur == p + p->size) + { +- q->magic = 0; +- p->size += q->size; +- if (q == s) +- s = p; +- s->next = p; +- q = s; ++ cur->magic = 0; ++ p->size += cur->size; ++ if (cur == prev) ++ prev = p; ++ prev->next = p; ++ cur = prev; + } + +- r->first = q; ++ /* ++ * Set r->first such that the just free()d block is tried first. ++ * (An allocation is tried from *first->next, and cur->next == p.) ++ */ ++ r->first = cur; + } + } + diff --git a/0311-mm-Document-grub_mm_init_region.patch b/0311-mm-Document-grub_mm_init_region.patch new file mode 100644 index 0000000..d819fa3 --- /dev/null +++ b/0311-mm-Document-grub_mm_init_region.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:49 +1100 +Subject: [PATCH] mm: Document grub_mm_init_region() + +The grub_mm_init_region() does some things that seem magical, especially +around region merging. Make it a bit clearer. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 246d69b7ea619fc1e77dcc5960e37aea45a9808c) +(cherry picked from commit 1eb53ad7659ee1d8141fe31138d0df9873b09182) +--- + grub-core/kern/mm.c | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 0351171cf9..1cbf98c7ab 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -128,23 +128,52 @@ grub_mm_init_region (void *addr, grub_size_t size) + if (((grub_addr_t) addr + 0x1000) > ~(grub_addr_t) size) + size = ((grub_addr_t) -0x1000) - (grub_addr_t) addr; + ++ /* Attempt to merge this region with every existing region */ + for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p) ++ /* ++ * Is the new region immediately below an existing region? That ++ * is, is the address of the memory we're adding now (addr) + size ++ * of the memory we're adding (size) + the bytes we couldn't use ++ * at the start of the region we're considering (q->pre_size) ++ * equal to the address of q? In other words, does the memory ++ * looks like this? ++ * ++ * addr q ++ * |----size-----|-q->pre_size-|| ++ */ + if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) + { ++ /* ++ * Yes, we can merge the memory starting at addr into the ++ * existing region from below. Align up addr to GRUB_MM_ALIGN ++ * so that our new region has proper alignment. ++ */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); ++ /* Copy the region data across */ + *r = *q; ++ /* Consider all the new size as pre-size */ + r->pre_size += size; +- ++ ++ /* ++ * If we have enough pre-size to create a block, create a ++ * block with it. Mark it as allocated and pass it to ++ * grub_free (), which will sort out getting it into the free ++ * list. ++ */ + if (r->pre_size >> GRUB_MM_ALIGN_LOG2) + { + h = (grub_mm_header_t) (r + 1); ++ /* block size is pre-size converted to cells */ + h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); + h->magic = GRUB_MM_ALLOC_MAGIC; ++ /* region size grows by block size converted back to bytes */ + r->size += h->size << GRUB_MM_ALIGN_LOG2; ++ /* adjust pre_size to be accurate */ + r->pre_size &= (GRUB_MM_ALIGN - 1); + *p = r; + grub_free (h + 1); + } ++ /* Replace the old region with the new region */ + *p = r; + return; + } diff --git a/0312-mm-Document-GRUB-internal-memory-management-structur.patch b/0312-mm-Document-GRUB-internal-memory-management-structur.patch new file mode 100644 index 0000000..657555b --- /dev/null +++ b/0312-mm-Document-GRUB-internal-memory-management-structur.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:45 +1100 +Subject: [PATCH] mm: Document GRUB internal memory management structures + +I spent more than a trivial quantity of time figuring out pre_size and +whether a memory region's size contains the header cell or not. + +Document the meanings of all the properties. Hopefully now no-one else +has to figure it out! + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a6c5c52ccffd2674d43db25fb4baa9c528526aa0) +(cherry picked from commit 222eb8897c25581e63a352633528fc130d151a64) +--- + include/grub/mm_private.h | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index c2c4cb1511..203533cc3d 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -21,15 +21,27 @@ + + #include + ++/* For context, see kern/mm.c */ ++ + /* Magic words. */ + #define GRUB_MM_FREE_MAGIC 0x2d3c2808 + #define GRUB_MM_ALLOC_MAGIC 0x6db08fa4 + ++/* A header describing a block of memory - either allocated or free */ + typedef struct grub_mm_header + { ++ /* ++ * The 'next' free block in this region's circular free list. ++ * Only meaningful if the block is free. ++ */ + struct grub_mm_header *next; ++ /* The block size, not in bytes but the number of cells of ++ * GRUB_MM_ALIGN bytes. Includes the header cell. ++ */ + grub_size_t size; ++ /* either free or alloc magic, depending on the block type. */ + grub_size_t magic; ++ /* pad to cell size: see the top of kern/mm.c. */ + #if GRUB_CPU_SIZEOF_VOID_P == 4 + char padding[4]; + #elif GRUB_CPU_SIZEOF_VOID_P == 8 +@@ -48,11 +60,27 @@ typedef struct grub_mm_header + + #define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) + ++/* A region from which we can make allocations. */ + typedef struct grub_mm_region + { ++ /* The first free block in this region. */ + struct grub_mm_header *first; ++ ++ /* ++ * The next region in the linked list of regions. Regions are initially ++ * sorted in order of increasing size, but can grow, in which case the ++ * ordering may not be preserved. ++ */ + struct grub_mm_region *next; ++ ++ /* ++ * A grub_mm_region will always be aligned to cell size. The pre-size is ++ * the number of bytes we were given but had to skip in order to get that ++ * alignment. ++ */ + grub_size_t pre_size; ++ ++ /* How many bytes are in this region? (free and allocated) */ + grub_size_t size; + } + *grub_mm_region_t; diff --git a/0313-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch b/0313-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch new file mode 100644 index 0000000..bff055a --- /dev/null +++ b/0313-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Apr 2022 15:24:14 +1000 +Subject: [PATCH] mm: Assert that we preserve header vs region alignment + +grub_mm_region_init() does: + + h = (grub_mm_header_t) (r + 1); + +where h is a grub_mm_header_t and r is a grub_mm_region_t. + +Cells are supposed to be GRUB_MM_ALIGN aligned, but while grub_mm_dump +ensures this vs the region header, grub_mm_region_init() does not. + +It's better to be explicit than implicit here: rather than changing +grub_mm_region_init() to ALIGN_UP(), require that the struct is +explicitly a multiple of the header size. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 1df8fe66c57087eb33bd6dc69f786ed124615aa7) +(cherry picked from commit f4d39686e773274e690ada441f5e128ac3c4ac06) +--- + include/grub/mm_private.h | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index 203533cc3d..a688b92a83 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -20,6 +20,7 @@ + #define GRUB_MM_PRIVATE_H 1 + + #include ++#include + + /* For context, see kern/mm.c */ + +@@ -89,4 +90,17 @@ typedef struct grub_mm_region + extern grub_mm_region_t EXPORT_VAR (grub_mm_base); + #endif + ++static inline void ++grub_mm_size_sanity_check (void) { ++ /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1). */ ++ COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) % ++ sizeof (struct grub_mm_header)) == 0); ++ ++ /* ++ * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is ++ * supposed to be 1 cell. ++ */ ++ COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); ++} ++ + #endif diff --git a/0314-mm-When-adding-a-region-merge-with-region-after-as-w.patch b/0314-mm-When-adding-a-region-merge-with-region-after-as-w.patch new file mode 100644 index 0000000..e0e4b71 --- /dev/null +++ b/0314-mm-When-adding-a-region-merge-with-region-after-as-w.patch @@ -0,0 +1,204 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Apr 2022 15:24:15 +1000 +Subject: [PATCH] mm: When adding a region, merge with region after as well as + before + +On x86_64-efi (at least) regions seem to be added from top down. The mm +code will merge a new region with an existing region that comes +immediately before the new region. This allows larger allocations to be +satisfied that would otherwise be the case. + +On powerpc-ieee1275, however, regions are added from bottom up. So if +we add 3x 32MB regions, we can still only satisfy a 32MB allocation, +rather than the 96MB allocation we might otherwise be able to satisfy. + + * Define 'post_size' as being bytes lost to the end of an allocation + due to being given weird sizes from firmware that are not multiples + of GRUB_MM_ALIGN. + + * Allow merging of regions immediately _after_ existing regions, not + just before. As with the other approach, we create an allocated + block to represent the new space and the pass it to grub_free() to + get the metadata right. + +Signed-off-by: Daniel Axtens +Tested-by: Stefan Berger +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 052e6068be622ff53f1238b449c300dbd0a8abcd) +(cherry picked from commit 9b7b9820e37b6828ea9b7da15f8da952a53a3df5) +--- + grub-core/kern/mm.c | 128 +++++++++++++++++++++++++++++----------------- + include/grub/mm_private.h | 9 ++++ + 2 files changed, 91 insertions(+), 46 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 1cbf98c7ab..7be33e23bf 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -130,53 +130,88 @@ grub_mm_init_region (void *addr, grub_size_t size) + + /* Attempt to merge this region with every existing region */ + for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p) +- /* +- * Is the new region immediately below an existing region? That +- * is, is the address of the memory we're adding now (addr) + size +- * of the memory we're adding (size) + the bytes we couldn't use +- * at the start of the region we're considering (q->pre_size) +- * equal to the address of q? In other words, does the memory +- * looks like this? +- * +- * addr q +- * |----size-----|-q->pre_size-|| +- */ +- if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) +- { +- /* +- * Yes, we can merge the memory starting at addr into the +- * existing region from below. Align up addr to GRUB_MM_ALIGN +- * so that our new region has proper alignment. +- */ +- r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); +- /* Copy the region data across */ +- *r = *q; +- /* Consider all the new size as pre-size */ +- r->pre_size += size; ++ { ++ /* ++ * Is the new region immediately below an existing region? That ++ * is, is the address of the memory we're adding now (addr) + size ++ * of the memory we're adding (size) + the bytes we couldn't use ++ * at the start of the region we're considering (q->pre_size) ++ * equal to the address of q? In other words, does the memory ++ * looks like this? ++ * ++ * addr q ++ * |----size-----|-q->pre_size-|| ++ */ ++ if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) ++ { ++ /* ++ * Yes, we can merge the memory starting at addr into the ++ * existing region from below. Align up addr to GRUB_MM_ALIGN ++ * so that our new region has proper alignment. ++ */ ++ r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); ++ /* Copy the region data across */ ++ *r = *q; ++ /* Consider all the new size as pre-size */ ++ r->pre_size += size; + +- /* +- * If we have enough pre-size to create a block, create a +- * block with it. Mark it as allocated and pass it to +- * grub_free (), which will sort out getting it into the free +- * list. +- */ +- if (r->pre_size >> GRUB_MM_ALIGN_LOG2) +- { +- h = (grub_mm_header_t) (r + 1); +- /* block size is pre-size converted to cells */ +- h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); +- h->magic = GRUB_MM_ALLOC_MAGIC; +- /* region size grows by block size converted back to bytes */ +- r->size += h->size << GRUB_MM_ALIGN_LOG2; +- /* adjust pre_size to be accurate */ +- r->pre_size &= (GRUB_MM_ALIGN - 1); +- *p = r; +- grub_free (h + 1); +- } +- /* Replace the old region with the new region */ +- *p = r; +- return; +- } ++ /* ++ * If we have enough pre-size to create a block, create a ++ * block with it. Mark it as allocated and pass it to ++ * grub_free (), which will sort out getting it into the free ++ * list. ++ */ ++ if (r->pre_size >> GRUB_MM_ALIGN_LOG2) ++ { ++ h = (grub_mm_header_t) (r + 1); ++ /* block size is pre-size converted to cells */ ++ h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); ++ h->magic = GRUB_MM_ALLOC_MAGIC; ++ /* region size grows by block size converted back to bytes */ ++ r->size += h->size << GRUB_MM_ALIGN_LOG2; ++ /* adjust pre_size to be accurate */ ++ r->pre_size &= (GRUB_MM_ALIGN - 1); ++ *p = r; ++ grub_free (h + 1); ++ } ++ /* Replace the old region with the new region */ ++ *p = r; ++ return; ++ } ++ ++ /* ++ * Is the new region immediately above an existing region? That ++ * is: ++ * q addr ++ * ||-q->post_size-|----size-----| ++ */ ++ if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size == ++ (grub_uint8_t *) addr) ++ { ++ /* ++ * Yes! Follow a similar pattern to above, but simpler. ++ * Our header starts at address - post_size, which should align us ++ * to a cell boundary. ++ * ++ * Cast to (void *) first to avoid the following build error: ++ * kern/mm.c: In function ‘grub_mm_init_region’: ++ * kern/mm.c:211:15: error: cast increases required alignment of target type [-Werror=cast-align] ++ * 211 | h = (grub_mm_header_t) ((grub_uint8_t *) addr - q->post_size); ++ * | ^ ++ * It is safe to do that because proper alignment is enforced in grub_mm_size_sanity_check(). ++ */ ++ h = (grub_mm_header_t)(void *) ((grub_uint8_t *) addr - q->post_size); ++ /* our size is the allocated size plus post_size, in cells */ ++ h->size = (size + q->post_size) >> GRUB_MM_ALIGN_LOG2; ++ h->magic = GRUB_MM_ALLOC_MAGIC; ++ /* region size grows by block size converted back to bytes */ ++ q->size += h->size << GRUB_MM_ALIGN_LOG2; ++ /* adjust new post_size to be accurate */ ++ q->post_size = (q->post_size + size) & (GRUB_MM_ALIGN - 1); ++ grub_free (h + 1); ++ return; ++ } ++ } + + /* Allocate a region from the head. */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); +@@ -195,6 +230,7 @@ grub_mm_init_region (void *addr, grub_size_t size) + r->first = h; + r->pre_size = (grub_addr_t) r - (grub_addr_t) addr; + r->size = (h->size << GRUB_MM_ALIGN_LOG2); ++ r->post_size = size - r->size; + + /* Find where to insert this region. Put a smaller one before bigger ones, + to prevent fragmentation. */ +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index a688b92a83..96c2d816be 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -81,8 +81,17 @@ typedef struct grub_mm_region + */ + grub_size_t pre_size; + ++ /* ++ * Likewise, the post-size is the number of bytes we wasted at the end ++ * of the allocation because it wasn't a multiple of GRUB_MM_ALIGN ++ */ ++ grub_size_t post_size; ++ + /* How many bytes are in this region? (free and allocated) */ + grub_size_t size; ++ ++ /* pad to a multiple of cell size */ ++ char padding[3 * GRUB_CPU_SIZEOF_VOID_P]; + } + *grub_mm_region_t; + diff --git a/0315-mm-Debug-support-for-region-operations.patch b/0315-mm-Debug-support-for-region-operations.patch new file mode 100644 index 0000000..86a6205 --- /dev/null +++ b/0315-mm-Debug-support-for-region-operations.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Apr 2022 15:24:16 +1000 +Subject: [PATCH] mm: Debug support for region operations + +This is handy for debugging. Enable with "set debug=regions". + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 8afa5ef45b797ba5d8147ceee85ac2c59dcc7f09) +(cherry picked from commit 4eb79abc52d35f40afc21e241561cf1dd8251a7b) +--- + grub-core/kern/mm.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 7be33e23bf..38bfb01df9 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -115,9 +115,8 @@ grub_mm_init_region (void *addr, grub_size_t size) + grub_mm_header_t h; + grub_mm_region_t r, *p, q; + +-#if 0 +- grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size); +-#endif ++ grub_dprintf ("regions", "Using memory for heap: start=%p, end=%p\n", ++ addr, (char *) addr + (unsigned int) size); + + /* Exclude last 4K to avoid overflows. */ + /* If addr + 0x1000 overflows then whole region is in excluded zone. */ +@@ -142,8 +141,14 @@ grub_mm_init_region (void *addr, grub_size_t size) + * addr q + * |----size-----|-q->pre_size-|| + */ ++ grub_dprintf ("regions", "Can we extend into region above?" ++ " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", ++ (grub_uint8_t *) addr, size, q->pre_size, (grub_uint8_t *) q); + if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) + { ++ grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", ++ q, (grub_uint8_t *) q + sizeof (*q) + q->size, ++ addr, (grub_uint8_t *) q + sizeof (*q) + q->size); + /* + * Yes, we can merge the memory starting at addr into the + * existing region from below. Align up addr to GRUB_MM_ALIGN +@@ -185,9 +190,15 @@ grub_mm_init_region (void *addr, grub_size_t size) + * q addr + * ||-q->post_size-|----size-----| + */ ++ grub_dprintf ("regions", "Can we extend into region below?" ++ " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", ++ (grub_uint8_t *) q, sizeof(*q), q->size, q->post_size, (grub_uint8_t *) addr); + if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size == + (grub_uint8_t *) addr) + { ++ grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", ++ q, (grub_uint8_t *) q + sizeof (*q) + q->size, ++ q, (grub_uint8_t *) addr + size); + /* + * Yes! Follow a similar pattern to above, but simpler. + * Our header starts at address - post_size, which should align us +@@ -213,6 +224,8 @@ grub_mm_init_region (void *addr, grub_size_t size) + } + } + ++ grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n", ++ addr, size); + /* Allocate a region from the head. */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); + diff --git a/0316-mm-Drop-unused-unloading-of-modules-on-OOM.patch b/0316-mm-Drop-unused-unloading-of-modules-on-OOM.patch new file mode 100644 index 0000000..f5357a8 --- /dev/null +++ b/0316-mm-Drop-unused-unloading-of-modules-on-OOM.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:17 +1000 +Subject: [PATCH] mm: Drop unused unloading of modules on OOM + +In grub_memalign(), there's a commented section which would allow for +unloading of unneeded modules in case where there is not enough free +memory available to satisfy a request. Given that this code is never +compiled in, let's remove it together with grub_dl_unload_unneeded(). + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 139fd9b134a01e0b5fe0ebefafa7f48d1ffb6d60) +(cherry picked from commit 81267ca5387486ede52e0462a71555bc6d181085) +--- + grub-core/kern/dl.c | 20 -------------------- + grub-core/kern/mm.c | 8 -------- + include/grub/dl.h | 1 - + 3 files changed, 29 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index d5de80186f..ab9101a5ad 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -998,23 +998,3 @@ grub_dl_unload (grub_dl_t mod) + grub_free (mod); + return 1; + } +- +-/* Unload unneeded modules. */ +-void +-grub_dl_unload_unneeded (void) +-{ +- /* Because grub_dl_remove modifies the list of modules, this +- implementation is tricky. */ +- grub_dl_t p = grub_dl_head; +- +- while (p) +- { +- if (grub_dl_unload (p)) +- { +- p = grub_dl_head; +- continue; +- } +- +- p = p->next; +- } +-} +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 38bfb01df9..1825dc8289 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -444,14 +444,6 @@ grub_memalign (grub_size_t align, grub_size_t size) + count++; + goto again; + +-#if 0 +- case 1: +- /* Unload unneeded modules. */ +- grub_dl_unload_unneeded (); +- count++; +- goto again; +-#endif +- + default: + break; + } +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 45ac8e339f..6bc2560bf0 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -206,7 +206,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); + grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); + grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); + int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +-extern void grub_dl_unload_unneeded (void); + extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); + extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); + extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); diff --git a/0317-mm-Allow-dynamically-requesting-additional-memory-re.patch b/0317-mm-Allow-dynamically-requesting-additional-memory-re.patch new file mode 100644 index 0000000..cde9cba --- /dev/null +++ b/0317-mm-Allow-dynamically-requesting-additional-memory-re.patch @@ -0,0 +1,131 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:18 +1000 +Subject: [PATCH] mm: Allow dynamically requesting additional memory regions + +Currently, all platforms will set up their heap on initialization of the +platform code. While this works mostly fine, it poses some limitations +on memory management on us. Most notably, allocating big chunks of +memory in the gigabyte range would require us to pre-request this many +bytes from the firmware and add it to the heap from the beginning on +some platforms like EFI. As this isn't needed for most configurations, +it is inefficient and may even negatively impact some usecases when, +e.g., chainloading. Nonetheless, allocating big chunks of memory is +required sometimes, where one example is the upcoming support for the +Argon2 key derival function in LUKS2. + +In order to avoid pre-allocating big chunks of memory, this commit +implements a runtime mechanism to add more pages to the system. When +a given allocation cannot be currently satisfied, we'll call a given +callback set up by the platform's own memory management subsystem, +asking it to add a memory area with at least "n" bytes. If this +succeeds, we retry searching for a valid memory region, which should +now succeed. + +If this fails, we try asking for "n" bytes, possibly spread across +multiple regions, in hopes that region merging means that we end up +with enough memory for things to work out. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Tested-by: Stefan Berger +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 887f98f0db43e33fba4ec1f85e42fae1185700bc) +(cherry picked from commit 8f3238a7dc482497e76b5ef6fbeb04f84d9a9aaa) +--- + grub-core/kern/mm.c | 30 ++++++++++++++++++++++++++++++ + include/grub/mm.h | 18 ++++++++++++++++++ + 2 files changed, 48 insertions(+) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 1825dc8289..f2e27f263b 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -28,6 +28,9 @@ + - multiple regions may be used as free space. They may not be + contiguous. + ++ - if existing regions are insufficient to satisfy an allocation, a new ++ region can be requested from firmware. ++ + Regions are managed by a singly linked list, and the meta information is + stored in the beginning of each region. Space after the meta information + is used to allocate memory. +@@ -81,6 +84,7 @@ + + + grub_mm_region_t grub_mm_base; ++grub_mm_add_region_func_t grub_mm_add_region_fn; + + /* Get a header from the pointer PTR, and set *P and *R to a pointer + to the header and a pointer to its region, respectively. PTR must +@@ -444,6 +448,32 @@ grub_memalign (grub_size_t align, grub_size_t size) + count++; + goto again; + ++ case 1: ++ /* Request additional pages, contiguous */ ++ count++; ++ ++ if (grub_mm_add_region_fn != NULL && ++ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) ++ goto again; ++ ++ /* fallthrough */ ++ ++ case 2: ++ /* Request additional pages, anything at all */ ++ count++; ++ ++ if (grub_mm_add_region_fn != NULL) ++ { ++ /* ++ * Try again even if this fails, in case it was able to partially ++ * satisfy the request ++ */ ++ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); ++ goto again; ++ } ++ ++ /* fallthrough */ ++ + default: + break; + } +diff --git a/include/grub/mm.h b/include/grub/mm.h +index d81623d226..7c6f925ffd 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -20,6 +20,7 @@ + #ifndef GRUB_MM_H + #define GRUB_MM_H 1 + ++#include + #include + #include + #include +@@ -29,6 +30,23 @@ + # define NULL ((void *) 0) + #endif + ++#define GRUB_MM_ADD_REGION_NONE 0 ++#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0) ++ ++/* ++ * Function used to request memory regions of `grub_size_t` bytes. The second ++ * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags. ++ */ ++typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int); ++ ++/* ++ * Set this function pointer to enable adding memory-regions at runtime in case ++ * a memory allocation cannot be satisfied with existing regions. ++ */ ++#ifndef GRUB_MACHINE_EMU ++extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn); ++#endif ++ + void grub_mm_init_region (void *addr, grub_size_t size); + void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); + void *EXPORT_FUNC(grub_malloc) (grub_size_t size); diff --git a/0318-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch b/0318-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch new file mode 100644 index 0000000..59ef18a --- /dev/null +++ b/0318-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:19 +1000 +Subject: [PATCH] kern/efi/mm: Always request a fixed number of pages on init + +When initializing the EFI memory subsystem, we will by default request +a quarter of the available memory, bounded by a minimum/maximum value. +Given that we're about to extend the EFI memory system to dynamically +request additional pages from the firmware as required, this scaling of +requested memory based on available memory will not make a lot of sense +anymore. + +Remove this logic as a preparatory patch such that we'll instead defer +to the runtime memory allocator. Note that ideally, we'd want to change +this after dynamic requesting of pages has been implemented for the EFI +platform. But because we'll need to split up initialization of the +memory subsystem and the request of pages from the firmware, we'd have +to duplicate quite some logic at first only to remove it afterwards +again. This seems quite pointless, so we instead have patches slightly +out of order. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 938c3760b8c0fca759140be48307179b50107ff6) +(cherry picked from commit 90e793a2ef3bc35609cb1b605ebd1fae15dd4b2d) +--- + grub-core/kern/efi/mm.c | 35 +++-------------------------------- + 1 file changed, 3 insertions(+), 32 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 88364d764c..f574edabef 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -38,9 +38,8 @@ + a multiplier of 4KB. */ + #define MEMORY_MAP_SIZE 0x3000 + +-/* The minimum and maximum heap size for GRUB itself. */ +-#define MIN_HEAP_SIZE 0x100000 +-#define MAX_HEAP_SIZE (1600 * 0x100000) ++/* The default heap size for GRUB itself in bytes. */ ++#define DEFAULT_HEAP_SIZE 0x100000 + + static void *finish_mmap_buf = 0; + static grub_efi_uintn_t finish_mmap_size = 0; +@@ -514,23 +513,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + return filtered_desc; + } + +-/* Return the total number of pages. */ +-static grub_efi_uint64_t +-get_total_pages (grub_efi_memory_descriptor_t *memory_map, +- grub_efi_uintn_t desc_size, +- grub_efi_memory_descriptor_t *memory_map_end) +-{ +- grub_efi_memory_descriptor_t *desc; +- grub_efi_uint64_t total = 0; +- +- for (desc = memory_map; +- desc < memory_map_end; +- desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- total += desc->num_pages; +- +- return total; +-} +- + /* Add memory regions. */ + static void + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, +@@ -695,8 +677,6 @@ grub_efi_mm_init (void) + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; +- grub_efi_uint64_t total_pages; +- grub_efi_uint64_t required_pages; + int mm_status; + + grub_nx_init (); +@@ -738,22 +718,13 @@ 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. */ +- total_pages = get_total_pages (filtered_memory_map, desc_size, +- filtered_memory_map_end); +- required_pages = (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)) +- required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE); +- + /* Sort the filtered descriptors, so that GRUB can allocate pages + from smaller regions. */ + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, required_pages); ++ filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); + + #if 0 + /* For debug. */ diff --git a/0319-kern-efi-mm-Extract-function-to-add-memory-regions.patch b/0319-kern-efi-mm-Extract-function-to-add-memory-regions.patch new file mode 100644 index 0000000..5d39c57 --- /dev/null +++ b/0319-kern-efi-mm-Extract-function-to-add-memory-regions.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:20 +1000 +Subject: [PATCH] kern/efi/mm: Extract function to add memory regions + +In preparation of support for runtime-allocating additional memory +region, this patch extracts the function to retrieve the EFI memory +map and add a subset of it to GRUB's own memory regions. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 96a7ea29e3cb61b6c2302e260e8e6a6117e17fa3) +[rharwood: backport around our nx] +(cherry picked from commit 4a85c48111f5e516cbc000bf4a7bc989b36d623c) +--- + grub-core/kern/efi/mm.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index f574edabef..9c9f9ac0c5 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -668,8 +668,8 @@ grub_nx_init (void) + } + } + +-void +-grub_efi_mm_init (void) ++static grub_err_t ++grub_efi_mm_add_regions (grub_size_t required_bytes) + { + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; +@@ -684,7 +684,7 @@ grub_efi_mm_init (void) + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +- grub_fatal ("cannot allocate memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map"); + + /* Obtain descriptors for available memory. */ + map_size = MEMORY_MAP_SIZE; +@@ -702,14 +702,14 @@ grub_efi_mm_init (void) + + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); + if (! memory_map) +- grub_fatal ("cannot allocate memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map"); + + mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, + &desc_size, 0); + } + + if (mm_status < 0) +- grub_fatal ("cannot get memory map"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI"); + + memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); + +@@ -724,7 +724,7 @@ grub_efi_mm_init (void) + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); ++ filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); + + #if 0 + /* For debug. */ +@@ -742,6 +742,15 @@ grub_efi_mm_init (void) + /* Release the memory maps. */ + grub_efi_free_pages ((grub_addr_t) memory_map, + 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++void ++grub_efi_mm_init (void) ++{ ++ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) ++ grub_fatal ("%s", grub_errmsg); + } + + #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) diff --git a/0320-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch b/0320-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch new file mode 100644 index 0000000..82322aa --- /dev/null +++ b/0320-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:21 +1000 +Subject: [PATCH] kern/efi/mm: Pass up errors from add_memory_regions() + +The function add_memory_regions() is currently only called on system +initialization to allocate a fixed amount of pages. As such, it didn't +need to return any errors: in case it failed, we cannot proceed anyway. +This will change with the upcoming support for requesting more memory +from the firmware at runtime, where it doesn't make sense anymore to +fail hard. + +Refactor the function to return an error to prepare for this. Note that +this does not change the behaviour when initializing the memory system +because grub_efi_mm_init() knows to call grub_fatal() in case +grub_efi_mm_add_regions() returns an error. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 15a015698921240adc1ac266a3b5bc5fcbd81521) +(cherry picked from commit c39acabc11d98ba18c6724eeb446508da7410c68) +--- + grub-core/kern/efi/mm.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 9c9f9ac0c5..29cf178aa9 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -514,7 +514,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + + /* Add memory regions. */ +-static void ++static grub_err_t + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, +@@ -542,9 +542,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_CODE); + if (! addr) +- grub_fatal ("cannot allocate conventional memory %p with %u pages", +- (void *) ((grub_addr_t) start), +- (unsigned) pages); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Memory starting at %p (%u pages) marked as free, but EFI would not allocate", ++ (void *) ((grub_addr_t) start), (unsigned) pages); + + grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); + +@@ -554,7 +554,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + } + + if (required_pages > 0) +- grub_fatal ("too little memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map", ++ required_pages); ++ ++ return GRUB_ERR_NONE; + } + + void +@@ -677,6 +681,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; ++ grub_err_t err; + int mm_status; + + grub_nx_init (); +@@ -723,8 +728,11 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ +- add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); ++ err = add_memory_regions (filtered_memory_map, desc_size, ++ filtered_memory_map_end, ++ BYTES_TO_PAGES (required_bytes)); ++ if (err != GRUB_ERR_NONE) ++ return err; + + #if 0 + /* For debug. */ diff --git a/0321-kern-efi-mm-Implement-runtime-addition-of-pages.patch b/0321-kern-efi-mm-Implement-runtime-addition-of-pages.patch new file mode 100644 index 0000000..45f4991 --- /dev/null +++ b/0321-kern-efi-mm-Implement-runtime-addition-of-pages.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:22 +1000 +Subject: [PATCH] kern/efi/mm: Implement runtime addition of pages + +Adjust the interface of grub_efi_mm_add_regions() to take a set of +GRUB_MM_ADD_REGION_* flags, which most notably is currently only the +GRUB_MM_ADD_REGION_CONSECUTIVE flag. This allows us to set the function +up as callback for the memory subsystem and have it call out to us in +case there's not enough pages available in the current heap. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 1df2934822df4c1170dde069d97cfbf7a9572bba) +(cherry picked from commit d2c744833aafcd84485e7b1faebaade5bfe7db7a) +--- + grub-core/kern/efi/mm.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 29cf178aa9..fc7561bbf7 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -518,7 +518,8 @@ static grub_err_t + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, +- grub_efi_uint64_t required_pages) ++ grub_efi_uint64_t required_pages, ++ unsigned int flags) + { + grub_efi_memory_descriptor_t *desc; + +@@ -532,6 +533,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + + start = desc->physical_start; + pages = desc->num_pages; ++ ++ if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)) ++ continue; ++ + if (pages > required_pages) + { + start += PAGES_TO_BYTES (pages - required_pages); +@@ -673,7 +678,7 @@ grub_nx_init (void) + } + + static grub_err_t +-grub_efi_mm_add_regions (grub_size_t required_bytes) ++grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) + { + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; +@@ -730,7 +735,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + /* Allocate memory regions for GRUB's memory management. */ + err = add_memory_regions (filtered_memory_map, desc_size, + filtered_memory_map_end, +- BYTES_TO_PAGES (required_bytes)); ++ BYTES_TO_PAGES (required_bytes), ++ flags); + if (err != GRUB_ERR_NONE) + return err; + +@@ -757,8 +763,9 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + void + grub_efi_mm_init (void) + { +- if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) ++ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE) + grub_fatal ("%s", grub_errmsg); ++ grub_mm_add_region_fn = grub_efi_mm_add_regions; + } + + #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) diff --git a/0322-efi-Increase-default-memory-allocation-to-32-MiB.patch b/0322-efi-Increase-default-memory-allocation-to-32-MiB.patch new file mode 100644 index 0000000..dde9e90 --- /dev/null +++ b/0322-efi-Increase-default-memory-allocation-to-32-MiB.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 20 Sep 2022 00:30:30 +1000 +Subject: [PATCH] efi: Increase default memory allocation to 32 MiB + +We have multiple reports of things being slower with a 1 MiB initial static +allocation, and a report (more difficult to nail down) of a boot failure +as a result of the smaller initial allocation. + +Make the initial memory allocation 32 MiB. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 75e38e86e7d9202f050b093f20500d9ad4c6dad9) +(cherry picked from commit 7cae9dcf90a9db0cdfae144356fe97e5391862e9) +--- + grub-core/kern/efi/mm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index fc7561bbf7..fde92ac9a5 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -39,7 +39,7 @@ + #define MEMORY_MAP_SIZE 0x3000 + + /* The default heap size for GRUB itself in bytes. */ +-#define DEFAULT_HEAP_SIZE 0x100000 ++#define DEFAULT_HEAP_SIZE 0x2000000 + + static void *finish_mmap_buf = 0; + static grub_efi_uintn_t finish_mmap_size = 0; diff --git a/0323-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch b/0323-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch new file mode 100644 index 0000000..a9069f1 --- /dev/null +++ b/0323-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sat, 15 Oct 2022 22:15:11 +0800 +Subject: [PATCH] mm: Try invalidate disk caches last when out of memory + +Every heap grow will cause all disk caches invalidated which decreases +performance severely. This patch moves disk cache invalidation code to +the last of memory squeezing measures. So, disk caches are released only +when there are no other ways to get free memory. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +Reviewed-by: Patrick Steinhardt +(cherry picked from commit 17975d10a80e2457e5237f87fa58a7943031983e) +(cherry picked from commit a048b2280ae6a2cf90fd5d2960823843e17e4d66) +--- + grub-core/kern/mm.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index f2e27f263b..da1ac9427c 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -443,12 +443,6 @@ grub_memalign (grub_size_t align, grub_size_t size) + switch (count) + { + case 0: +- /* Invalidate disk caches. */ +- grub_disk_cache_invalidate_all (); +- count++; +- goto again; +- +- case 1: + /* Request additional pages, contiguous */ + count++; + +@@ -458,7 +452,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + + /* fallthrough */ + +- case 2: ++ case 1: + /* Request additional pages, anything at all */ + count++; + +@@ -474,6 +468,12 @@ grub_memalign (grub_size_t align, grub_size_t size) + + /* fallthrough */ + ++ case 2: ++ /* Invalidate disk caches. */ ++ grub_disk_cache_invalidate_all (); ++ count++; ++ goto again; ++ + default: + break; + } diff --git a/grub.patches b/grub.patches index 23ccf3c..11b5828 100644 --- a/grub.patches +++ b/grub.patches @@ -277,32 +277,47 @@ Patch0276: 0276-nx-set-page-permissions-for-loaded-modules.patch Patch0277: 0277-nx-set-attrs-in-our-kernel-loaders.patch Patch0278: 0278-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch Patch0279: 0279-Make-debug-file-show-which-file-filters-get-run.patch -Patch0280: 0280-efi-make-the-default-arena-most-of-ram.patch -Patch0281: 0281-efi-use-enumerated-array-positions-for-our-allocatio.patch -Patch0282: 0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch -Patch0283: 0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch -Patch0284: 0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch -Patch0285: 0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch -Patch0286: 0286-ieee1275-implement-vec5-for-cas-negotiation.patch -Patch0287: 0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch -Patch0288: 0288-squish-give-up-on-rhgb-quiet.patch -Patch0289: 0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch -Patch0290: 0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch -Patch0291: 0291-commands-efi-tpm-Refine-the-status-of-log-event.patch -Patch0292: 0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch -Patch0293: 0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch -Patch0294: 0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch -Patch0295: 0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch -Patch0296: 0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch -Patch0297: 0297-font-Remove-grub_font_dup_glyph.patch -Patch0298: 0298-font-Fix-integer-overflow-in-ensure_comb_space.patch -Patch0299: 0299-font-Fix-integer-overflow-in-BMP-index.patch -Patch0300: 0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch -Patch0301: 0301-kern-efi-sb-Enforce-verification-of-font-files.patch -Patch0302: 0302-fbutil-Fix-integer-overflow.patch -Patch0303: 0303-font-Fix-an-integer-underflow-in-blit_comb.patch -Patch0304: 0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch -Patch0305: 0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch -Patch0306: 0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch -Patch0307: 0307-Correction-in-vector-5-values.patch -Patch0308: 0308-ppc64le-signed-boot-media-changes.patch +Patch0280: 0280-efi-use-enumerated-array-positions-for-our-allocatio.patch +Patch0281: 0281-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch +Patch0282: 0282-efi-allocate-the-initrd-within-the-bounds-expressed-.patch +Patch0283: 0283-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch +Patch0284: 0284-BLS-create-etc-kernel-cmdline-during-mkconfig.patch +Patch0285: 0285-ieee1275-implement-vec5-for-cas-negotiation.patch +Patch0286: 0286-squish-don-t-dup-rhgb-quiet-check-mtimes.patch +Patch0287: 0287-squish-give-up-on-rhgb-quiet.patch +Patch0288: 0288-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch +Patch0289: 0289-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch +Patch0290: 0290-commands-efi-tpm-Refine-the-status-of-log-event.patch +Patch0291: 0291-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch +Patch0292: 0292-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +Patch0293: 0293-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch +Patch0294: 0294-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch +Patch0295: 0295-font-Fix-several-integer-overflows-in-grub_font_cons.patch +Patch0296: 0296-font-Remove-grub_font_dup_glyph.patch +Patch0297: 0297-font-Fix-integer-overflow-in-ensure_comb_space.patch +Patch0298: 0298-font-Fix-integer-overflow-in-BMP-index.patch +Patch0299: 0299-font-Fix-integer-underflow-in-binary-search-of-char-.patch +Patch0300: 0300-kern-efi-sb-Enforce-verification-of-font-files.patch +Patch0301: 0301-fbutil-Fix-integer-overflow.patch +Patch0302: 0302-font-Fix-an-integer-underflow-in-blit_comb.patch +Patch0303: 0303-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch +Patch0304: 0304-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch +Patch0305: 0305-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch +Patch0306: 0306-Correction-in-vector-5-values.patch +Patch0307: 0307-ppc64le-signed-boot-media-changes.patch +Patch0308: 0308-mm-Clarify-grub_real_malloc.patch +Patch0309: 0309-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch +Patch0310: 0310-mm-Document-grub_free.patch +Patch0311: 0311-mm-Document-grub_mm_init_region.patch +Patch0312: 0312-mm-Document-GRUB-internal-memory-management-structur.patch +Patch0313: 0313-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch +Patch0314: 0314-mm-When-adding-a-region-merge-with-region-after-as-w.patch +Patch0315: 0315-mm-Debug-support-for-region-operations.patch +Patch0316: 0316-mm-Drop-unused-unloading-of-modules-on-OOM.patch +Patch0317: 0317-mm-Allow-dynamically-requesting-additional-memory-re.patch +Patch0318: 0318-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch +Patch0319: 0319-kern-efi-mm-Extract-function-to-add-memory-regions.patch +Patch0320: 0320-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch +Patch0321: 0321-kern-efi-mm-Implement-runtime-addition-of-pages.patch +Patch0322: 0322-efi-Increase-default-memory-allocation-to-32-MiB.patch +Patch0323: 0323-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch diff --git a/grub2.spec b/grub2.spec index 1a36c11..07f599e 100644 --- a/grub2.spec +++ b/grub2.spec @@ -14,7 +14,7 @@ Name: grub2 Epoch: 1 Version: 2.06 -Release: 56%{?dist} +Release: 57%{?dist} Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -532,6 +532,10 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Wed Feb 01 2023 Robbie Harwood - 2.06-57 +- Pull in allocator fixes from upstream +- Resolves: #2156419 + * Tue Jan 31 2023 Robbie Harwood - 2.06-56 - ppc64le: disable mdraid < 1.1 - Resolves: #2143420