* [PATCH v3 2/3] LoongArch: kexec: add KHO support for ACPI-only
2026-06-01 9:39 ` [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based George Guo
@ 2026-06-01 9:39 ` George Guo
2026-06-01 9:39 ` [PATCH v3 3/3] selftests/kho: add LoongArch vmtest support George Guo
2026-07-13 13:53 ` [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based Pratyush Yadav
2 siblings, 0 replies; 9+ messages in thread
From: George Guo @ 2026-06-01 9:39 UTC (permalink / raw)
To: Huacai Chen, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
Shuah Khan
Cc: George Guo, WANG Xuerui, Alexander Graf, loongarch, linux-kernel,
kexec, linux-mm, linux-kselftest, systems
From: George Guo <guodongtai@kylinos.cn>
On ACPI-only systems fdt_setup() returns early when it detects ACPI,
so initial_boot_params remains NULL and the FDT-based kho_load_fdt()
path cannot be used.
machine_kexec_file.c:
- kho_load_fdt(): add an else branch that builds a minimal FDT from
scratch (SZ_1K) containing only a /chosen node with linux,kho-fdt
and linux,kho-scratch properties, using the libfdt creation API.
- Since DEVICE_TREE_GUID is absent from the EFI config table on
ACPI-only systems, build a new config table with DEVICE_TREE_GUID
appended and load it as a kexec segment. Store the result in
kimage_arch so machine_kexec() can switch st->tables before jumping.
- arch_kimage_file_post_load_cleanup(): free the efi_tables kvmalloc
buffer once the kexec image has been loaded.
machine_kexec.c:
- Before jumping, update the EFI system table pointer: for FDT-based
systems update the existing DEVICE_TREE_GUID entry; for ACPI-only
systems switch st->tables / st->nr_tables to the new extended table.
setup.c:
- fdt_setup(): when ACPI is detected, use efi_fdt_pointer() to detect
whether this is a KHO kexec boot. The first kernel switches the EFI
config table to a new one that includes a DEVICE_TREE_GUID entry
pointing to the minimal KHO FDT. If found, call early_init_dt_scan()
so early_init_dt_check_kho() can consume linux,kho-fdt and
linux,kho-scratch, then reset initial_boot_params to NULL so the rest
of the ACPI boot path is unaffected.
kexec.h:
- Add efi_tables, efi_tables_mem, efi_tables_cnt to kimage_arch.
Signed-off-by: George Guo <guodongtai@kylinos.cn>
---
arch/loongarch/include/asm/kexec.h | 3 +
arch/loongarch/kernel/machine_kexec.c | 11 ++
arch/loongarch/kernel/machine_kexec_file.c | 162 +++++++++++++++++++--
arch/loongarch/kernel/setup.c | 21 ++-
4 files changed, 184 insertions(+), 13 deletions(-)
diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
index adf54bfcdd49..e1abaf40b06a 100644
--- a/arch/loongarch/include/asm/kexec.h
+++ b/arch/loongarch/include/asm/kexec.h
@@ -42,6 +42,9 @@ struct kimage_arch {
#ifdef CONFIG_KEXEC_HANDOVER
void *fdt; /* virtual address of KHO FDT segment buffer */
unsigned long fdt_mem; /* physical address of KHO FDT segment */
+ void *efi_tables; /* new EFI config table buffer (virtual) */
+ unsigned long efi_tables_mem; /* physical address of new EFI config table */
+ unsigned long efi_tables_cnt; /* number of entries in new EFI config table */
#endif
};
diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
index 98529c71d001..cbb7f8368843 100644
--- a/arch/loongarch/kernel/machine_kexec.c
+++ b/arch/loongarch/kernel/machine_kexec.c
@@ -313,6 +313,17 @@ void machine_kexec(struct kimage *image)
break;
}
}
+ } else if (internal->efi_tables_mem) {
+ /*
+ * ACPI-only system: DEVICE_TREE_GUID was not in the original
+ * EFI config table. Switch to the new table that was built in
+ * kho_load_fdt() with DEVICE_TREE_GUID appended.
+ */
+ efi_system_table_t *st =
+ (efi_system_table_t *)TO_CACHE(systable_ptr);
+
+ st->tables = internal->efi_tables_mem;
+ st->nr_tables = internal->efi_tables_cnt;
}
#endif
diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
index bf1e8c1c7e70..c1955d991061 100644
--- a/arch/loongarch/kernel/machine_kexec_file.c
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) "kexec_file: " fmt
+#include <linux/efi.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
@@ -20,6 +21,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
+#include <asm/addrspace.h>
#include <asm/bootinfo.h>
const struct kexec_file_ops * const kexec_file_loaders[] = {
@@ -37,6 +39,8 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
#ifdef CONFIG_KEXEC_HANDOVER
kvfree(image->arch.fdt);
image->arch.fdt = NULL;
+ kvfree(image->arch.efi_tables);
+ image->arch.efi_tables = NULL;
#endif
return kexec_image_post_load_cleanup_default(image);
@@ -68,6 +72,13 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
* segment. The second kernel reads linux,kho-fdt and linux,kho-scratch
* from /chosen via early_init_dt_check_kho() and calls kho_populate().
*
+ * On FDT-based systems (initial_boot_params != NULL), the current FDT is
+ * copied and the KHO properties are appended to /chosen.
+ *
+ * On ACPI-only systems (initial_boot_params == NULL), a minimal FDT
+ * containing only /chosen is built from scratch. machine_kexec() updates
+ * the EFI config table DEVICE_TREE_GUID entry to point to this segment so
+ * that the second kernel's fdt_setup() can find and parse it.
*/
static int kho_load_fdt(struct kimage *image)
{
@@ -143,24 +154,151 @@ static int kho_load_fdt(struct kimage *image)
* once the kexec image has been loaded.
*/
fdt_pack(fdt);
+ } else {
+ /*
+ * ACPI boot: build a minimal FDT containing only /chosen with
+ * the two KHO properties. No system FDT is available to copy.
+ */
- kbuf.buffer = fdt;
- kbuf.bufsz = fdt_totalsize(fdt);
- kbuf.memsz = kbuf.bufsz;
- kbuf.buf_align = PAGE_SIZE;
- kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+ __be64 prop[2];
- ret = kexec_add_buffer(&kbuf);
- if (ret)
+ fdt_size = SZ_1K;
+ fdt = kvmalloc(fdt_size, GFP_KERNEL);
+ if (!fdt)
+ return -ENOMEM;
+
+ ret = fdt_create(fdt, fdt_size);
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_finish_reservemap(fdt);
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_begin_node(fdt, ""); /* root */
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_property_u32(fdt, "#address-cells", 2);
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_property_u32(fdt, "#size-cells", 2);
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_begin_node(fdt, "chosen");
+ if (ret < 0)
goto out_free;
- image->arch.fdt = fdt;
- image->arch.fdt_mem = kbuf.mem;
- return 0;
- } else {
- return -EINVAL;
+ prop[0] = cpu_to_be64(image->kho.fdt);
+ prop[1] = cpu_to_be64(PAGE_SIZE);
+ ret = fdt_property(fdt, "linux,kho-fdt", prop, sizeof(prop));
+ if (ret < 0)
+ goto out_free;
+
+ prop[0] = cpu_to_be64(image->kho.scratch->mem);
+ prop[1] = cpu_to_be64(image->kho.scratch->bufsz);
+ ret = fdt_property(fdt, "linux,kho-scratch", prop, sizeof(prop));
+ if (ret < 0)
+ goto out_free;
+
+ ret = fdt_end_node(fdt); /* chosen */
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_end_node(fdt); /* root */
+ if (ret < 0)
+ goto out_free;
+ ret = fdt_finish(fdt);
+ if (ret < 0)
+ goto out_free;
}
+ kbuf.buffer = fdt;
+ kbuf.bufsz = fdt_totalsize(fdt);
+ kbuf.memsz = kbuf.bufsz;
+ kbuf.buf_align = PAGE_SIZE;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+
+ ret = kexec_add_buffer(&kbuf);
+ if (ret)
+ goto out_free;
+
+ image->arch.fdt = fdt;
+ image->arch.fdt_mem = kbuf.mem;
+
+ /*
+ * On ACPI-only systems DEVICE_TREE_GUID is not in the EFI config
+ * table, so the second kernel's efi_fdt_pointer() cannot locate the
+ * KHO FDT. Build a new EFI config table with DEVICE_TREE_GUID added
+ * and load it as a kexec segment; machine_kexec() will update
+ * st->tables / st->nr_tables to point to it before jumping.
+ */
+
+ /*
+ * fw_arg2 is the EFI system table physical address passed by the
+ * firmware/bootloader. Use it directly here because
+ * image->arch.systable_ptr is set later in machine_kexec_prepare(),
+ * which runs after load_other_segments() / kho_load_fdt().
+ */
+ if (!initial_boot_params && fw_arg2) {
+ efi_system_table_t *st =
+ (efi_system_table_t *)TO_CACHE(fw_arg2);
+ efi_config_table_t *ct =
+ (efi_config_table_t *)TO_CACHE((unsigned long)st->tables);
+ unsigned long i;
+ bool found = false;
+
+ /*
+ * Scan the original config table;
+ * DEVICE_TREE_GUID is absent on ACPI-only systems.
+ */
+ for (i = 0; i < st->nr_tables; i++) {
+ if (!efi_guidcmp(ct[i].guid, DEVICE_TREE_GUID)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ size_t old_sz = st->nr_tables * sizeof(efi_config_table_t);
+ size_t new_sz = old_sz + sizeof(efi_config_table_t);
+ efi_config_table_t *new_ct;
+ struct kexec_buf tbuf = {
+ .image = image,
+ .buf_min = 0,
+ .buf_max = ULONG_MAX,
+ .top_down = true,
+ };
+
+ /*
+ * Allocate a new table with n+1 entries and append
+ * the DEVICE_TREE_GUID entry.
+ */
+ new_ct = kvmalloc(new_sz, GFP_KERNEL);
+ if (!new_ct)
+ return -ENOMEM;
+
+ memcpy(new_ct, ct, old_sz);
+ new_ct[st->nr_tables].guid = DEVICE_TREE_GUID;
+ new_ct[st->nr_tables].table = (void *)image->arch.fdt_mem;
+
+ /* Register the new config table as a kexec segment. */
+ tbuf.buffer = new_ct;
+ tbuf.bufsz = new_sz;
+ tbuf.memsz = new_sz;
+ tbuf.buf_align = sizeof(void *);
+ tbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+
+ ret = kexec_add_buffer(&tbuf);
+ if (ret) {
+ kvfree(new_ct);
+ return ret;
+ }
+
+ image->arch.efi_tables = new_ct;
+ image->arch.efi_tables_mem = tbuf.mem;
+ image->arch.efi_tables_cnt = st->nr_tables + 1;
+ }
+ }
+
+ return 0;
+
out_free:
kvfree(fdt);
return ret;
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 839b23edee87..c82067d1dc75 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -286,8 +286,27 @@ static void __init fdt_setup(void)
void *fdt_pointer;
/* ACPI-based systems do not require parsing fdt */
- if (acpi_os_get_root_pointer())
+ if (acpi_os_get_root_pointer()) {
+#ifdef CONFIG_KEXEC_HANDOVER
+ /*
+ * On a KHO kexec boot the first kernel builds a minimal FDT
+ * containing only /chosen with linux,kho-fdt and
+ * linux,kho-scratch, and switches the EFI config table to a
+ * new one that includes a DEVICE_TREE_GUID entry pointing to
+ * it. Use efi_fdt_pointer() to detect this case.
+ *
+ * Call early_init_dt_scan() to let early_init_dt_check_kho()
+ * consume the KHO data, then reset initial_boot_params so the
+ * rest of the ACPI boot path is not confused by this FDT.
+ */
+ fdt_pointer = efi_fdt_pointer();
+ if (fdt_pointer && !fdt_check_header(fdt_pointer)) {
+ early_init_dt_scan(fdt_pointer, __pa(fdt_pointer));
+ initial_boot_params = NULL;
+ }
+#endif
return;
+ }
/* Prefer to use built-in dtb, checking its legality first. */
if (IS_ENABLED(CONFIG_BUILTIN_DTB) && !fdt_check_header(__dtb_start))
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 3/3] selftests/kho: add LoongArch vmtest support
2026-06-01 9:39 ` [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based George Guo
2026-06-01 9:39 ` [PATCH v3 2/3] LoongArch: kexec: add KHO support for ACPI-only George Guo
@ 2026-06-01 9:39 ` George Guo
2026-06-14 10:23 ` Mike Rapoport
2026-07-13 13:53 ` [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based Pratyush Yadav
2 siblings, 1 reply; 9+ messages in thread
From: George Guo @ 2026-06-01 9:39 UTC (permalink / raw)
To: Huacai Chen, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
Shuah Khan
Cc: George Guo, WANG Xuerui, Alexander Graf, loongarch, linux-kernel,
kexec, linux-mm, linux-kselftest, Kexin Liu
From: George Guo <guodongtai@kylinos.cn>
Add loongarch.conf to configure QEMU's LoongArch virt machine with a
la464 CPU, enable the 8250 serial console, and set the kernel image
to vmlinux.efi. Extend vmtest.sh to recognise loongarch64 as a
supported target and map it to the 'loongarch' kernel arch name.
QEMU's LoongArch virt machine provides no ACPI tables and relies on
FDT to describe hardware. Without 'earlycon' on the kernel command
line, the FDT is not scanned for a console UART, no output reaches
the console, and vmtest.sh's console log stays empty causing the test
to always fail. Add 'earlycon' to KERNEL_CMDLINE in loongarch.conf.
QEMU's LoongArch virt machine has no i8042 PS/2 controller. When PNP
detection finds nothing, i8042_init() falls back to probing the ports
directly. On LoongArch the I/O ports are memory-mapped, and the i8042
port addresses are not backed by any device on the virt machine, so
i8042_flush() takes a page fault and the kernel panics:
i8042: PNP: No PS/2 controller found.
i8042: Probing ports directly.
CPU 0 Unable to handle kernel paging request at virtual address ffff800000008064
ERA: i8042_flush+0x50/0x198
RA: i8042_init+0x2a8/0x35c
Kernel panic - not syncing: Attempted to kill init!
Disable SERIO_I8042 and its dependents (KEYBOARD_ATKBD, MOUSE_PS2) in
the QEMU_KCONFIG fragment to prevent the driver from being built.
All three options are scoped to loongarch.conf; no other architecture
is affected.
QEMU provides no EFI runtime services on LoongArch, so machine_restart()
falls through to an infinite idle loop after kexec. Set QEMU_TIMEOUT=120
in loongarch.conf so vmtest.sh wraps the QEMU invocation with timeout(1),
which terminates QEMU after 120 seconds if it does not exit on its own.
Architectures that do not set QEMU_TIMEOUT are unaffected.
Co-developed-by: Kexin Liu <liukexin@kylinos.cn>
Signed-off-by: Kexin Liu <liukexin@kylinos.cn>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
---
tools/testing/selftests/kho/loongarch.conf | 13 ++++++++++++
tools/testing/selftests/kho/vmtest.sh | 23 +++++++++++++++-------
2 files changed, 29 insertions(+), 7 deletions(-)
create mode 100644 tools/testing/selftests/kho/loongarch.conf
diff --git a/tools/testing/selftests/kho/loongarch.conf b/tools/testing/selftests/kho/loongarch.conf
new file mode 100644
index 000000000000..68727654578d
--- /dev/null
+++ b/tools/testing/selftests/kho/loongarch.conf
@@ -0,0 +1,13 @@
+QEMU_CMD="qemu-system-loongarch64 -M virt -cpu la464"
+QEMU_KCONFIG="
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+"
+KERNEL_IMAGE="vmlinux.efi"
+KERNEL_CMDLINE="console=ttyS0 earlycon"
+# QEMU never exits after kexec on LoongArch (no EFI runtime services);
+# give the test a fixed time limit and let timeout(1) terminate QEMU.
+QEMU_TIMEOUT=120
diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh
index 49fdac8e8b15..918698b6dd2a 100755
--- a/tools/testing/selftests/kho/vmtest.sh
+++ b/tools/testing/selftests/kho/vmtest.sh
@@ -21,7 +21,7 @@ Options:
-d) path to the kernel build directory
-j) number of jobs for compilation, similar to -j in make
-t) run test for target_arch, requires CROSS_COMPILE set
- supported targets: aarch64, x86_64
+ supported targets: aarch64, x86_64, loongarch64
-h) display this help
EOF
}
@@ -107,12 +107,20 @@ function run_qemu() {
cmdline="$cmdline kho=on panic=-1"
- $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
- -accel kvm -accel hvf -accel tcg \
- -serial file:"$serial" \
- -append "$cmdline" \
- -kernel "$kernel" \
- -initrd "$initrd"
+ local qemu_args=(
+ -m 1G -smp 2 -no-reboot -nographic -nodefaults
+ -accel kvm -accel hvf -accel tcg
+ -serial file:"$serial"
+ -append "$cmdline"
+ -kernel "$kernel"
+ -initrd "$initrd"
+ )
+
+ if [[ -n "${QEMU_TIMEOUT:-}" ]]; then
+ timeout "$QEMU_TIMEOUT" $qemu_cmd "${qemu_args[@]}" || true
+ else
+ $qemu_cmd "${qemu_args[@]}"
+ fi
grep "KHO restore succeeded" "$serial" &> /dev/null || fail "KHO failed"
}
@@ -123,6 +131,7 @@ function target_to_arch() {
case $target in
aarch64) echo "arm64" ;;
x86_64) echo "x86" ;;
+ loongarch64) echo "loongarch" ;;
*) skip "architecture $target is not supported"
esac
}
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 3/3] selftests/kho: add LoongArch vmtest support
2026-06-01 9:39 ` [PATCH v3 3/3] selftests/kho: add LoongArch vmtest support George Guo
@ 2026-06-14 10:23 ` Mike Rapoport
0 siblings, 0 replies; 9+ messages in thread
From: Mike Rapoport @ 2026-06-14 10:23 UTC (permalink / raw)
To: George Guo
Cc: Huacai Chen, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
Shuah Khan, George Guo, WANG Xuerui, Alexander Graf, loongarch,
linux-kernel, kexec, linux-mm, linux-kselftest, Kexin Liu
On Mon, 01 Jun 2026 17:39:30 +0800, George Guo <dongtai.guo@linux.dev> wrote:
Hi,
> Add loongarch.conf to configure QEMU's LoongArch virt machine with a
Please spell out "virtual machine" here and below or use VM abbrevation.
>
>
> diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh
> index 49fdac8e8b15..918698b6dd2a 100755
> --- a/tools/testing/selftests/kho/vmtest.sh
> +++ b/tools/testing/selftests/kho/vmtest.sh
> @@ -107,12 +107,20 @@ function run_qemu() {
> [ ... skip 14 lines ... ]
> + -kernel "$kernel"
> + -initrd "$initrd"
> + )
> +
> + if [[ -n "${QEMU_TIMEOUT:-}" ]]; then
> + timeout "$QEMU_TIMEOUT" $qemu_cmd "${qemu_args[@]}" || true
Runnig with timeout can be actually useful for other architecures. Let's
make a local variable for timeout of 120 seconds and always run qemu with timeout.
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based
2026-06-01 9:39 ` [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based George Guo
2026-06-01 9:39 ` [PATCH v3 2/3] LoongArch: kexec: add KHO support for ACPI-only George Guo
2026-06-01 9:39 ` [PATCH v3 3/3] selftests/kho: add LoongArch vmtest support George Guo
@ 2026-07-13 13:53 ` Pratyush Yadav
2026-07-14 12:17 ` Huacai Chen
2 siblings, 1 reply; 9+ messages in thread
From: Pratyush Yadav @ 2026-07-13 13:53 UTC (permalink / raw)
To: George Guo
Cc: Huacai Chen, Mike Rapoport, Pasha Tatashin, Pratyush Yadav,
Shuah Khan, George Guo, WANG Xuerui, Alexander Graf, loongarch,
linux-kernel, kexec, linux-mm, linux-kselftest, Kexin Liu
On Mon, Jun 01 2026, George Guo wrote:
> From: George Guo <guodongtai@kylinos.cn>
>
> Enable Kexec Handover (KHO) on LoongArch64 for FDT-based systems.
>
> - Kconfig: select ARCH_SUPPORTS_KEXEC_HANDOVER for CONFIG_64BIT
> - kexec.h: add fdt/fdt_mem fields to kimage_arch to hold the KHO FDT
> kexec segment virtual and physical addresses
> - machine_kexec_file.c: add kho_load_fdt() which copies the running
> kernel's FDT (initial_boot_params), appends linux,kho-fdt and
> linux,kho-scratch properties to /chosen, and loads the result as a
> kexec segment; called from load_other_segments(). Returns -EINVAL
> when initial_boot_params is NULL (ACPI-only boot) since that path
> requires separate handling.
> - machine_kexec.c: before jumping to the new kernel, update the
> DEVICE_TREE_GUID entry in the EFI config table to point to the KHO
> FDT segment so the second kernel finds it via efi_fdt_pointer() and
> early_init_dt_check_kho() calls kho_populate()
>
> Co-developed-by: Kexin Liu <liukexin@kylinos.cn>
> Signed-off-by: Kexin Liu <liukexin@kylinos.cn>
> Signed-off-by: George Guo <guodongtai@kylinos.cn>
> ---
> arch/loongarch/Kconfig | 3 +
> arch/loongarch/include/asm/kexec.h | 4 +
> arch/loongarch/kernel/machine_kexec.c | 27 +++++
> arch/loongarch/kernel/machine_kexec_file.c | 118 +++++++++++++++++++++
> 4 files changed, 152 insertions(+)
>
> diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> index 606597da46b8..d494418545f5 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -684,6 +684,9 @@ config ARCH_SUPPORTS_KEXEC
> config ARCH_SUPPORTS_KEXEC_FILE
> def_bool 64BIT
>
> +config ARCH_SUPPORTS_KEXEC_HANDOVER
> + def_bool 64BIT
> +
> config ARCH_SELECTS_KEXEC_FILE
> def_bool 64BIT
> depends on KEXEC_FILE
> diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
> index 209fa43222e1..adf54bfcdd49 100644
> --- a/arch/loongarch/include/asm/kexec.h
> +++ b/arch/loongarch/include/asm/kexec.h
> @@ -39,6 +39,10 @@ struct kimage_arch {
> unsigned long efi_boot;
> unsigned long cmdline_ptr;
> unsigned long systable_ptr;
> +#ifdef CONFIG_KEXEC_HANDOVER
> + void *fdt; /* virtual address of KHO FDT segment buffer */
> + unsigned long fdt_mem; /* physical address of KHO FDT segment */
> +#endif
> };
>
> #ifdef CONFIG_KEXEC_FILE
> diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> index ad27fef098f1..98529c71d001 100644
> --- a/arch/loongarch/kernel/machine_kexec.c
> +++ b/arch/loongarch/kernel/machine_kexec.c
> @@ -6,6 +6,7 @@
> */
> #include <linux/compiler.h>
> #include <linux/cpu.h>
> +#include <linux/efi.h>
> #include <linux/kexec.h>
> #include <linux/crash_dump.h>
> #include <linux/delay.h>
> @@ -289,6 +290,32 @@ void machine_kexec(struct kimage *image)
> pr_notice("We will call new kernel at 0x%lx\n", start_addr);
> pr_notice("Bye ...\n");
>
> +#ifdef CONFIG_KEXEC_HANDOVER
> + /*
> + * Point the EFI FDTPTR config table entry at the modified FDT so the
> + * second kernel picks up the linux,kho-fdt and linux,kho-scratch
> + * properties via early_init_dt_check_kho().
> + */
> + if (internal->fdt_mem) {
> + /*
> + * FDT-based system: DEVICE_TREE_GUID already exists in the EFI
> + * config table; just update its pointer to our KHO FDT.
> + */
> + efi_system_table_t *st =
> + (efi_system_table_t *)TO_CACHE(systable_ptr);
> + efi_config_table_t *ct =
> + (efi_config_table_t *)TO_CACHE((unsigned long)st->tables);
> + unsigned long i;
> +
> + for (i = 0; i < st->nr_tables; i++) {
> + if (!efi_guidcmp(ct[i].guid, DEVICE_TREE_GUID)) {
> + ct[i].table = (void *)internal->fdt_mem;
> + break;
> + }
> + }
> + }
> +#endif
Honestly this and the ACPI stuff looks worse to me than what your
previous version did. Now I am not an expert on EFI and architecture
stuff, and know nothing about Loongarch, but to me this looks hacky and
I am not sure if it is doing the right thing.
I think you should get some alignment with Loongarch maintainers on what
the kexec boot protocol looks like. It looked odd to me, but if the
Loongarch maintainers are fine with using the kernel cmdline for
bootloader to pass data to the kernel, then I think we should go back to
that.
Huacai, do you have any thoughts? For KHO we essentially need a way for
the pre-kexec kernel to tell the post-kexec kernel about a blob of
memory that has some information it can use. For x86, we do that via
setup data. See arch/x86/include/uapi/asm/setup_data.h and struct
kho_data for example. On arm64, we use the boot FDT's /chosen node. See
kho_add_chosen() in drivers/of/kexec.c.
Ideally, all device tree platforms should use the FDT path. But
Loongarch also has ACPI only and I don't know what a good idea for that
is.
So, do you have any suggestions on where to best place a pointer to this
blob of data on Loongarch? v1 of this series put it in the kernel
commandline, but I found that odd and asked if it can be done via DT
instead. But to me, this code looks even more hacky.
> +
> /* Make reboot code buffer available to the boot CPU. */
> flush_cache_all();
>
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based
2026-07-13 13:53 ` [PATCH v3 1/3] LoongArch: kexec: add KHO support for FDT-based Pratyush Yadav
@ 2026-07-14 12:17 ` Huacai Chen
0 siblings, 0 replies; 9+ messages in thread
From: Huacai Chen @ 2026-07-14 12:17 UTC (permalink / raw)
To: Pratyush Yadav
Cc: George Guo, Mike Rapoport, Pasha Tatashin, Shuah Khan, George Guo,
WANG Xuerui, Alexander Graf, loongarch, linux-kernel, kexec,
linux-mm, linux-kselftest, Kexin Liu
Hi, Pratyush,
On Mon, Jul 13, 2026 at 9:53 PM Pratyush Yadav <pratyush@kernel.org> wrote:
>
> On Mon, Jun 01 2026, George Guo wrote:
>
> > From: George Guo <guodongtai@kylinos.cn>
> >
> > Enable Kexec Handover (KHO) on LoongArch64 for FDT-based systems.
> >
> > - Kconfig: select ARCH_SUPPORTS_KEXEC_HANDOVER for CONFIG_64BIT
> > - kexec.h: add fdt/fdt_mem fields to kimage_arch to hold the KHO FDT
> > kexec segment virtual and physical addresses
> > - machine_kexec_file.c: add kho_load_fdt() which copies the running
> > kernel's FDT (initial_boot_params), appends linux,kho-fdt and
> > linux,kho-scratch properties to /chosen, and loads the result as a
> > kexec segment; called from load_other_segments(). Returns -EINVAL
> > when initial_boot_params is NULL (ACPI-only boot) since that path
> > requires separate handling.
> > - machine_kexec.c: before jumping to the new kernel, update the
> > DEVICE_TREE_GUID entry in the EFI config table to point to the KHO
> > FDT segment so the second kernel finds it via efi_fdt_pointer() and
> > early_init_dt_check_kho() calls kho_populate()
> >
> > Co-developed-by: Kexin Liu <liukexin@kylinos.cn>
> > Signed-off-by: Kexin Liu <liukexin@kylinos.cn>
> > Signed-off-by: George Guo <guodongtai@kylinos.cn>
> > ---
> > arch/loongarch/Kconfig | 3 +
> > arch/loongarch/include/asm/kexec.h | 4 +
> > arch/loongarch/kernel/machine_kexec.c | 27 +++++
> > arch/loongarch/kernel/machine_kexec_file.c | 118 +++++++++++++++++++++
> > 4 files changed, 152 insertions(+)
> >
> > diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> > index 606597da46b8..d494418545f5 100644
> > --- a/arch/loongarch/Kconfig
> > +++ b/arch/loongarch/Kconfig
> > @@ -684,6 +684,9 @@ config ARCH_SUPPORTS_KEXEC
> > config ARCH_SUPPORTS_KEXEC_FILE
> > def_bool 64BIT
> >
> > +config ARCH_SUPPORTS_KEXEC_HANDOVER
> > + def_bool 64BIT
> > +
> > config ARCH_SELECTS_KEXEC_FILE
> > def_bool 64BIT
> > depends on KEXEC_FILE
> > diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
> > index 209fa43222e1..adf54bfcdd49 100644
> > --- a/arch/loongarch/include/asm/kexec.h
> > +++ b/arch/loongarch/include/asm/kexec.h
> > @@ -39,6 +39,10 @@ struct kimage_arch {
> > unsigned long efi_boot;
> > unsigned long cmdline_ptr;
> > unsigned long systable_ptr;
> > +#ifdef CONFIG_KEXEC_HANDOVER
> > + void *fdt; /* virtual address of KHO FDT segment buffer */
> > + unsigned long fdt_mem; /* physical address of KHO FDT segment */
> > +#endif
> > };
> >
> > #ifdef CONFIG_KEXEC_FILE
> > diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
> > index ad27fef098f1..98529c71d001 100644
> > --- a/arch/loongarch/kernel/machine_kexec.c
> > +++ b/arch/loongarch/kernel/machine_kexec.c
> > @@ -6,6 +6,7 @@
> > */
> > #include <linux/compiler.h>
> > #include <linux/cpu.h>
> > +#include <linux/efi.h>
> > #include <linux/kexec.h>
> > #include <linux/crash_dump.h>
> > #include <linux/delay.h>
> > @@ -289,6 +290,32 @@ void machine_kexec(struct kimage *image)
> > pr_notice("We will call new kernel at 0x%lx\n", start_addr);
> > pr_notice("Bye ...\n");
> >
> > +#ifdef CONFIG_KEXEC_HANDOVER
> > + /*
> > + * Point the EFI FDTPTR config table entry at the modified FDT so the
> > + * second kernel picks up the linux,kho-fdt and linux,kho-scratch
> > + * properties via early_init_dt_check_kho().
> > + */
> > + if (internal->fdt_mem) {
> > + /*
> > + * FDT-based system: DEVICE_TREE_GUID already exists in the EFI
> > + * config table; just update its pointer to our KHO FDT.
> > + */
> > + efi_system_table_t *st =
> > + (efi_system_table_t *)TO_CACHE(systable_ptr);
> > + efi_config_table_t *ct =
> > + (efi_config_table_t *)TO_CACHE((unsigned long)st->tables);
> > + unsigned long i;
> > +
> > + for (i = 0; i < st->nr_tables; i++) {
> > + if (!efi_guidcmp(ct[i].guid, DEVICE_TREE_GUID)) {
> > + ct[i].table = (void *)internal->fdt_mem;
> > + break;
> > + }
> > + }
> > + }
> > +#endif
>
> Honestly this and the ACPI stuff looks worse to me than what your
> previous version did. Now I am not an expert on EFI and architecture
> stuff, and know nothing about Loongarch, but to me this looks hacky and
> I am not sure if it is doing the right thing.
>
> I think you should get some alignment with Loongarch maintainers on what
> the kexec boot protocol looks like. It looked odd to me, but if the
> Loongarch maintainers are fine with using the kernel cmdline for
> bootloader to pass data to the kernel, then I think we should go back to
> that.
>
> Huacai, do you have any thoughts? For KHO we essentially need a way for
> the pre-kexec kernel to tell the post-kexec kernel about a blob of
> memory that has some information it can use. For x86, we do that via
> setup data. See arch/x86/include/uapi/asm/setup_data.h and struct
> kho_data for example. On arm64, we use the boot FDT's /chosen node. See
> kho_add_chosen() in drivers/of/kexec.c.
>
> Ideally, all device tree platforms should use the FDT path. But
> Loongarch also has ACPI only and I don't know what a good idea for that
> is.
>
> So, do you have any suggestions on where to best place a pointer to this
> blob of data on Loongarch? v1 of this series put it in the kernel
> commandline, but I found that odd and asked if it can be done via DT
> instead. But to me, this code looks even more hacky.
I don't know which is the best way, but I can give some information.
ARM64 and RISC-V create a FDT to contain all needed boot information
(EFI system table, command line, etc.) in efistub. In other words,
both ACPI booting and FDT booting have an existing FDT to pass the
blob.
But LoongArch is different, the efistub doesn't create a FDT, instead
it passes the EFI system table and command line to the core kernel
directly.
Huacai
>
> > +
> > /* Make reboot code buffer available to the boot CPU. */
> > flush_cache_all();
> >
> [...]
>
> --
> Regards,
> Pratyush Yadav
^ permalink raw reply [flat|nested] 9+ messages in thread