On Fri, Aug 08, 2025 at 04:36:51PM +0000, Evangelos Petrongonas wrote: > When KHO (Kexec HandOver) is enabled, it sets up scratch memory regions > early during device tree scanning. After kexec, the new kernel > exclusively uses this region for memory allocations during boot up to > the initialization of the page allocator > > However, when booting with EFI, EFI's reserve_regions() uses > memblock_remove(0, PHYS_ADDR_MAX) to clear all memory regions before > rebuilding them from EFI data. This destroys KHO scratch regions and > their flags, thus causing a kernel panic, as there are no scratch > memory regions. > > Instead of wholesale removal, iterate through memory regions and only > remove non-KHO ones. This preserves KHO scratch regions while still > allowing EFI to rebuild its memory map.
It's worth mentioning that scratch areas are "good known memory" :) > Signed-off-by: Evangelos Petrongonas <[email protected]> > --- > > Reproduction/Verification Steps > The issue and the fix can be reproduced/verified by booting a VM with > EFI and attempting to perform a KHO enabled kexec. The fix > was developed/tested on arm64. > > drivers/firmware/efi/efi-init.c | 31 +++++++++++++++++++++++++++---- > 1 file changed, 27 insertions(+), 4 deletions(-) > > diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c > index a00e07b853f22..2f08b1ab764f6 100644 > --- a/drivers/firmware/efi/efi-init.c > +++ b/drivers/firmware/efi/efi-init.c > @@ -164,12 +164,35 @@ static __init void reserve_regions(void) > pr_info("Processing EFI memory map:\n"); > > /* > - * Discard memblocks discovered so far: if there are any at this > - * point, they originate from memory nodes in the DT, and UEFI > - * uses its own memory map instead. > + * Discard memblocks discovered so far except for KHO scratch regions. > + * Most memblocks at this point originate from memory nodes in the DT, > + * and UEFI uses its own memory map instead. However, if KHO is enabled, > + * scratch regions must be preserved. > */ > memblock_dump_all(); > - memblock_remove(0, PHYS_ADDR_MAX); > + > + if (IS_ENABLED(CONFIG_MEMBLOCK_KHO_SCRATCH)) { It's better to condition this on kho_get_fdt() that means that we are actually doing a handover. > + struct memblock_region *reg; > + phys_addr_t start, size; > + int i; > + > + /* Remove all non-KHO regions */ > + for (i = memblock.memory.cnt - 1; i >= 0; i--) { Please use for_each_mem_region() > + reg = &memblock.memory.regions[i]; > + if (!memblock_is_kho_scratch(reg)) { > + start = reg->base; > + size = reg->size; > + memblock_remove(start, size); > + } > + } > + } else { > + /* > + * KHO is disabled. Discard memblocks discovered so far: if there > + * are any at this point, they originate from memory nodes in the > + * DT, and UEFI uses its own memory map instead. > + */ > + memblock_remove(0, PHYS_ADDR_MAX); > + } > > for_each_efi_memory_desc(md) { > paddr = md->phys_addr; > -- > 2.43.0 -- Sincerely yours, Mike.
