Re: [RFC PATCH 2/3] powerpc: add support for Kexec HandOver (KHO)
From: Sourabh Jain
Date: Wed Aug 26 2026 - 09:41:03 EST
Hello Pratyush,
After looking at the x86 crashkernel and KHO scratch memory
allocation order, I realized that the same issue should exist on x86
as well. I ran the same experiment on an x86 guest, and the results
confirmed this.
[root@localhost ~]# dmesg | grep -i -e kho -e crashkernel
[ 0.000000] Command line: BOOT_IMAGE=(hd0,gpt3)/boot/vmlinuz-6.19.10-300.fc44.x86_64 no_timer_check console=tty1 console=ttyS0,115200n8 systemd.firstboot=off root=UUID=15c26993-ac30-424a-9c4b-faec4434d234 rootflags=subvol=root kho=on crashkernel=1G
[ 0.004615] crashkernel reserved: 0x000000007f000000 - 0x00000000bf000000 (1024 MB)
[ 0.034746] Kernel command line: BOOT_IMAGE=(hd0,gpt3)/boot/vmlinuz-6.19.10-300.fc44.x86_64 no_timer_check console=tty1 console=ttyS0,115200n8 systemd.firstboot=off root=UUID=15c26993-ac30-424a-9c4b-faec4434d234 rootflags=subvol=root kho=on crashkernel=1G
[ 0.095761] KHO: Failed to reserve scratch area, disabling kexec handover
I agree that this can be avoided by using the crashkernel=xxM,high option.
However, I just wanted to share the same problem currently exists on x86 as well.
While reading the KHO code, I came across the following commit, which handles
a somewhat similar problem with HugeTLB:
fdd843f2be1a ("kho: exclude hugetlb memory from scratch size calculation")
The approach is to first account for HugeTLB allocations as a separate memblock
reservation type and then exclude them when calculating the scratch memory
reservation.
How about using the same approach to avoid accounting for crashkernel memory
when calculating the scratch memory size?
- Sourabh Jain
On 21/08/26 17:26, Pratyush Yadav wrote:
On Fri, Aug 21 2026, Sourabh Jain wrote:
Add the architecture bits needed to enable CONFIG_KEXEC_HANDOVER oncrashkernel has the variant "crashkernel=size[KMG],high", which ensures
powerpc.
Set ARCH_SUPPORTS_KEXEC_HANDOVER for PPC64, following the existing
pattern used by ARCH_SUPPORTS_KEXEC and ARCH_SUPPORTS_KEXEC_FILE.
On the boot path, parse the "linux,kho-fdt" and "linux,kho-scratch"
properties from /chosen and pass them to kho_populate(). This lets a
kernel booted via KHO kexec recover the FDT and scratch region left
behind by the previous kernel. The call is placed early in
setup_arch(), before unflatten_device_tree().
Open issues:
============
This patch also adds "depends on !CRASH_DUMP" to
ARCH_SUPPORTS_KEXEC_HANDOVER. This is needed because of an ordering
conflict between crashkernel reservation and KHO scratch reservation
on powerpc.
Crashkernel memory is reserved very early in boot, from arch-specific
code: head.S -> early_setup() -> early_init_devtree() ->
arch_reserve_crashkernel() / fadump_reserve_mem(). KHO's scratch
region is reserved later, from generic code: start_kernel() ->
mm_core_init() -> kho_memory_init(). So on powerpc, crashkernel
memory is always reserved first.
This ordering causes a real failure. In the common case, crashkernel
reservation on powerpc starts at a 512M offset (the exact offset can
vary, but 512M is typical). So with crashkernel=3G, the reservation
occupies memory from 512M up to 3.5G -- roughly 75% of the entire low
4G area.
Since crashkernel reservation always happens first, that 3G is
already committed by the time kho_memory_init() runs. It then tries
to reserve a low scratch region sized at 200% of whatever is already
reserved below 4G. With ~75% of that 4G area already taken by
crashkernel memory, 200% of that easily exceeds the remaining space
-- and since the low scratch region is itself capped at 4G, there's
no room left to fit it. The reservation fails.
memory is allocated above 4G. Unless powerpc has some requirement for
strictly having the crashkernel below 4G, I think it will make a lot of
sense to enable support for this feature. So KHO users can specify this
to get crashkernel working with KHO.
Powerpc doesn't support this right now, but from a quick skim of the
code, I think it should be simple enough. From
arch_reserve_crashkernel() you just need to pass a bool * to
parse_crashkernel(), and then pass the result to
reserve_crashkernel_generic().
Solving the ordering of crash reservations and KHO is tricky and comes
with some difficult tradeoffs. Allocating crash from highmem should be a
lot simpler.
And on that note, I don't think you should do a depends on !CRASH_DUMP.
Even when CONFIG_KEXEC_HANDOVER is enabled, KHO isn't on by default
(well, unless KEXEC_HANDOVER_ENABLE_DEFAULT is set). You need to enable
it via cmdline. So it is entirely possible for people using KHO on PPC
to not use crash and vice versa. This decision can be made at deployment
time, not at compile time.
To work around this and get KHO working on powerpc, this patch:[...]
1. Makes KHO usable on powerpc only when CRASH_DUMP is disabled.
2. Calls kho_populate() from setup_arch(), so it runs before
kho_memory_init() reserves the scratch region.
The real fix would be to reserve the KHO scratch region before
crashkernel memory instead of after. But scratch reservation happens
in generic code (kho_memory_init(), called from mm_core_init()), so
this isn't something powerpc can address on its own -- it needs
discussion on how to influence the ordering between generic scratch
reservation and arch-specific crashkernel reservation. This patch
doesn't attempt that; it's meant as a starting point for that
discussion.
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig[...]
index 2580e27e4328..61350d3e7a19 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -716,6 +716,11 @@ config ARCH_SELECTS_CRASH_DUMP
depends on CRASH_DUMP
select RELOCATABLE if PPC64 || 44x || PPC_85xx
+config ARCH_SUPPORTS_KEXEC_HANDOVER
+ def_bool y
+ depends on PPC64
+ depends on !CRASH_DUMP
+
config ARCH_SUPPORTS_CRASH_HOTPLUG
def_bool y
depends on PPC64
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 4afaba19b586..1fee743abdf2 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
}This looks pretty much a duplicate of early_init_dt_check_kho(). On
#endif
+#ifdef CONFIG_PPC64
+static void __init init_kho(const void *fdt)
+{
+ unsigned long node;
+ u64 fdt_start, fdt_size, scratch_start, scratch_size;
+
+ if (!IS_ENABLED(CONFIG_KEXEC_HANDOVER))
+ return;
+
+ /* Find and verify the /chosen node, same as early_init_dt_scan_chosen() does */
+ node = fdt_path_offset(fdt, "/chosen");
+ if ((long)node < 0)
+ node = fdt_path_offset(fdt, "/chosen@0");
+ if ((long)node < 0)
+ return;
+
+ if (!of_flat_dt_get_addr_size(node, "linux,kho-fdt",
+ &fdt_start, &fdt_size))
+ return;
+ if (!of_flat_dt_get_addr_size(node, "linux,kho-scratch",
+ &scratch_start, &scratch_size))
+ return;
+
+ kho_populate(fdt_start, fdt_size, scratch_start, scratch_size);
+}
arm64 this is called via early_init_dt_scan(). But from a quick search I
don't see powerpc calling it.
Would it make sense to call this function (or
early_init_dt_scan_nodes()) for powerpc?
If not, I think it would be a better idea to expose
early_init_dt_check_kho() and call it from powerpc setup_arch() instead
of duplicating the logic.
+#endif[...]
+
/*
* Called into from start_kernel this initializes memblock, which is used
* to manage page allocation until mem_init is called.