diff --git a/0580-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch b/0580-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch new file mode 100644 index 00000000..27ac2784 --- /dev/null +++ b/0580-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch @@ -0,0 +1,210 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 8 Aug 2023 12:21:55 -0400 +Subject: [PATCH] kern/ieee1275/init: ppc64: Restrict high memory in presence + of fadump + +This is a backport of the patch with the same name to grub 2.02. + +When a kernel dump is present then restrict the high memory regions to +avoid allocating memory where the kernel dump resides. Use the +ibm,kernel-dump node under /rtas to determine whether a kernel dump exists +and up to which limit grub can use available memory. Set the +upper_mem_limit to the size of the kernel dump section of type +'REAL_MODE_REGION' and therefore only allow grub's memory usage for high +addresses from 768MB to 'upper_mem_limit'. This means that grub can +use high memory in the range of 768MB to upper_mem_limit and +the kernel-dump memory regions above 'upper_mem_limit' remain untouched. +This change has no effect on memory allocations below 640MB. + +Also, fall back to allocating below 640MB in case the chunk of +memory there would be larger than the chunk of memory above 768MB. +This can for example occur if a free memory area is found starting at 300MB +extending up to 1GB but a kernel dump is located at 768MB and therefore +does not allow the allocation of the high memory area but requiring to use +the chunk starting at 300MB to avoid an unnecessary out-of-memory +condition. + +Signed-off-by: Stefan Berger +Cc: Hari Bathini +Cc: Pavithra Prakash +Cc: Michael Ellerman +Cc: Carolyn Scherrer +Cc: Mahesh Salgaonkar +Cc: Sourabh Jain +--- + grub-core/kern/ieee1275/init.c | 139 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 139 insertions(+) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 1fae84440403..31843ab70a62 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -17,6 +17,8 @@ + * along with GRUB. If not, see . + */ + ++#include /* offsetof() */ ++ + #include + #include + #include +@@ -180,6 +182,97 @@ grub_claim_heap (void) + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); + } + #else ++ ++/* ibm,kernel-dump data structures */ ++struct kd_section ++{ ++ grub_uint32_t flags; ++ grub_uint16_t src_datatype; ++#define KD_SRC_DATATYPE_REAL_MODE_REGION 0x0011 ++ grub_uint16_t error_flags; ++ grub_uint64_t src_address; ++ grub_uint64_t num_bytes; ++ grub_uint64_t act_bytes; ++ grub_uint64_t dst_address; ++} GRUB_PACKED; ++ ++#define MAX_KD_SECTIONS 10 ++ ++struct kernel_dump ++{ ++ grub_uint32_t format; ++ grub_uint16_t num_sections; ++ grub_uint16_t status_flags; ++ grub_uint32_t offset_1st_section; ++ grub_uint32_t num_blocks; ++ grub_uint64_t start_block; ++ grub_uint64_t num_blocks_avail; ++ grub_uint32_t offet_path_string; ++ grub_uint32_t max_time_allowed; ++ struct kd_section kds[MAX_KD_SECTIONS]; /* offset_1st_section should point to kds[0] */ ++} GRUB_PACKED; ++ ++/* ++ * Determine if a kernel dump exists and if it does, then determine the highest ++ * address that grub can use for memory allocations. ++ * The caller must have initialized *highest to ~0. *highest will not ++ * be modified if no kernel dump is found. ++ */ ++static int ++check_kernel_dump (grub_uint64_t *highest) ++{ ++ struct kernel_dump kernel_dump; ++ grub_ssize_t kernel_dump_size; ++ grub_ieee1275_phandle_t rtas; ++ struct kd_section *kds; ++ grub_size_t i; ++ ++ /* If there's a kernel-dump it must have at least one section */ ++ if (grub_ieee1275_finddevice ("/rtas", &rtas) || ++ grub_ieee1275_get_property (rtas, "ibm,kernel-dump", &kernel_dump, ++ sizeof (kernel_dump), &kernel_dump_size) || ++ kernel_dump_size <= (grub_ssize_t) offsetof (struct kernel_dump, kds[1])) ++ return 0; ++ ++ kernel_dump_size = grub_min (kernel_dump_size, (grub_ssize_t) sizeof (kernel_dump)); ++ ++ if (grub_be_to_cpu32 (kernel_dump.format) != 1) ++ { ++ grub_printf (_("Error: ibm,kernel-dump has an unexpected format version '%u'\n"), ++ grub_be_to_cpu32 (kernel_dump.format)); ++ return 0; ++ } ++ ++ if (grub_be_to_cpu16 (kernel_dump.num_sections) > MAX_KD_SECTIONS) ++ { ++ grub_printf (_("Error: Too many kernel dump sections: %d\n"), ++ grub_be_to_cpu32 (kernel_dump.num_sections)); ++ return 0; ++ } ++ ++ for (i = 0; i < grub_be_to_cpu16 (kernel_dump.num_sections); i++) ++ { ++ kds = (struct kd_section *) ((grub_addr_t) &kernel_dump + ++ grub_be_to_cpu32 (kernel_dump.offset_1st_section) + ++ i * sizeof (struct kd_section)); ++ /* sanity check the address is within the 'kernel_dump' struct */ ++ if ((grub_addr_t) kds > (grub_addr_t) &kernel_dump + kernel_dump_size + sizeof (*kds)) ++ { ++ grub_printf (_("Error: 'kds' address beyond last available section\n")); ++ return 0; ++ } ++ ++ if ((grub_be_to_cpu16 (kds->src_datatype) == KD_SRC_DATATYPE_REAL_MODE_REGION) && ++ (grub_be_to_cpu64 (kds->src_address) == 0)) ++ { ++ *highest = grub_min (*highest, grub_be_to_cpu64 (kds->num_bytes)); ++ break; ++ } ++ } ++ ++ return 1; ++} ++ + /* Helper for grub_claim_heap on powerpc. */ + static int + heap_size (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, +@@ -207,7 +300,9 @@ static int + heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + void *data) + { ++ grub_uint64_t upper_mem_limit = ~0; + grub_uint32_t total = *(grub_uint32_t *)data; ++ int has_kernel_dump; + + if (type != GRUB_MEMORY_AVAILABLE) + return 0; +@@ -243,6 +338,50 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + len = 0; + } + ++ has_kernel_dump = check_kernel_dump (&upper_mem_limit); ++ if (has_kernel_dump) ++ { ++ grub_uint64_t lo_len = 0, hi_len = 0; ++ ++ if (addr > upper_mem_limit || upper_mem_limit == (grub_uint64_t)~0) ++ return 0; ++ ++ /* limit len to stay below upper_mem_limit */ ++ if (addr < upper_mem_limit && (addr + len) > upper_mem_limit) ++ { ++ len = grub_min (len, upper_mem_limit - addr); ++ } ++ ++ /* We can allocate below 640MB or above 768MB. ++ * Choose the bigger chunk below 640MB or above 768MB. ++ */ ++ if (addr < 0x28000000) ++ { ++ lo_len = grub_min (len, 0x28000000 - addr); ++ } ++ if (addr + len > 0x30000000) ++ { ++ if (addr < 0x30000000) ++ hi_len = len - (0x30000000 - addr); ++ else ++ hi_len = len; ++ } ++ ++ if (hi_len > lo_len) ++ { ++ len = hi_len; ++ if (addr < 0x30000000) ++ addr = 0x30000000; ++ } ++ else ++ { ++ len = lo_len; ++ } ++ ++ if (len == 0) ++ return 0; ++ } ++ + /* If this block contains 0x30000000 (768MB), do not claim below that. + Linux likes to claim memory at min(RMO top, 768MB) and works down + without reference to /memory/available. */ diff --git a/grub.patches b/grub.patches index c4591e35..4dbe3152 100644 --- a/grub.patches +++ b/grub.patches @@ -577,3 +577,4 @@ Patch0576: 0576-efi-http-change-uint32_t-to-uintn_t-for-grub_efi_htt.patch Patch0577: 0577-ieee1275-Converting-plain-numbers-to-constants-in-Ve.patch Patch0578: 0578-ieee1275-extended-support-in-options-vector5.patch Patch0579: 0579-Regenerate-kernelopts-if-missing-on-ppc.patch +Patch0580: 0580-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch diff --git a/grub2.spec b/grub2.spec index 658146f7..44a119e7 100644 --- a/grub2.spec +++ b/grub2.spec @@ -7,7 +7,7 @@ Name: grub2 Epoch: 1 Version: 2.02 -Release: 151%{?dist} +Release: 152%{?dist} Summary: Bootloader with support for Linux, Multiboot and more Group: System Environment/Base License: GPLv3+ @@ -510,6 +510,11 @@ fi %endif %changelog +* Fri Oct 20 2023 Nicolas Frayer - 2.02-152 +- kern/ieee1275/init: ppc64: Restrict high memory in presence + of fadump +- Resolves: #RHEL-14283 + * Mon Aug 28 2023 Nicolas Frayer - 2.02-151 - util: Regenerate kernelopts if missing on ppc - Resolves: #2051889