Re: [PATCH v3] LoongArch: kexec: use core control page for relocation trampoline to avoid QEMU FDT conflict
From: Huacai Chen
Date: Mon Jun 29 2026 - 10:12:58 EST
Hi, George,
On Thu, Jun 4, 2026 at 7:41 PM George Guo <dongtai.guo@xxxxxxxxx> wrote:
>
> From: George Guo <guodongtai@xxxxxxxxxx>
>
> KEXEC_CONTROL_CODE was hardcoded to TO_CACHE(0x100000). QEMU places its
> machine FDT at physical 0x100000 when booting with '-kernel', so
> machine_kexec_prepare() overwrote the FDT with the relocation trampoline.
> The kexec'd kernel's fdt_setup() then read trampoline code instead of a
> valid FDT, earlycon auto-detection failed, and the second kernel booted
> silently with no console output.
>
> The trampoline does not need a fixed address. It is executed by the
> current kernel to relocate and enter the new kernel, and is dead once the
> new kernel starts. Drop KEXEC_CONTROL_CODE and reuse the
> control_code_page that the kexec core already allocates (as arm64 and
> riscv do). That page is excluded from the relocation copy and lives
> nowhere near 0x100000, so the QEMU FDT is left intact.
>
> Signed-off-by: George Guo <guodongtai@xxxxxxxxxx>
> ---
> Changes in v3:
> - Only the relocation trampoline is moved off the hardcoded address onto
> the core-allocated control_code_page. v2 also moved the kernel command
> line to a kexec control page, but as Huacai pointed out a control page
> only avoids being clobbered by the relocation copy in the current
> kernel; it is not reserved in the new kernel, which reads the command
> line early in boot. The command line therefore stays at the existing
> fixed KEXEC_CMDLINE_ADDR in the reserved first 2MB (unchanged).
Then how to avoid the cmdline overlapping FDT, and how to avoid the
control page being corrupted by the new kernel?
Huacai
>
> Changes in v2:
> - Instead of moving KEXEC_CONTROL_CODE to a different fixed address, reuse
> the kexec core's control_code_page for the trampoline.
>
> v2: https://lore.kernel.org/all/20260601033820.38805-1-dongtai.guo@xxxxxxxxx/
> v1: https://lore.kernel.org/all/20260528135828.196953-1-dongtai.guo@xxxxxxxxx/
>
> arch/loongarch/kernel/machine_kexec.c | 21 ++++++++++++++++-----
> 1 file changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> index d7fafda1d541..3527da57234d 100644
> --- a/arch/loongarch/kernel/machine_kexec.c
> +++ b/arch/loongarch/kernel/machine_kexec.c
> @@ -21,8 +21,14 @@
> #include <asm/cacheflush.h>
> #include <asm/page.h>
>
> -/* 0x100000 ~ 0x200000 is safe */
> -#define KEXEC_CONTROL_CODE TO_CACHE(0x100000UL)
> +/*
> + * The kexec'd kernel reads its command line from this pointer early in
> + * boot, so the command line must live in memory the new kernel will not
> + * reuse. Keep it at a fixed address in the first 2MB, which both the
> + * current and the kexec'd kernel always keep reserved (see
> + * memblock_reserve(PHYS_OFFSET, 0x200000) in arch/loongarch/kernel/mem.c).
> + * 0x108000 does not overlap QEMU's machine FDT at 0x100000.
> + */
> #define KEXEC_CMDLINE_ADDR TO_CACHE(0x108000UL)
>
> static unsigned long reboot_code_buffer;
> @@ -72,9 +78,14 @@ int machine_kexec_prepare(struct kimage *kimage)
> }
> }
>
> - /* kexec/kdump need a safe page to save reboot_code_buffer */
> - kimage->control_code_page = virt_to_page((void *)KEXEC_CONTROL_CODE);
> -
> + /*
> + * kexec/kdump need a safe page to save reboot_code_buffer. Reuse the
> + * control_code_page allocated by the kexec core (as arm64 and riscv
> + * do) instead of a fixed address: the trampoline is only executed by
> + * the current kernel before entering the new kernel, so it needs no
> + * fixed or reserved location. This also stops machine_kexec_prepare()
> + * from overwriting QEMU's machine FDT at 0x100000.
> + */
> reboot_code_buffer = (unsigned long)page_address(kimage->control_code_page);
> memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size);
>
> --
> 2.25.1
>