Hi, George, On Thu, Jun 4, 2026 at 7:41 PM George Guo <[email protected]> wrote: > > From: George Guo <[email protected]> > > 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 <[email protected]> > --- > 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/[email protected]/ > v1: https://lore.kernel.org/all/[email protected]/ > > 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 >
