Skip to contentSkip to conversation

LoongArch: add KHO support and selftests

PATCH Superseded George Guo 5 participants 18 messages Sep 4 – Oct 21

Subsystems (8)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

George Guo

author
#0 lore raw

v5 cover LoongArch: add KHO support and selftests

This series enables Kexec HandOver (KHO) on 64-bit LoongArch and adds LoongArch coverage to the KHO QEMU selftest. KHO is the remaining architecture gate needed by Live Update (LUO) on LoongArch.

The transport is the central problem. Arm64 and riscv can pass the KHO state FDT and scratch area through properties under /chosen in a boot FDT. LoongArch boots through EFI without a boot FDT, so that path is not available.

EFI KHO channel:

v5 reworks the EFI transport following Pratyush's and Huacai's reviews [1, 2]. Instead of rebuilding the EFI configuration table in LoongArch code and switching st->tables before kexec, the common EFI stub allocates and installs a persistent table under LINUX_EFI_KEXEC_HANDOVER_GUID. This follows the model used by LINUX_EFI_MEMRESERVE_TABLE_GUID.

The common EFI table parser reserves the stub-allocated table, reads it during early boot, and calls kho_populate(). An early initcall keeps the table persistently mapped so it can also be updated on the crash kexec path. The implementation is architecture-independent; LoongArch only selects EFI_KHO when KEXEC_HANDOVER is enabled.

The EFI table is global, but kexec can keep separate normal and crash images and can replace a loaded candidate. Updating the table while a candidate image is being loaded could therefore leave it pointing at a failed candidate while the previously installed image remains the one that will be executed. v5 records the KHO data in struct kimage and synchronizes the channel from the image selected for execution. Images without KHO data, including legacy and crash images, clear the channel so the next kernel boots cold rather than reviving stale state.

The GUID name is changed to LINUX_EFI_KEXEC_HANDOVER_GUID as suggested by Huacai and Pratyush [3]. Existing x86 KHO support continues to use its setup_data transport. Besides supporting non-UEFI boot, that entry is consumed by the x86 decompressor before normal EFI table parsing, so KASLR only uses KHO scratch areas and does not overwrite preserved memory. The new channel is installed by the generic EFI-stub entry path and relies on EFI_GENERIC_STUB, which x86 does not select. Moving x86 would therefore require installing the table from the x86-specific EFI stub and scanning it in the decompressor, not just selecting EFI_KHO.

LoongArch enablement and build fix:

The architecture patch now only enables ARCH_SUPPORTS_KEXEC_HANDOVER and selects the generic EFI channel. No LoongArch setup reader, kexec writer, or EFI system-table replacement remains.

The linux/mm.h build fix is moved from luo_session.c to kho_block.c, where the virt_to_phys() and phys_to_virt() calls reside after the liveupdate refactoring. This addresses Pratyush's review [4]. Adding linux/mm.h to asm/io.h was previously attempted, but creates an include cycle under CONFIG_KFENCE [5]. The fix precedes LoongArch enablement so every intermediate commit builds with CONFIG_KFENCE=y.

Selftest:

The LoongArch vmtest boots vmlinux.efi through EDK2 because the initial EFI stub invocation installs the channel being tested. QEMU_EFI can override the firmware filename for distributions that install it under a different name or path.

CONFIG_ACPI_SPCR_TABLE lets the bare earlycon parameter obtain the UART description from EDK2's SPCR table. CONFIG_PCI_HOST_GENERIC keeps i8042 enabled while ensuring that the QEMU virt machine's PCI I/O space is mapped before the legacy fallback probe, addressing Huacai's concern that the same kernel configuration should remain usable for hosts and guests.

With EFI runtime reset services available, panic=-1 and QEMU's existing -no-reboot option terminate the test normally. The generic QEMU runner therefore remains unchanged and does not mask failures by forcibly terminating QEMU after a timeout.

The LoongArch vmtest uses the default KHO scratch-sizing path. This series is based on the generic fix that calculates per-node scratch sizes before scratch allocation [6].

The KHO vmtest passes on:

* LoongArch with KVM using QEMU_EFI.fd from edk2-loongarch64.
* x86_64 with KVM, as regression coverage for the generic kexec/KHO changes.

Patch layout:

1. Add the generic EFI KHO channel and its ABI.
2. Synchronize the channel from the selected image at execution.
3. Fix the kho_block.c header dependency exposed by LoongArch/KFENCE.
4. Enable KHO on 64-bit LoongArch through the generic EFI channel.
5. Add LoongArch to the KHO QEMU selftest.

Changes since v4:

* Allocate and install the KHO table from the common EFI stub, following the EFI memreserve-table model (Pratyush).
* Parse, reserve, map, and update the channel in generic EFI code; remove

    the LoongArch-specific reader, writer, and st->tables replacement
    (Pratyush, Huacai).

* Synchronize the global channel at execution rather than image load; clear it for cold and crash images and use the scratch payload size.
* Rename the GUID to LINUX_EFI_KEXEC_HANDOVER_GUID (Huacai, Pratyush).
* Move the linux/mm.h include from luo_session.c to the actual caller, kho_block.c, and place the fix before architecture enablement (Pratyush, Huacai).
* Boot the vmtest through EDK2, allow QEMU_EFI to override the firmware, and use vmlinux.efi to exercise the EFI stub and channel.
* Keep i8042 enabled and select PCI_HOST_GENERIC instead of disabling the host configuration in the selftest (Huacai).
* Enable ACPI_SPCR_TABLE and use the SPCR-provided early console.
* Exercise the default KHO scratch-sizing path in the LoongArch vmtest; depend on the separately posted generic sizing fix [6].
* Drop the generic QEMU timeout now that EFI runtime reset services make the LoongArch guest terminate normally.
* Rebase onto Linux 7.3-rc1.

[1] Pratyush Yadav:

    https://lore.kernel.org/r/[email protected]/

[2] Huacai Chen:
https://lore.kernel.org/r/CAAhV-H4PKRNCa4g=6TGepP+trtM82JiMoWgVr3O7PqbZYP9uGw@mail.gmail.com/
[3] https://lore.kernel.org/r/[email protected]/
[4] https://lore.kernel.org/r/[email protected]/
[5] https://lore.kernel.org/r/[email protected]/
[6] https://lore.kernel.org/loongarch/[email protected]/

Previous version:

v4: https://lore.kernel.org/loongarch/[email protected]/

George Guo (5):
efi: add a KHO configuration table channel
liveupdate: synchronize EFI KHO channel at execution
liveupdate: kho_block: include linux/mm.h for virt/phys translation
LoongArch: enable kexec handover (KHO)
selftests/kho: add LoongArch vmtest support

 arch/loongarch/Kconfig                     |  4 ++
 drivers/firmware/efi/Kconfig               | 12 ++++
 drivers/firmware/efi/efi.c                 | 78 ++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c    | 25 +++++++
 include/linux/efi.h                        | 36 ++++++++++
 kernel/crash_core.c                        |  7 ++
 kernel/kexec_core.c                        |  5 ++
 kernel/kexec_internal.h                    |  3 +
 kernel/liveupdate/kexec_handover.c         | 33 +++++++++
 kernel/liveupdate/kho_block.c              |  1 +
 tools/testing/selftests/kho/loongarch.conf | 11 +++
 tools/testing/selftests/kho/vmtest.sh      |  3 +-
 12 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
prerequisite-patch-id: a2f06addb17cc379b9f98674f087a1642588dc6e

Signature · 1 line
2.53.0
author
#1 lore raw

PATCH v5 1/5 efi: add a KHO configuration table channel

From: George Guo <[email protected]>

Add an architecture-agnostic EFI configuration table channel for kexec handover (KHO): a LINUX_EFI_KEXEC_HANDOVER_GUID table entry pointing at a struct linux_efi_kho_data that carries the KHO state FDT and scratch area addresses from one kernel to the next.

This is the channel for architectures that boot through EFI without a device tree (e.g. LoongArch), where the /chosen linux,kho-fdt and linux,kho-scratch properties read by early_init_dt_check_kho() are not available. Architectures with a boot FDT (arm64, riscv) keep using the FDT path and do not select this.

The design mirrors the LINUX_EFI_MEMRESERVE_TABLE_GUID channel:

- The EFI stub allocates and installs the table once at boot (install_kho_table(), next to install_memreserve_table()), so the config table entry is inherited across kexec for free.

- The reader is a common_tables[] entry in efi_config_parse_tables(). It reserves the stub-allocated table with memblock_reserve(), the same way the memreserve entries are reserved there, so the table is neither handed out by the buddy allocator nor placed on by kexec segments. It then maps the table and calls kho_populate(). No arch-specific setup.c hook is needed.

- efi_kho_update() rewrites the table contents in place before a kexec; the config table array is never rebuilt and st->tables is never switched, unlike the per-arch approach it replaces. The table stays persistently mapped from an early_initcall, the same way the memreserve root is, so the update also works on the crash kexec path.

Gated behind CONFIG_EFI_KHO, selected by architectures that use this channel.

---
 drivers/firmware/efi/Kconfig            | 12 ++++
 drivers/firmware/efi/efi.c              | 78 +++++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c | 25 ++++++++
 include/linux/efi.h                     | 36 ++++++++++++
 4 files changed, 151 insertions(+)
drivers/firmware/efi/Kconfig +12 -0
index 29e0729299f5..d6c1372484b4 100644
@@ -314,6 +314,18 @@ config EFI_SBAT_FILE
 
 	  If unsure, leave blank.
 
+config EFI_KHO
+	bool
+	depends on EFI_STUB && EFI_GENERIC_STUB && KEXEC_HANDOVER
+	help
+	  Carry the KHO state (the KHO state FDT and the scratch area) from
+	  one kernel to the next across kexec via an EFI configuration table
+	  entry under LINUX_EFI_KEXEC_HANDOVER_GUID, for architectures that
+	  boot through EFI without a device tree (e.g. LoongArch).
+
+	  Architectures with a boot FDT (arm64, riscv) use the /chosen FDT
+	  path instead and do not select this.
+
 endmenu
 
 config UEFI_CPER
drivers/firmware/efi/efi.c +78 -0

108 lines not on this page · raw message

drivers/firmware/efi/libstub/efi-stub.c +25 -0
index 42d6073bcd06..751f46280433 100644
@@ -100,6 +100,29 @@ static void install_memreserve_table(void)
 		efi_err("Failed to install memreserve config table!\n");
 }
 
+static void install_kho_table(void)
+{
+#ifdef CONFIG_EFI_KHO
+	struct linux_efi_kho_data *kho;
+	efi_guid_t kho_table_guid = LINUX_EFI_KEXEC_HANDOVER_GUID;
+	efi_status_t status;
+
+	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*kho),
+			     (void **)&kho);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to allocate KHO config table!\n");
+		return;
+	}
+
+	*kho = (struct linux_efi_kho_data){};
+
+	status = efi_bs_call(install_configuration_table, &kho_table_guid,
+			     kho);
+	if (status != EFI_SUCCESS)
+		efi_err("Failed to install KHO config table!\n");
+#endif
+}
+
 static u32 get_supported_rt_services(void)
 {
 	const efi_rt_properties_table_t *rt_prop_table;
@@ -180,6 +203,8 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
 	install_memreserve_table();
 
+	install_kho_table();
+
 	status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
 
 	free_primary_display(dpy);
include/linux/efi.h +36 -0
index aa15ff88539b..564b3cbd5ccb 100644
@@ -422,6 +422,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_COCO_SECRET_AREA_GUID		EFI_GUID(0xadf956ad, 0xe98c, 0x484c,  0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47)
 #define LINUX_EFI_BOOT_MEMMAP_GUID		EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 #define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID	EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9,  0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31)
+#define LINUX_EFI_KEXEC_HANDOVER_GUID		EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)
 
 #define RISCV_EFI_BOOT_PROTOCOL_GUID		EFI_GUID(0xccd15fec, 0x6f73, 0x4eec,  0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
 
@@ -1273,6 +1274,41 @@ struct linux_efi_memreserve {
 
 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
 
+#ifdef CONFIG_EFI_KHO
+/*
+ * The LINUX_EFI_KEXEC_HANDOVER_GUID config table points to this structure.
+ * It carries the kexec handover (KHO) state from the current kernel to the
+ * next one: the addresses of the KHO state FDT and of the scratch area.
+ *
+ * This is the handover channel for architectures that boot through EFI
+ * without a device tree (e.g. LoongArch), where the /chosen linux,kho-fdt
+ * and linux,kho-scratch properties read by early_init_dt_check_kho() are not
+ * available.  The EFI stub allocates and installs the table once at boot;
+ * the current kernel updates its contents before a kexec, and the next
+ * kernel reads it back and calls kho_populate().
+ *
+ * The layout is an ABI between the two kernels and carries no version
+ * field: an incompatible change must use a new GUID.  The handover payload
+ * itself is versioned separately by the compatible string of the KHO state
+ * FDT, which kho_populate() checks.
+ */
+struct linux_efi_kho_data {
+	u64 fdt_addr;
+	u64 fdt_size;
+	u64 scratch_addr;
+	u64 scratch_size;
+} __packed;
+
+int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+		   phys_addr_t scratch_addr, u64 scratch_size);
+#else
+static inline int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+				 phys_addr_t scratch_addr, u64 scratch_size)
+{
+	return 0;
+}
+#endif
+
 /*
  * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table can be provided
  * to the kernel by an EFI boot loader. The table contains a packed
Signature · 1 line
2.53.0
maintainer
#2 lore raw

Re: [PATCH v5 1/5] efi: add a KHO configuration table channel

Hi, George,

Quoted 82 lines · George Guo

From: George Guo <[email protected]>

Add an architecture-agnostic EFI configuration table channel for kexec handover (KHO): a LINUX_EFI_KEXEC_HANDOVER_GUID table entry pointing at a struct linux_efi_kho_data that carries the KHO state FDT and scratch area addresses from one kernel to the next.

This is the channel for architectures that boot through EFI without a device tree (e.g. LoongArch), where the /chosen linux,kho-fdt and linux,kho-scratch properties read by early_init_dt_check_kho() are not available. Architectures with a boot FDT (arm64, riscv) keep using the FDT path and do not select this.

The design mirrors the LINUX_EFI_MEMRESERVE_TABLE_GUID channel:

- The EFI stub allocates and installs the table once at boot (install_kho_table(), next to install_memreserve_table()), so the config table entry is inherited across kexec for free.

- The reader is a common_tables[] entry in efi_config_parse_tables(). It reserves the stub-allocated table with memblock_reserve(), the same way the memreserve entries are reserved there, so the table is neither handed out by the buddy allocator nor placed on by kexec segments. It then maps the table and calls kho_populate(). No arch-specific setup.c hook is needed.

- efi_kho_update() rewrites the table contents in place before a kexec; the config table array is never rebuilt and st->tables is never switched, unlike the per-arch approach it replaces. The table stays persistently mapped from an early_initcall, the same way the memreserve root is, so the update also works on the crash kexec path.

Gated behind CONFIG_EFI_KHO, selected by architectures that use this channel.

---
 drivers/firmware/efi/Kconfig            | 12 ++++
 drivers/firmware/efi/efi.c              | 78 +++++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c | 25 ++++++++
 include/linux/efi.h                     | 36 ++++++++++++
 4 files changed, 151 insertions(+)
drivers/firmware/efi/Kconfig +12 -0
index 29e0729299f5..d6c1372484b4 100644
@@ -314,6 +314,18 @@ config EFI_SBAT_FILE
 
          If unsure, leave blank.
 
+config EFI_KHO
+       bool
+       depends on EFI_STUB && EFI_GENERIC_STUB && KEXEC_HANDOVER
+       help
+         Carry the KHO state (the KHO state FDT and the scratch area) from
+         one kernel to the next across kexec via an EFI configuration table
+         entry under LINUX_EFI_KEXEC_HANDOVER_GUID, for architectures that
+         boot through EFI without a device tree (e.g. LoongArch).
+
+         Architectures with a boot FDT (arm64, riscv) use the /chosen FDT
+         path instead and do not select this.
+
 endmenu
 
 config UEFI_CPER
drivers/firmware/efi/efi.c +1 -0
index 0327a39d31fa..6380cfab1493 100644
@@ -24,6 +24,7 @@
 #include <linux/initrd.h>
 #include <linux/io.h>
 #include <linux/kexec.h>
+#include <linux/kexec_handover.h>
 #include <linux/platform_device.h>
 #include <linux/random.h>
 #include <linux/reboot.h>

drivers/firmware/efi/efi.c unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR; · line 67

Quoted 5 lines
drivers/firmware/efi/efi.c +2 -0
@@ -62,6 +63,9 @@ unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
+#ifdef CONFIG_EFI_KHO
+static unsigned long __ro_after_init efi_kho_table_phys = EFI_INVALID_TABLE_ADDR;

I think it is better to define:
static unsigned long __initdata efi_kho = EFI_INVALID_TABLE_ADDR;

Quoted 28 lines
drivers/firmware/efi/efi.c +14 -0
+#endif
 
 extern unsigned long primary_display_table;
 
@@ -629,6 +633,9 @@ static const efi_config_table_type_t common_tables[] __initconst = {
        {EFI_TCG2_FINAL_EVENTS_TABLE_GUID,      &efi.tpm_final_log,     "TPMFinalLog"   },
        {EFI_CC_FINAL_EVENTS_TABLE_GUID,        &efi.tpm_final_log,     "CCFinalLog"    },
        {LINUX_EFI_MEMRESERVE_TABLE_GUID,       &mem_reserve,           "MEMRESERVE"    },
+#ifdef CONFIG_EFI_KHO
+       {LINUX_EFI_KEXEC_HANDOVER_GUID,         &efi_kho_table_phys,    "KHO"           },
+#endif
        {LINUX_EFI_INITRD_MEDIA_GUID,           &initrd,                "INITRD"        },
        {EFI_RT_PROPERTIES_TABLE_GUID,          &rt_prop,               "RTPROP"        },
 #ifdef CONFIG_OVMF_DEBUG_LOG
@@ -806,6 +813,31 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
                }
        }
 
+#ifdef CONFIG_EFI_KHO
+       if (efi_kho_table_phys != EFI_INVALID_TABLE_ADDR) {
+               struct linux_efi_kho_data *kho;
+
+               /*
+                * Reserve the stub-allocated table so it is neither handed
+                * out by the buddy allocator nor placed on by kexec
+                * segments, mirroring the memreserve handling above.  This
+                * runs on every boot, so it also protects the table in the
+                * next kernel until it reads it.

drivers/firmware/efi/efi.c int __init efi_config_parse_tables(const efi_config_table_t *config_tables, · line 835

Quoted 10 lines
drivers/firmware/efi/efi.c +10 -0
+                */
+               memblock_reserve(efi_kho_table_phys, sizeof(*kho));
+
+               kho = early_memremap(efi_kho_table_phys, sizeof(*kho));
+               if (kho) {
+                       if (kho->fdt_addr)
+                               kho_populate((phys_addr_t)kho->fdt_addr,
+                                            kho->fdt_size,
+                                            (phys_addr_t)kho->scratch_addr,
+                                            kho->scratch_size);

Now there is no 80 cols limit, you can just use

     kho_populate((phys_addr_t)kho->fdt_addr, kho->fdt_size,
              (phys_addr_t)kho->scratch_addr, kho->scratch_size);
Quoted 18 lines
drivers/firmware/efi/efi.c +11 -0
+                       early_memunmap(kho, sizeof(*kho));
+               }
+       }
+#endif
+
        if (rt_prop != EFI_INVALID_TABLE_ADDR) {
                efi_rt_properties_table_t *tbl;
 
@@ -1171,6 +1203,52 @@ static int __init efi_memreserve_root_init(void)
 }
 early_initcall(efi_memreserve_root_init);
 
+#ifdef CONFIG_EFI_KHO
+static struct linux_efi_kho_data *efi_kho_table __ro_after_init;
+
+static int __init efi_kho_table_init(void)
+{
+       if (efi_kho_table_phys == EFI_INVALID_TABLE_ADDR)

drivers/firmware/efi/efi.c static int __init efi_memreserve_root_init(void) · line 1221

Quoted 10 lines
drivers/firmware/efi/efi.c +10 -0
+               return 0;
+
+       /*
+        * Keep a persistent mapping of the table, the same way
+        * efi_memreserve_root_init() keeps the memreserve root mapped:
+        * efi_kho_update() is also called on the crash kexec path, where
+        * memremap() is no longer an option.
+        */
+       efi_kho_table = memremap(efi_kho_table_phys, sizeof(*efi_kho_table),
+                                MEMREMAP_WB);

The same, just write it in one line.

Quoted 40 lines
drivers/firmware/efi/efi.c +30 -0
+       WARN_ON_ONCE(!efi_kho_table);
+
+       return 0;
+}
+early_initcall(efi_kho_table_init);
+
+/*
+ * Update the KHO config table in place before a kexec, so the next kernel
+ * finds the current handover state.  Mirrors efi_mem_reserve_persistent():
+ * the config table entry was installed once by the EFI stub and is inherited
+ * across kexec, so only the table contents are rewritten here -- the config
+ * table array is never rebuilt and st->tables is never switched.
+ */
+int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+                  phys_addr_t scratch_addr, u64 scratch_size)
+{
+       struct linux_efi_kho_data *kho = efi_kho_table;
+
+       if (!kho)
+               return -ENODEV;
+
+       kho->fdt_addr           = fdt_addr;
+       kho->fdt_size           = fdt_size;
+       kho->scratch_addr       = scratch_addr;
+       kho->scratch_size       = scratch_size;
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_KEXEC
 static int update_efi_random_seed(struct notifier_block *nb,
                                  unsigned long code, void *unused)
drivers/firmware/efi/libstub/efi-stub.c +0 -0
index 42d6073bcd06..751f46280433 100644
@@ -100,6 +100,29 @@ static void install_memreserve_table(void)
                efi_err("Failed to install memreserve config table!\n");
 }

drivers/firmware/efi/libstub/efi-stub.c static void install_memreserve_table(void) · line 111

Quoted 10 lines
drivers/firmware/efi/libstub/efi-stub.c +9 -0
 
+static void install_kho_table(void)
+{
+#ifdef CONFIG_EFI_KHO
+       struct linux_efi_kho_data *kho;
+       efi_guid_t kho_table_guid = LINUX_EFI_KEXEC_HANDOVER_GUID;
+       efi_status_t status;
+
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*kho),
+                            (void **)&kho);

The same, just write it in one line.

drivers/firmware/efi/libstub/efi-stub.c static void install_memreserve_table(void) · line 120

Quoted 9 lines
drivers/firmware/efi/libstub/efi-stub.c +9 -0
+       if (status != EFI_SUCCESS) {
+               efi_err("Failed to allocate KHO config table!\n");
+               return;
+       }
+
+       *kho = (struct linux_efi_kho_data){};
+
+       status = efi_bs_call(install_configuration_table, &kho_table_guid,
+                            kho);

The same, just write it in one line.

Quoted 74 lines
drivers/firmware/efi/libstub/efi-stub.c +7 -0
+       if (status != EFI_SUCCESS)
+               efi_err("Failed to install KHO config table!\n");
+#endif
+}
+
 static u32 get_supported_rt_services(void)
 {
        const efi_rt_properties_table_t *rt_prop_table;
@@ -180,6 +203,8 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
        install_memreserve_table();
 
+       install_kho_table();
+
        status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
 
        free_primary_display(dpy);
include/linux/efi.h +36 -1
index aa15ff88539b..564b3cbd5ccb 100644
@@ -422,6 +422,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_COCO_SECRET_AREA_GUID                EFI_GUID(0xadf956ad, 0xe98c, 0x484c,  0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47)
 #define LINUX_EFI_BOOT_MEMMAP_GUID             EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 #define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID    EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9,  0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31)
+#define LINUX_EFI_KEXEC_HANDOVER_GUID          EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)
 
 #define RISCV_EFI_BOOT_PROTOCOL_GUID           EFI_GUID(0xccd15fec, 0x6f73, 0x4eec,  0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
 
@@ -1273,6 +1274,41 @@ struct linux_efi_memreserve {
 
 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
 
+#ifdef CONFIG_EFI_KHO
+/*
+ * The LINUX_EFI_KEXEC_HANDOVER_GUID config table points to this structure.
+ * It carries the kexec handover (KHO) state from the current kernel to the
+ * next one: the addresses of the KHO state FDT and of the scratch area.
+ *
+ * This is the handover channel for architectures that boot through EFI
+ * without a device tree (e.g. LoongArch), where the /chosen linux,kho-fdt
+ * and linux,kho-scratch properties read by early_init_dt_check_kho() are not
+ * available.  The EFI stub allocates and installs the table once at boot;
+ * the current kernel updates its contents before a kexec, and the next
+ * kernel reads it back and calls kho_populate().
+ *
+ * The layout is an ABI between the two kernels and carries no version
+ * field: an incompatible change must use a new GUID.  The handover payload
+ * itself is versioned separately by the compatible string of the KHO state
+ * FDT, which kho_populate() checks.
+ */
+struct linux_efi_kho_data {
+       u64 fdt_addr;
+       u64 fdt_size;
+       u64 scratch_addr;
+       u64 scratch_size;
+} __packed;
+
+int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+                  phys_addr_t scratch_addr, u64 scratch_size);
+#else
+static inline int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+                                phys_addr_t scratch_addr, u64 scratch_size)
+{
+       return 0;
+}
+#endif
+
 /*
  * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table can be provided
  * to the kernel by an EFI boot loader. The table contains a packed
--

2.53.0

maintainer
#3 lore raw

Re: [PATCH v5 1/5] efi: add a KHO configuration table channel

In reply to George Guo
Quoted 54 lines · George Guo

From: George Guo <[email protected]>

Add an architecture-agnostic EFI configuration table channel for kexec handover (KHO): a LINUX_EFI_KEXEC_HANDOVER_GUID table entry pointing at a struct linux_efi_kho_data that carries the KHO state FDT and scratch area addresses from one kernel to the next.

This is the channel for architectures that boot through EFI without a device tree (e.g. LoongArch), where the /chosen linux,kho-fdt and linux,kho-scratch properties read by early_init_dt_check_kho() are not available. Architectures with a boot FDT (arm64, riscv) keep using the FDT path and do not select this.

The design mirrors the LINUX_EFI_MEMRESERVE_TABLE_GUID channel:

- The EFI stub allocates and installs the table once at boot (install_kho_table(), next to install_memreserve_table()), so the config table entry is inherited across kexec for free.

- The reader is a common_tables[] entry in efi_config_parse_tables(). It reserves the stub-allocated table with memblock_reserve(), the same way the memreserve entries are reserved there, so the table is neither handed out by the buddy allocator nor placed on by kexec segments. It then maps the table and calls kho_populate(). No arch-specific setup.c hook is needed.

- efi_kho_update() rewrites the table contents in place before a kexec; the config table array is never rebuilt and st->tables is never switched, unlike the per-arch approach it replaces. The table stays persistently mapped from an early_initcall, the same way the memreserve root is, so the update also works on the crash kexec path.

Gated behind CONFIG_EFI_KHO, selected by architectures that use this channel.

---
 drivers/firmware/efi/Kconfig            | 12 ++++
 drivers/firmware/efi/efi.c              | 78 +++++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c | 25 ++++++++
 include/linux/efi.h                     | 36 ++++++++++++
 4 files changed, 151 insertions(+)
drivers/firmware/efi/Kconfig +1 -0
index 29e0729299f5..d6c1372484b4 100644
@@ -314,6 +314,18 @@ config EFI_SBAT_FILE
 
 	  If unsure, leave blank.
 
+config EFI_KHO

drivers/firmware/efi/Kconfig config EFI_SBAT_FILE · line 327

Quoted 10 lines
drivers/firmware/efi/Kconfig +10 -0
+	bool
+	depends on EFI_STUB && EFI_GENERIC_STUB && KEXEC_HANDOVER
+	help
+	  Carry the KHO state (the KHO state FDT and the scratch area) from
+	  one kernel to the next across kexec via an EFI configuration table
+	  entry under LINUX_EFI_KEXEC_HANDOVER_GUID, for architectures that
+	  boot through EFI without a device tree (e.g. LoongArch).
+
+	  Architectures with a boot FDT (arm64, riscv) use the /chosen FDT
+	  path instead and do not select this.

I don't like adding a config for this sort of thing. Do we really need this? Why not just have the code always compiled and only used by loongarch? I don't really see we need a user decision for this sort of thing.

Quoted 41 lines
drivers/firmware/efi/Kconfig +1 -0
+
 endmenu
 
 config UEFI_CPER
drivers/firmware/efi/efi.c +8 -0
index 0327a39d31fa..6380cfab1493 100644
@@ -24,6 +24,7 @@
 #include <linux/initrd.h>
 #include <linux/io.h>
 #include <linux/kexec.h>
+#include <linux/kexec_handover.h>
 #include <linux/platform_device.h>
 #include <linux/random.h>
 #include <linux/reboot.h>
@@ -62,6 +63,9 @@ unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
+#ifdef CONFIG_EFI_KHO
+static unsigned long __ro_after_init efi_kho_table_phys = EFI_INVALID_TABLE_ADDR;
+#endif
 
 extern unsigned long primary_display_table;
 
@@ -629,6 +633,9 @@ static const efi_config_table_type_t common_tables[] __initconst = {
 	{EFI_TCG2_FINAL_EVENTS_TABLE_GUID,	&efi.tpm_final_log,	"TPMFinalLog"	},
 	{EFI_CC_FINAL_EVENTS_TABLE_GUID,	&efi.tpm_final_log,	"CCFinalLog"	},
 	{LINUX_EFI_MEMRESERVE_TABLE_GUID,	&mem_reserve,		"MEMRESERVE"	},
+#ifdef CONFIG_EFI_KHO
+	{LINUX_EFI_KEXEC_HANDOVER_GUID,		&efi_kho_table_phys,	"KHO"		},
+#endif
 	{LINUX_EFI_INITRD_MEDIA_GUID,		&initrd,		"INITRD"	},
 	{EFI_RT_PROPERTIES_TABLE_GUID,		&rt_prop,		"RTPROP"	},
 #ifdef CONFIG_OVMF_DEBUG_LOG
@@ -806,6 +813,31 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
 		}
 	}
 
+#ifdef CONFIG_EFI_KHO

drivers/firmware/efi/efi.c int __init efi_config_parse_tables(const efi_config_table_t *config_tables, · line 826

Quoted 10 lines
drivers/firmware/efi/efi.c +10 -0
+	if (efi_kho_table_phys != EFI_INVALID_TABLE_ADDR) {
+		struct linux_efi_kho_data *kho;
+
+		/*
+		 * Reserve the stub-allocated table so it is neither handed
+		 * out by the buddy allocator nor placed on by kexec
+		 * segments, mirroring the memreserve handling above.  This
+		 * runs on every boot, so it also protects the table in the
+		 * next kernel until it reads it.
+		 */

Nit: this comment is too wordy. Can you please make it more concise and to the point?

drivers/firmware/efi/efi.c int __init efi_config_parse_tables(const efi_config_table_t *config_tables, · line 831

Quoted 5 lines
drivers/firmware/efi/efi.c +5 -0
+		memblock_reserve(efi_kho_table_phys, sizeof(*kho));
+
+		kho = early_memremap(efi_kho_table_phys, sizeof(*kho));
+		if (kho) {
+			if (kho->fdt_addr)

When can kho->fdt_addr be NULL? Also, perhaps print a warning if early_memremap() fails?

Quoted 20 lines
drivers/firmware/efi/efi.c +13 -0
+				kho_populate((phys_addr_t)kho->fdt_addr,
+					     kho->fdt_size,
+					     (phys_addr_t)kho->scratch_addr,
+					     kho->scratch_size);
+			early_memunmap(kho, sizeof(*kho));
+		}
+	}
+#endif
+
 	if (rt_prop != EFI_INVALID_TABLE_ADDR) {
 		efi_rt_properties_table_t *tbl;
 
@@ -1171,6 +1203,52 @@ static int __init efi_memreserve_root_init(void)
 }
 early_initcall(efi_memreserve_root_init);
 
+#ifdef CONFIG_EFI_KHO
+static struct linux_efi_kho_data *efi_kho_table __ro_after_init;
+
+static int __init efi_kho_table_init(void)

drivers/firmware/efi/efi.c static int __init efi_memreserve_root_init(void) · line 1219

Quoted 10 lines
drivers/firmware/efi/efi.c +10 -0
+{
+	if (efi_kho_table_phys == EFI_INVALID_TABLE_ADDR)
+		return 0;
+
+	/*
+	 * Keep a persistent mapping of the table, the same way
+	 * efi_memreserve_root_init() keeps the memreserve root mapped:
+	 * efi_kho_update() is also called on the crash kexec path, where
+	 * memremap() is no longer an option.
+	 */

No need to mention memreserve. Just explain the reason here. And keep it as short and to the point as possible.

Quoted 5 lines
drivers/firmware/efi/efi.c +5 -0
+	efi_kho_table = memremap(efi_kho_table_phys, sizeof(*efi_kho_table),
+				 MEMREMAP_WB);
+	WARN_ON_ONCE(!efi_kho_table);
+
+	return 0;

drivers/firmware/efi/efi.c static int __init efi_memreserve_root_init(void) · line 1234

Quoted 10 lines
drivers/firmware/efi/efi.c +10 -0
+}
+early_initcall(efi_kho_table_init);
+
+/*
+ * Update the KHO config table in place before a kexec, so the next kernel
+ * finds the current handover state.  Mirrors efi_mem_reserve_persistent():
+ * the config table entry was installed once by the EFI stub and is inherited
+ * across kexec, so only the table contents are rewritten here -- the config
+ * table array is never rebuilt and st->tables is never switched.
+ */

This is unreadable. Please add a human touch to this.

And once again, the fact that it mirrors efi_mem_reserve_persistent() isn't important.

drivers/firmware/efi/efi.c static int __init efi_memreserve_root_init(void) · line 1241

Quoted 7 lines
drivers/firmware/efi/efi.c +7 -0
+int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+		   phys_addr_t scratch_addr, u64 scratch_size)
+{
+	struct linux_efi_kho_data *kho = efi_kho_table;
+
+	if (!kho)
+		return -ENODEV;

Why ENODEV? Wouldn't ENOENT be a tiny bit better?

Quoted 74 lines
drivers/firmware/efi/efi.c +10 -0
+
+	kho->fdt_addr		= fdt_addr;
+	kho->fdt_size		= fdt_size;
+	kho->scratch_addr	= scratch_addr;
+	kho->scratch_size	= scratch_size;
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_KEXEC
 static int update_efi_random_seed(struct notifier_block *nb,
 				  unsigned long code, void *unused)
drivers/firmware/efi/libstub/efi-stub.c +25 -0
index 42d6073bcd06..751f46280433 100644
@@ -100,6 +100,29 @@ static void install_memreserve_table(void)
 		efi_err("Failed to install memreserve config table!\n");
 }
 
+static void install_kho_table(void)
+{
+#ifdef CONFIG_EFI_KHO
+	struct linux_efi_kho_data *kho;
+	efi_guid_t kho_table_guid = LINUX_EFI_KEXEC_HANDOVER_GUID;
+	efi_status_t status;
+
+	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*kho),
+			     (void **)&kho);
+	if (status != EFI_SUCCESS) {
+		efi_err("Failed to allocate KHO config table!\n");
+		return;
+	}
+
+	*kho = (struct linux_efi_kho_data){};
+
+	status = efi_bs_call(install_configuration_table, &kho_table_guid,
+			     kho);
+	if (status != EFI_SUCCESS)
+		efi_err("Failed to install KHO config table!\n");
+#endif
+}
+
 static u32 get_supported_rt_services(void)
 {
 	const efi_rt_properties_table_t *rt_prop_table;
@@ -180,6 +203,8 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 
 	install_memreserve_table();
 
+	install_kho_table();
+
 	status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
 
 	free_primary_display(dpy);
include/linux/efi.h +3 -0
index aa15ff88539b..564b3cbd5ccb 100644
@@ -422,6 +422,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_COCO_SECRET_AREA_GUID		EFI_GUID(0xadf956ad, 0xe98c, 0x484c,  0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47)
 #define LINUX_EFI_BOOT_MEMMAP_GUID		EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 #define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID	EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9,  0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31)
+#define LINUX_EFI_KEXEC_HANDOVER_GUID		EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)
 
 #define RISCV_EFI_BOOT_PROTOCOL_GUID		EFI_GUID(0xccd15fec, 0x6f73, 0x4eec,  0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
 
@@ -1273,6 +1274,41 @@ struct linux_efi_memreserve {
 
 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
 
+#ifdef CONFIG_EFI_KHO
+/*

include/linux/efi.h struct linux_efi_memreserve { · line 1288

Quoted 10 lines
include/linux/efi.h +10 -0
+ * The LINUX_EFI_KEXEC_HANDOVER_GUID config table points to this structure.
+ * It carries the kexec handover (KHO) state from the current kernel to the
+ * next one: the addresses of the KHO state FDT and of the scratch area.
+ *
+ * This is the handover channel for architectures that boot through EFI
+ * without a device tree (e.g. LoongArch), where the /chosen linux,kho-fdt
+ * and linux,kho-scratch properties read by early_init_dt_check_kho() are not
+ * available.  The EFI stub allocates and installs the table once at boot;
+ * the current kernel updates its contents before a kexec, and the next
+ * kernel reads it back and calls kho_populate().

This has too much information. You need to make it more to the point. For example, "without a device tree" already implies there is no /chosen property in the first place. No need to mention the function either.

The lifetime of the table is certainly useful information but again, should be much more clear and to the point.

Also, you should document what each of the members of the struct mean.

include/linux/efi.h struct linux_efi_memreserve { · line 1299

Quoted 11 lines
include/linux/efi.h +11 -0
+ *
+ * The layout is an ABI between the two kernels and carries no version
+ * field: an incompatible change must use a new GUID.  The handover payload
+ * itself is versioned separately by the compatible string of the KHO state
+ * FDT, which kho_populate() checks.
+ */
+struct linux_efi_kho_data {
+	u64 fdt_addr;
+	u64 fdt_size;
+	u64 scratch_addr;
+	u64 scratch_size;

Note: I recently sent a series that renames scratch to bootmem [0]. It looks close to landing. So you likely need to rename this to bootmem_{addr,size}.

include/linux/efi.h struct linux_efi_memreserve { · line 1300

Quoted 1 line
include/linux/efi.h +1 -0
+} __packed;

Why __packed?

Quoted 14 lines
include/linux/efi.h +11 -0
+
+int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+		   phys_addr_t scratch_addr, u64 scratch_size);
+#else
+static inline int efi_kho_update(phys_addr_t fdt_addr, u64 fdt_size,
+				 phys_addr_t scratch_addr, u64 scratch_size)
+{
+	return 0;
+}
+#endif
+
 /*
  * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table can be provided
  * to the kernel by an EFI boot loader. The table contains a packed
Signature · 2 lines
Regards,
Pratyush Yadav
author
#4 lore raw

Re: [PATCH v5 1/5] efi: add a KHO configuration table channel

Hi Pratyush,

Thanks for the detailed review. I've rewriten the comments and commit messages myself for v6. Replies inline.

Quoted 4 lines · Pratyush Yadav
Quoted 4 lines
drivers/firmware/efi/Kconfig +4 -0
+config EFI_KHO
+	bool
+	depends on EFI_STUB && EFI_GENERIC_STUB && KEXEC_HANDOVER
+	help

[...]

Quoted 4 lines

I don't like adding a config for this sort of thing. Do we really need this? Why not just have the code always compiled and only used by loongarch? I don't really see we need a user decision for this sort of thing.

Agreed, v6 drops it.

Quoted 10 lines

drivers/firmware/efi/efi.c int __init efi_config_parse_tables(const efi_config_table_t *config_tables, · line 826

Quoted 7 lines
drivers/firmware/efi/efi.c +7 -0
+		/*
+		 * Reserve the stub-allocated table so it is neither handed
+		 * out by the buddy allocator nor placed on by kexec
+		 * segments, mirroring the memreserve handling above.  This
+		 * runs on every boot, so it also protects the table in the
+		 * next kernel until it reads it.
+		 */

Nit: this comment is too wordy. Can you please make it more concise and to the point?

v6:

	/* Keep the buddy allocator and kexec segments off the table. */
Quoted 4 lines

drivers/firmware/efi/efi.c int __init efi_config_parse_tables(const efi_config_table_t *config_tables, · line 831

Quoted 1 line
drivers/firmware/efi/efi.c +1 -0
+			if (kho->fdt_addr)

When can kho->fdt_addr be NULL? Also, perhaps print a warning if early_memremap() fails?

It is 0 when there is nothing to restore:

- on a cold boot, because the stub installs the table zeroed;
- after a kexec into an image without KHO state, such as a crash kernel, because the table is zeroed just before that kexec.

v6 says this in the struct documentation, and adds a pr_warn() when early_memremap() fails.

Quoted 9 lines

drivers/firmware/efi/efi.c static int __init efi_memreserve_root_init(void) · line 1219

Quoted 6 lines
drivers/firmware/efi/efi.c +6 -0
+	/*
+	 * Keep a persistent mapping of the table, the same way
+	 * efi_memreserve_root_init() keeps the memreserve root mapped:
+	 * efi_kho_update() is also called on the crash kexec path, where
+	 * memremap() is no longer an option.
+	 */

No need to mention memreserve. Just explain the reason here. And keep it as short and to the point as possible.

v6:

	/* Map it now: the table is also written at panic time. */
Quoted 4 lines

This is unreadable. Please add a human touch to this.

And once again, the fact that it mirrors efi_mem_reserve_persistent() isn't important.

v6:

	/*
	 * Write the KHO addresses the next kernel should use, or zeroes
	 * if it should boot without KHO.
	 */
Quoted 1 line

Why ENODEV? Wouldn't ENOENT be a tiny bit better?

Neither, in v6. No table is the normal case outside LoongArch, so efi_kho_update() now returns 0. The only error left is a table that could not be mapped at boot, which returns -ENOMEM.

Quoted 8 lines

This has too much information. You need to make it more to the point. For example, "without a device tree" already implies there is no /chosen property in the first place. No need to mention the function either.

The lifetime of the table is certainly useful information but again, should be much more clear and to the point.

Also, you should document what each of the members of the struct mean.

Agreed. v6:

/**
* struct linux_efi_kho_data - KHO state passed to the next kernel
* @fdt_addr: physical address of the KHO FDT, 0 if there is none
* @fdt_size: size of the KHO FDT
* @bootmem_addr: physical address of the bootmem area list
* @bootmem_size: size of the bootmem area list
*
* Pointed to by the LINUX_EFI_KEXEC_HANDOVER_GUID configuration table. *
* The EFI stub installs this table zeroed on a cold boot. It stays
* in place across kexec; the running kernel rewrites it just before
* each kexec, and the next kernel reads it during early boot. *
* The layout is fixed. Changing it requires a new GUID. */

Quoted 3 lines

Note: I recently sent a series that renames scratch to bootmem [0]. It looks close to landing. So you likely need to rename this to bootmem_{addr,size}.

Thanks for the heads-up. It is in liveupdate/next now, so v6 is based on it and uses bootmem_{addr,size}.

Quoted 1 line

Why __packed?

No good reason. All four members are u64, so there is no padding and __packed changes nothing. Dropped.

Thanks,
George

author
#5 lore raw

PATCH v5 2/5 liveupdate: synchronize EFI KHO channel at execution

In reply to George Guo

From: George Guo <[email protected]>

The EFI KHO configuration table is a global channel. Updating it while a candidate kexec image is still being loaded can leave the channel pointing at the failed candidate even though the previous image remains installed. Synchronize it instead from the image selected for execution.

Use the actual scratch payload size rather than its page-aligned segment size, and propagate update failures before live-update serialization. Keep clearing the channel for cold and crash images best-effort.

---
 kernel/crash_core.c                |  7 +++++++
 kernel/kexec_core.c                |  5 +++++
 kernel/kexec_internal.h            |  3 +++
 kernel/liveupdate/kexec_handover.c | 33 ++++++++++++++++++++++++++++++
 4 files changed, 48 insertions(+)
kernel/crash_core.c +7 -0
index 2b36aa9fade0..6166ce4203d3 100644
@@ -138,6 +138,13 @@ void __noclone __crash_kexec(struct pt_regs *regs)
 		if (kexec_crash_image) {
 			struct pt_regs fixed_regs;
 
+			/*
+			 * A crash image carries no KHO state: clear the
+			 * transport so the crash kernel boots cold instead
+			 * of reviving from stale state.
+			 */
+			(void)kho_sync_channel(kexec_crash_image);
+
 			crash_setup_regs(&fixed_regs, regs);
 			crash_save_vmcoreinfo();
 			machine_crash_shutdown(&fixed_regs);
kernel/kexec_core.c +5 -0
index dc770b9a6d05..147f5b5b23d4 100644
@@ -1146,6 +1146,11 @@ int kernel_kexec(void)
 		goto Unlock;
 	}
 
+	/* Synchronize the handover transport with the image being executed. */
+	error = kho_sync_channel(kexec_image);
+	if (error)
+		goto Unlock;
+
 	if (!kexec_image->preserve_context) {
 		error = liveupdate_reboot();
 		if (error)
kernel/kexec_internal.h +3 -0
index 228bb88c018b..4d4c2290e85c 100644
@@ -46,6 +46,7 @@ struct kexec_buf;
 int kho_locate_mem_hole(struct kexec_buf *kbuf,
 			int (*func)(struct resource *, void *));
 int kho_fill_kimage(struct kimage *image);
+int kho_sync_channel(struct kimage *image);
 #else
 static inline int kho_locate_mem_hole(struct kexec_buf *kbuf,
 				      int (*func)(struct resource *, void *))
@@ -54,5 +55,7 @@ static inline int kho_locate_mem_hole(struct kexec_buf *kbuf,
 }
 
 static inline int kho_fill_kimage(struct kimage *image) { return 0; }
+
+static inline int kho_sync_channel(struct kimage *image) { return 0; }
 #endif /* CONFIG_KEXEC_HANDOVER */
 #endif /* LINUX_KEXEC_INTERNAL_H */
kernel/liveupdate/kexec_handover.c +33 -0
index 39f489a258d9..3aa5c66dfc6d 100644
@@ -14,6 +14,7 @@
 #include <linux/cma.h>
 #include <linux/kmemleak.h>
 #include <linux/count_zeros.h>
+#include <linux/efi.h>
 #include <linux/kasan.h>
 #include <linux/kexec.h>
 #include <linux/kexec_handover.h>
@@ -2074,6 +2075,38 @@ int kho_fill_kimage(struct kimage *image)
 	return 0;
 }
 
+/*
+ * Synchronize the handover transport with the image that is about to be
+ * executed.  The EFI config table channel is global, while kexec keeps
+ * separate images for a normal reboot and for crash.  Write the state of the
+ * selected image immediately before it is executed, rather than while a
+ * candidate image is being loaded, so a failed replacement cannot leave the
+ * channel pointing at that failed image.
+ *
+ * An image loaded through the legacy kexec_load() syscall, a crash image, or
+ * an image loaded while KHO is disabled carries no handover state.  Clear the
+ * channel for those images so the next kernel boots cold instead of reviving
+ * from stale state.  Clearing is best-effort because an absent channel cannot
+ * affect a cold boot.
+ */
+int kho_sync_channel(struct kimage *image)
+{
+	int err;
+
+	if (!image->kho.fdt || !image->kho.scratch) {
+		efi_kho_update(0, 0, 0, 0);
+		return 0;
+	}
+
+	err = efi_kho_update(image->kho.fdt, PAGE_SIZE,
+			     image->kho.scratch->mem,
+			     image->kho.scratch->bufsz);
+	if (err)
+		pr_warn("failed to update EFI config table: %d\n", err);
+
+	return err;
+}
+
 static int kho_walk_scratch(struct kexec_buf *kbuf,
 			    int (*func)(struct resource *, void *))
 {
Signature · 1 line
2.53.0
maintainer
#6 lore raw

Re: [PATCH v5 2/5] liveupdate: synchronize EFI KHO channel at execution

Hi, George,

Quoted 106 lines · George Guo

From: George Guo <[email protected]>

The EFI KHO configuration table is a global channel. Updating it while a candidate kexec image is still being loaded can leave the channel pointing at the failed candidate even though the previous image remains installed. Synchronize it instead from the image selected for execution.

Use the actual scratch payload size rather than its page-aligned segment size, and propagate update failures before live-update serialization. Keep clearing the channel for cold and crash images best-effort.

---
 kernel/crash_core.c                |  7 +++++++
 kernel/kexec_core.c                |  5 +++++
 kernel/kexec_internal.h            |  3 +++
 kernel/liveupdate/kexec_handover.c | 33 ++++++++++++++++++++++++++++++
 4 files changed, 48 insertions(+)
kernel/crash_core.c +7 -0
index 2b36aa9fade0..6166ce4203d3 100644
@@ -138,6 +138,13 @@ void __noclone __crash_kexec(struct pt_regs *regs)
                if (kexec_crash_image) {
                        struct pt_regs fixed_regs;
 
+                       /*
+                        * A crash image carries no KHO state: clear the
+                        * transport so the crash kernel boots cold instead
+                        * of reviving from stale state.
+                        */
+                       (void)kho_sync_channel(kexec_crash_image);
+
                        crash_setup_regs(&fixed_regs, regs);
                        crash_save_vmcoreinfo();
                        machine_crash_shutdown(&fixed_regs);
kernel/kexec_core.c +5 -0
index dc770b9a6d05..147f5b5b23d4 100644
@@ -1146,6 +1146,11 @@ int kernel_kexec(void)
                goto Unlock;
        }
 
+       /* Synchronize the handover transport with the image being executed. */
+       error = kho_sync_channel(kexec_image);
+       if (error)
+               goto Unlock;
+
        if (!kexec_image->preserve_context) {
                error = liveupdate_reboot();
                if (error)
kernel/kexec_internal.h +3 -0
index 228bb88c018b..4d4c2290e85c 100644
@@ -46,6 +46,7 @@ struct kexec_buf;
 int kho_locate_mem_hole(struct kexec_buf *kbuf,
                        int (*func)(struct resource *, void *));
 int kho_fill_kimage(struct kimage *image);
+int kho_sync_channel(struct kimage *image);
 #else
 static inline int kho_locate_mem_hole(struct kexec_buf *kbuf,
                                      int (*func)(struct resource *, void *))
@@ -54,5 +55,7 @@ static inline int kho_locate_mem_hole(struct kexec_buf *kbuf,
 }
 
 static inline int kho_fill_kimage(struct kimage *image) { return 0; }
+
+static inline int kho_sync_channel(struct kimage *image) { return 0; }
 #endif /* CONFIG_KEXEC_HANDOVER */
 #endif /* LINUX_KEXEC_INTERNAL_H */
kernel/liveupdate/kexec_handover.c +17 -0
index 39f489a258d9..3aa5c66dfc6d 100644
@@ -14,6 +14,7 @@
 #include <linux/cma.h>
 #include <linux/kmemleak.h>
 #include <linux/count_zeros.h>
+#include <linux/efi.h>
 #include <linux/kasan.h>
 #include <linux/kexec.h>
 #include <linux/kexec_handover.h>
@@ -2074,6 +2075,38 @@ int kho_fill_kimage(struct kimage *image)
        return 0;
 }
 
+/*
+ * Synchronize the handover transport with the image that is about to be
+ * executed.  The EFI config table channel is global, while kexec keeps
+ * separate images for a normal reboot and for crash.  Write the state of the
+ * selected image immediately before it is executed, rather than while a
+ * candidate image is being loaded, so a failed replacement cannot leave the
+ * channel pointing at that failed image.
+ *
+ * An image loaded through the legacy kexec_load() syscall, a crash image, or
+ * an image loaded while KHO is disabled carries no handover state.  Clear the
+ * channel for those images so the next kernel boots cold instead of reviving
+ * from stale state.  Clearing is best-effort because an absent channel cannot
+ * affect a cold boot.
+ */
+int kho_sync_channel(struct kimage *image)
+{

kernel/liveupdate/kexec_handover.c int kho_fill_kimage(struct kimage *image) · line 2103

Quoted 10 lines
kernel/liveupdate/kexec_handover.c +10 -0
+       int err;
+
+       if (!image->kho.fdt || !image->kho.scratch) {
+               efi_kho_update(0, 0, 0, 0);
+               return 0;
+       }
+
+       err = efi_kho_update(image->kho.fdt, PAGE_SIZE,
+                            image->kho.scratch->mem,
+                            image->kho.scratch->bufsz);

You can combine the last two lines.

Huacai

Quoted 12 lines
kernel/liveupdate/kexec_handover.c +6 -1
+       if (err)
+               pr_warn("failed to update EFI config table: %d\n", err);
+
+       return err;
+}
+
 static int kho_walk_scratch(struct kexec_buf *kbuf,
                            int (*func)(struct resource *, void *))
 {
--

2.53.0

maintainer
#7 lore raw

Re: [PATCH v5 2/5] liveupdate: synchronize EFI KHO channel at execution

In reply to George Guo
Quoted 6 lines · George Guo

From: George Guo <[email protected]>

The EFI KHO configuration table is a global channel. Updating it while a candidate kexec image is still being loaded can leave the channel pointing at the failed candidate even though the previous image remains installed. Synchronize it instead from the image selected for execution.

Huh? Sorry, I don't understand this is supposed to mean at all. What failed candidate?

Quoted 4 lines

Use the actual scratch payload size rather than its page-aligned segment size, and propagate update failures before live-update serialization. Keep clearing the channel for cold and crash images best-effort.

Huh? This is word soup and I don't understand what any of this is supposed to mean.

If you are using a LLM to generate this, please _read_ what the output is and see if it even is readable to someone else.

And if you are writing this by hand, then take a step back, and consider if patch reviews can even understand what you are saying.

Quoted 32 lines
---
 kernel/crash_core.c                |  7 +++++++
 kernel/kexec_core.c                |  5 +++++
 kernel/kexec_internal.h            |  3 +++
 kernel/liveupdate/kexec_handover.c | 33 ++++++++++++++++++++++++++++++
 4 files changed, 48 insertions(+)
kernel/crash_core.c +7 -0
index 2b36aa9fade0..6166ce4203d3 100644
@@ -138,6 +138,13 @@ void __noclone __crash_kexec(struct pt_regs *regs)
 		if (kexec_crash_image) {
 			struct pt_regs fixed_regs;
 
+			/*
+			 * A crash image carries no KHO state: clear the
+			 * transport so the crash kernel boots cold instead
+			 * of reviving from stale state.
+			 */
+			(void)kho_sync_channel(kexec_crash_image);
+
 			crash_setup_regs(&fixed_regs, regs);
 			crash_save_vmcoreinfo();
 			machine_crash_shutdown(&fixed_regs);
kernel/kexec_core.c +0 -0
index dc770b9a6d05..147f5b5b23d4 100644

kernel/kexec_core.c int kernel_kexec(void) · line 1153

Quoted 8 lines
kernel/kexec_core.c +5 -0
@@ -1146,6 +1146,11 @@ int kernel_kexec(void)
 		goto Unlock;
 	}
 
+	/* Synchronize the handover transport with the image being executed. */
+	error = kho_sync_channel(kexec_image);
+	if (error)
+		goto Unlock;
+

Why are you setting this at kexec time? Why not set it at load time like every other architecture?

Also what's this "sync channel"? Use simpler words that _actually describe_ what they do.

Quoted 74 lines
kernel/kexec_core.c +0 -0
 	if (!kexec_image->preserve_context) {
 		error = liveupdate_reboot();
 		if (error)
kernel/kexec_internal.h +3 -0
index 228bb88c018b..4d4c2290e85c 100644
@@ -46,6 +46,7 @@ struct kexec_buf;
 int kho_locate_mem_hole(struct kexec_buf *kbuf,
 			int (*func)(struct resource *, void *));
 int kho_fill_kimage(struct kimage *image);
+int kho_sync_channel(struct kimage *image);
 #else
 static inline int kho_locate_mem_hole(struct kexec_buf *kbuf,
 				      int (*func)(struct resource *, void *))
@@ -54,5 +55,7 @@ static inline int kho_locate_mem_hole(struct kexec_buf *kbuf,
 }
 
 static inline int kho_fill_kimage(struct kimage *image) { return 0; }
+
+static inline int kho_sync_channel(struct kimage *image) { return 0; }
 #endif /* CONFIG_KEXEC_HANDOVER */
 #endif /* LINUX_KEXEC_INTERNAL_H */
kernel/liveupdate/kexec_handover.c +33 -0
index 39f489a258d9..3aa5c66dfc6d 100644
@@ -14,6 +14,7 @@
 #include <linux/cma.h>
 #include <linux/kmemleak.h>
 #include <linux/count_zeros.h>
+#include <linux/efi.h>
 #include <linux/kasan.h>
 #include <linux/kexec.h>
 #include <linux/kexec_handover.h>
@@ -2074,6 +2075,38 @@ int kho_fill_kimage(struct kimage *image)
 	return 0;
 }
 
+/*
+ * Synchronize the handover transport with the image that is about to be
+ * executed.  The EFI config table channel is global, while kexec keeps
+ * separate images for a normal reboot and for crash.  Write the state of the
+ * selected image immediately before it is executed, rather than while a
+ * candidate image is being loaded, so a failed replacement cannot leave the
+ * channel pointing at that failed image.
+ *
+ * An image loaded through the legacy kexec_load() syscall, a crash image, or
+ * an image loaded while KHO is disabled carries no handover state.  Clear the
+ * channel for those images so the next kernel boots cold instead of reviving
+ * from stale state.  Clearing is best-effort because an absent channel cannot
+ * affect a cold boot.
+ */
+int kho_sync_channel(struct kimage *image)
+{
+	int err;
+
+	if (!image->kho.fdt || !image->kho.scratch) {
+		efi_kho_update(0, 0, 0, 0);
+		return 0;
+	}
+
+	err = efi_kho_update(image->kho.fdt, PAGE_SIZE,
+			     image->kho.scratch->mem,
+			     image->kho.scratch->bufsz);
+	if (err)
+		pr_warn("failed to update EFI config table: %d\n", err);
+
+	return err;
+}
+
 static int kho_walk_scratch(struct kexec_buf *kbuf,
 			    int (*func)(struct resource *, void *))
 {
Signature · 2 lines
Regards,
Pratyush Yadav
author
#8 lore raw

Re: [PATCH v5 2/5] liveupdate: synchronize EFI KHO channel at execution

Hi Pratyush,

You are right about the text, and I am sorry. I used an LLM to help write this series. I meant to check every commit message and comment word by word myself before sending, but I made a mistake and sent v5 to the list before doing that check. That is my fault, and it cost you time trying to read it.

For v6 I am rewriting the messages and checking every line myself before sending.

Quoted 7 lines · Pratyush Yadav
Quoted 4 lines

The EFI KHO configuration table is a global channel. Updating it while a candidate kexec image is still being loaded can leave the channel pointing at the failed candidate even though the previous image remains installed. Synchronize it instead from the image selected for execution.

Huh? Sorry, I don't understand this is supposed to mean at all. What failed candidate?

Rewritten in v6.

Quoted 2 lines

Why are you setting this at kexec time? Why not set it at load time like every other architecture?

Other architectures store the KHO addresses in the loaded image itself, so each image has its own copy.

The EFI table is shared, but the normal and the crash image can both be loaded, and they need different contents: the normal kernel needs the KHO addresses, the crash kernel must find the table zeroed. Whatever is written at load time is wrong for one of them. For example, after "kexec -l" with KHO and then "kexec -p", a panic boots the crash kernel with KHO addresses that were meant for the normal kernel.

kernel_kexec() and __crash_kexec() know which image is about to run, so v6 writes the table there: filled from that image, or zeroed if it has no KHO state.

Quoted 2 lines

Also what's this "sync channel"? Use simpler words that _actually describe_ what they do.

Renamed to kho_update_efi_table() in v6.

Quoted 6 lines
Quoted 3 lines

Use the actual scratch payload size rather than its page-aligned segment size, and propagate update failures before live-update serialization. Keep clearing the channel for cold and crash images best-effort.

Huh? This is word soup and I don't understand what any of this is supposed to mean.

Rewritten in v6.

Thanks,
George

author
#9 lore raw

PATCH v5 3/5 liveupdate: kho_block: include linux/mm.h for virt/phys translation

In reply to George Guo

From: George Guo <[email protected]>

kho_block.c calls virt_to_phys() and phys_to_virt(). On LoongArch with CONFIG_KFENCE=y, these macros (in arch/loongarch/include/asm/io.h) expand to offset_in_page() and page_address(), both declared in <linux/mm.h>.

Since kho_block.c does not include <linux/mm.h>, the translation unit fails to build with CONFIG_KFENCE=y:

asm/io.h: error: implicit declaration of function 'offset_in_page' asm/io.h: error: implicit declaration of function 'page_address'

Add the missing include to fix these build errors.

This is the same root cause as the luo_session.c build fix previously acked by Mike Rapoport [1]; the virt_to_phys()/phys_to_virt() calls have since been refactored from luo_session.c into kho_block.c, so the fix moves with it.

[1] https://lore.kernel.org/r/[email protected]/

---
 kernel/liveupdate/kho_block.c | 1 +
 1 file changed, 1 insertion(+)
kernel/liveupdate/kho_block.c +1 -0
index 0d2a342ef422..0d56891b2f4c 100644
@@ -25,6 +25,7 @@
 #include <linux/kho/abi/block.h>
 #include <linux/kho_block.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 
 /*
  * Safeguard limit for the number of serialization blocks. This is used to
Signature · 1 line
2.53.0
maintainer
#10 lore raw

Re: [PATCH v5 3/5] liveupdate: kho_block: include linux/mm.h for virt/phys translation

Quoted 12 lines · George Guo

From: George Guo <[email protected]>

kho_block.c calls virt_to_phys() and phys_to_virt(). On LoongArch with CONFIG_KFENCE=y, these macros (in arch/loongarch/include/asm/io.h) expand to offset_in_page() and page_address(), both declared in <linux/mm.h>.

Since kho_block.c does not include <linux/mm.h>, the translation unit fails to build with CONFIG_KFENCE=y:

asm/io.h: error: implicit declaration of function 'offset_in_page' asm/io.h: error: implicit declaration of function 'page_address'

Quoted 8 lines

Add the missing include to fix these build errors.

This is the same root cause as the luo_session.c build fix previously acked by Mike Rapoport [1]; the virt_to_phys()/phys_to_virt() calls have since been refactored from luo_session.c into kho_block.c, so the fix moves with it.

[1] https://lore.kernel.org/r/[email protected]/

Drop this paragraph please. History of previous patch postings doesn't belong in the commit message. You should write this kind of things below the "---".

Quoted 20 lines
---
 kernel/liveupdate/kho_block.c | 1 +
 1 file changed, 1 insertion(+)
kernel/liveupdate/kho_block.c +1 -0
index 0d2a342ef422..0d56891b2f4c 100644
@@ -25,6 +25,7 @@
 #include <linux/kho/abi/block.h>
 #include <linux/kho_block.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 
 /*
  * Safeguard limit for the number of serialization blocks. This is used to
Signature · 2 lines
Regards,
Pratyush Yadav
author
#11 lore raw

PATCH v5 4/5 LoongArch: enable kexec handover (KHO)

In reply to George Guo

From: George Guo <[email protected]>

Enable ARCH_SUPPORTS_KEXEC_HANDOVER for 64-bit LoongArch. It selects EFI_KHO whenever KEXEC_HANDOVER is enabled, so LoongArch uses the architecture-agnostic EFI configuration table channel (LINUX_EFI_KEXEC_HANDOVER_GUID) introduced by this series to carry the KHO state across kexec.

LoongArch boots through EFI without a device tree, so it cannot use the /chosen FDT path that arm64 and riscv use; the EFI configuration table channel is its handover transport. No arch-specific setup.c reader or machine_kexec_file.c writer is needed -- both live in the generic EFI code.

---
 arch/loongarch/Kconfig | 4 ++++
 1 file changed, 4 insertions(+)
arch/loongarch/Kconfig +4 -0
index a21f51e5815e..5eaa65578d58 100644
@@ -685,6 +685,10 @@ config ARCH_SUPPORTS_KEXEC
 config ARCH_SUPPORTS_KEXEC_FILE
 	def_bool 64BIT
 
+config ARCH_SUPPORTS_KEXEC_HANDOVER
+	def_bool 64BIT && EFI_STUB
+	select EFI_KHO if KEXEC_HANDOVER
+
 config ARCH_SELECTS_KEXEC_FILE
 	def_bool 64BIT
 	depends on KEXEC_FILE
Signature · 1 line
2.53.0
author
#12 lore raw

PATCH v5 5/5 selftests/kho: add LoongArch vmtest support

In reply to George Guo

From: George Guo <[email protected]>

Add loongarch.conf to configure QEMU's LoongArch virtual machine with a la464 CPU, an 8250 serial console, and the generic PCI host controller. Extend vmtest.sh to recognize loongarch64 as a supported target and map it to the loongarch kernel architecture name.

Boot vmlinux.efi through EFI firmware. The KHO configuration table channel is installed by the EFI stub during the initial boot, so direct kernel boot bypasses the path that this test needs to exercise. QEMU_EFI defaults to the firmware shipped under /usr/share/edk2/loongarch64/ and can be overridden for distributions that install it under a different path, such as Debian's qemu-efi-loongarch64 package.

QEMU's LoongArch virt machine has no i8042 controller. Enable the generic PCI host so its I/O space is mapped before the i8042 fallback probe accesses the legacy ports. This avoids disabling the i8042 options and allows the same kernel configuration to remain usable on physical hosts.

Enable ACPI_SPCR_TABLE so the bare earlycon parameter can obtain the UART type, MMIO address and baud rate from the SPCR table installed by EDK2. Unlike on x86, ACPI_SPCR_TABLE does not default to enabled on LoongArch. Without it, no early console is registered for the EFI firmware boot path, and vmtest cannot observe the early kernel output in its serial log.

The KHO vmtest requires CONFIG_DEFERRED_STRUCT_PAGE_INIT=y, which depends on SPARSEMEM. Select CONFIG_SPARSEMEM_MANUAL=y to satisfy the dependency on LoongArch.

---
 tools/testing/selftests/kho/loongarch.conf | 11 +++++++++++
 tools/testing/selftests/kho/vmtest.sh      |  3 ++-
 2 files changed, 13 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf
tools/testing/selftests/kho/loongarch.conf new file +11 -0
new file mode 100644
index 000000000000..36153b03c4ef
@@ -0,0 +1,11 @@
+QEMU_EFI="${QEMU_EFI:-/usr/share/edk2/loongarch64/QEMU_EFI.fd}"
+QEMU_CMD="qemu-system-loongarch64 -M virt -cpu la464 -bios $QEMU_EFI"
+QEMU_KCONFIG="
+CONFIG_ACPI_SPCR_TABLE=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SPARSEMEM_MANUAL=y
+"
+KERNEL_IMAGE="vmlinux.efi"
+KERNEL_CMDLINE="console=ttyS0 earlycon"
tools/testing/selftests/kho/vmtest.sh +2 -1
index 0014bd76e88d..d05ba0734b25 100755
@@ -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, loongarch64, x86_64
 	-h)	display this help
 EOF
 }
@@ -126,6 +126,7 @@ function target_to_arch() {
 
 	case $target in
 	     aarch64) echo "arm64" ;;
+	     loongarch64) echo "loongarch" ;;
 	     x86_64) echo "x86" ;;
 	     *) skip "architecture $target is not supported"
 	esac
Signature · 1 line
2.53.0
maintainer
#13 lore raw
In reply to George Guo

Hi George,

Quoted 10 lines · George Guo

This series enables Kexec HandOver (KHO) on 64-bit LoongArch and adds LoongArch coverage to the KHO QEMU selftest. KHO is the remaining architecture gate needed by Live Update (LUO) on LoongArch.

The transport is the central problem. Arm64 and riscv can pass the KHO state FDT and scratch area through properties under /chosen in a boot FDT. LoongArch boots through EFI without a boot FDT, so that path is not available.

EFI KHO channel:

I can't say I like "transport" and "channel" terminology. We don't send anything anywhere.

Quoted 58 lines

v5 reworks the EFI transport following Pratyush's and Huacai's reviews [1, 2]. Instead of rebuilding the EFI configuration table in LoongArch code and switching st->tables before kexec, the common EFI stub allocates and installs a persistent table under LINUX_EFI_KEXEC_HANDOVER_GUID. This follows the model used by LINUX_EFI_MEMRESERVE_TABLE_GUID.

The common EFI table parser reserves the stub-allocated table, reads it during early boot, and calls kho_populate(). An early initcall keeps the table persistently mapped so it can also be updated on the crash kexec path. The implementation is architecture-independent; LoongArch only selects EFI_KHO when KEXEC_HANDOVER is enabled.

The EFI table is global, but kexec can keep separate normal and crash images and can replace a loaded candidate. Updating the table while a candidate image is being loaded could therefore leave it pointing at a failed candidate while the previously installed image remains the one that will be executed. v5 records the KHO data in struct kimage and synchronizes the channel from the image selected for execution. Images without KHO data, including legacy and crash images, clear the channel so the next kernel boots cold rather than reviving stale state.

The GUID name is changed to LINUX_EFI_KEXEC_HANDOVER_GUID as suggested by Huacai and Pratyush [3]. Existing x86 KHO support continues to use its setup_data transport. Besides supporting non-UEFI boot, that entry is consumed by the x86 decompressor before normal EFI table parsing, so KASLR only uses KHO scratch areas and does not overwrite preserved memory. The new channel is installed by the generic EFI-stub entry path and relies on EFI_GENERIC_STUB, which x86 does not select. Moving x86 would therefore require installing the table from the x86-specific EFI stub and scanning it in the decompressor, not just selecting EFI_KHO.

LoongArch enablement and build fix:

The architecture patch now only enables ARCH_SUPPORTS_KEXEC_HANDOVER and selects the generic EFI channel. No LoongArch setup reader, kexec writer, or EFI system-table replacement remains.

The linux/mm.h build fix is moved from luo_session.c to kho_block.c, where the virt_to_phys() and phys_to_virt() calls reside after the liveupdate refactoring. This addresses Pratyush's review [4]. Adding linux/mm.h to asm/io.h was previously attempted, but creates an include cycle under CONFIG_KFENCE [5]. The fix precedes LoongArch enablement so every intermediate commit builds with CONFIG_KFENCE=y.

Selftest:

The LoongArch vmtest boots vmlinux.efi through EDK2 because the initial EFI stub invocation installs the channel being tested. QEMU_EFI can override the firmware filename for distributions that install it under a different name or path.

CONFIG_ACPI_SPCR_TABLE lets the bare earlycon parameter obtain the UART description from EDK2's SPCR table. CONFIG_PCI_HOST_GENERIC keeps i8042 enabled while ensuring that the QEMU virt machine's PCI I/O space is mapped before the legacy fallback probe, addressing Huacai's concern that the same kernel configuration should remain usable for hosts and guests.

Quoted 8 lines

With EFI runtime reset services available, panic=-1 and QEMU's existing -no-reboot option terminate the test normally. The generic QEMU runner therefore remains unchanged and does not mask failures by forcibly terminating QEMU after a timeout.

The LoongArch vmtest uses the default KHO scratch-sizing path. This series is based on the generic fix that calculates per-node scratch sizes before scratch allocation [6].

The text here and in the patches changelog reads reads as LLM-generated text. First, it's quite blind and unreadable with wall-to-wall text. Second, LLMs tend to describe what they did in the context of a session, but since we apply the cover letter to the liveupdate tree, the description here should *only* describe why the changes are required and how they are implemented. The history belongs to changes since vN-1 section.

And last, but not least, please add LLM attribution as per

https://docs.kernel.org/process/coding-assistants.html#attribution

Quoted 78 lines

The KHO vmtest passes on:

* LoongArch with KVM using QEMU_EFI.fd from edk2-loongarch64.
* x86_64 with KVM, as regression coverage for the generic kexec/KHO changes.

Patch layout:

1. Add the generic EFI KHO channel and its ABI.
2. Synchronize the channel from the selected image at execution.
3. Fix the kho_block.c header dependency exposed by LoongArch/KFENCE.
4. Enable KHO on 64-bit LoongArch through the generic EFI channel.
5. Add LoongArch to the KHO QEMU selftest.

Changes since v4:

* Allocate and install the KHO table from the common EFI stub, following the EFI memreserve-table model (Pratyush).
* Parse, reserve, map, and update the channel in generic EFI code; remove

    the LoongArch-specific reader, writer, and st->tables replacement
    (Pratyush, Huacai).

* Synchronize the global channel at execution rather than image load; clear it for cold and crash images and use the scratch payload size.
* Rename the GUID to LINUX_EFI_KEXEC_HANDOVER_GUID (Huacai, Pratyush).
* Move the linux/mm.h include from luo_session.c to the actual caller, kho_block.c, and place the fix before architecture enablement (Pratyush, Huacai).
* Boot the vmtest through EDK2, allow QEMU_EFI to override the firmware, and use vmlinux.efi to exercise the EFI stub and channel.
* Keep i8042 enabled and select PCI_HOST_GENERIC instead of disabling the host configuration in the selftest (Huacai).
* Enable ACPI_SPCR_TABLE and use the SPCR-provided early console.
* Exercise the default KHO scratch-sizing path in the LoongArch vmtest; depend on the separately posted generic sizing fix [6].
* Drop the generic QEMU timeout now that EFI runtime reset services make the LoongArch guest terminate normally.
* Rebase onto Linux 7.3-rc1.

[1] Pratyush Yadav:

    https://lore.kernel.org/r/[email protected]/

[2] Huacai Chen:
https://lore.kernel.org/r/CAAhV-H4PKRNCa4g=6TGepP+trtM82JiMoWgVr3O7PqbZYP9uGw@mail.gmail.com/
[3] https://lore.kernel.org/r/[email protected]/
[4] https://lore.kernel.org/r/[email protected]/
[5] https://lore.kernel.org/r/[email protected]/
[6] https://lore.kernel.org/loongarch/[email protected]/

Previous version:

v4: https://lore.kernel.org/loongarch/[email protected]/

George Guo (5):
efi: add a KHO configuration table channel
liveupdate: synchronize EFI KHO channel at execution
liveupdate: kho_block: include linux/mm.h for virt/phys translation
LoongArch: enable kexec handover (KHO)
selftests/kho: add LoongArch vmtest support

 arch/loongarch/Kconfig                     |  4 ++
 drivers/firmware/efi/Kconfig               | 12 ++++
 drivers/firmware/efi/efi.c                 | 78 ++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c    | 25 +++++++
 include/linux/efi.h                        | 36 ++++++++++
 kernel/crash_core.c                        |  7 ++
 kernel/kexec_core.c                        |  5 ++
 kernel/kexec_internal.h                    |  3 +
 kernel/liveupdate/kexec_handover.c         | 33 +++++++++
 kernel/liveupdate/kho_block.c              |  1 +
 tools/testing/selftests/kho/loongarch.conf | 11 +++
 tools/testing/selftests/kho/vmtest.sh      |  3 +-
 12 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
prerequisite-patch-id: a2f06addb17cc379b9f98674f087a1642588dc6e

Signature · 1 line
2.53.0
Signature · 2 lines
Sincerely yours,
Mike.
author
#14 lore raw

Hi Mike,

Quoted 4 lines · Mike Rapoport
Quoted 1 line

EFI KHO channel:

I can't say I like "transport" and "channel" terminology. We don't send anything anywhere.

Agreed. It is just a table that the next kernel reads. v6 calls it the KHO EFI configuration table everywhere, and "transport" and "channel" are gone from the code, the commit messages and the cover letter.

[...]

Quoted 10 lines

The text here and in the patches changelog reads reads as LLM-generated text. First, it's quite blind and unreadable with wall-to-wall text. Second, LLMs tend to describe what they did in the context of a session, but since we apply the cover letter to the liveupdate tree, the description here should *only* describe why the changes are required and how they are implemented. The history belongs to changes since vN-1 section.

And last, but not least, please add LLM attribution as per

https://docs.kernel.org/process/coding-assistants.html#attribution

You are right, and I am sorry. I used an LLM to help write this series. I meant to check every line word by word myself before sending, but I made a mistake and sent v5 to the list before doing that check.

For v6:

- The cover letter only explains why LoongArch needs this and how it works. Everything about earlier versions moves to "Changes since v5".
- I am rewriting the cover letter and commit messages by hand, in short paragraphs, and checking every line myself before sending.
- Every patch carries the Assisted-by tag if we used LLM.

Thanks,
George

maintainer
#15 lore raw
In reply to George Guo
Quoted 8 lines · George Guo

This series enables Kexec HandOver (KHO) on 64-bit LoongArch and adds LoongArch coverage to the KHO QEMU selftest. KHO is the remaining architecture gate needed by Live Update (LUO) on LoongArch.

The transport is the central problem. Arm64 and riscv can pass the KHO state FDT and scratch area through properties under /chosen in a boot FDT. LoongArch boots through EFI without a boot FDT, so that path is not available.

I didn't look into your patchset very carefully, but I doubt you are reinventing the wheel. X86 didn't have FDT, seems it introduces FDT for KHO support. LoongArch doesn't have FDT, so you reworks the EFI transport. Is there a reason you don't want to follow the standard KHO way using FDT too?

Please correct me if I am wrong.

Quoted 149 lines

EFI KHO channel:

v5 reworks the EFI transport following Pratyush's and Huacai's reviews [1, 2]. Instead of rebuilding the EFI configuration table in LoongArch code and switching st->tables before kexec, the common EFI stub allocates and installs a persistent table under LINUX_EFI_KEXEC_HANDOVER_GUID. This follows the model used by LINUX_EFI_MEMRESERVE_TABLE_GUID.

The common EFI table parser reserves the stub-allocated table, reads it during early boot, and calls kho_populate(). An early initcall keeps the table persistently mapped so it can also be updated on the crash kexec path. The implementation is architecture-independent; LoongArch only selects EFI_KHO when KEXEC_HANDOVER is enabled.

The EFI table is global, but kexec can keep separate normal and crash images and can replace a loaded candidate. Updating the table while a candidate image is being loaded could therefore leave it pointing at a failed candidate while the previously installed image remains the one that will be executed. v5 records the KHO data in struct kimage and synchronizes the channel from the image selected for execution. Images without KHO data, including legacy and crash images, clear the channel so the next kernel boots cold rather than reviving stale state.

The GUID name is changed to LINUX_EFI_KEXEC_HANDOVER_GUID as suggested by Huacai and Pratyush [3]. Existing x86 KHO support continues to use its setup_data transport. Besides supporting non-UEFI boot, that entry is consumed by the x86 decompressor before normal EFI table parsing, so KASLR only uses KHO scratch areas and does not overwrite preserved memory. The new channel is installed by the generic EFI-stub entry path and relies on EFI_GENERIC_STUB, which x86 does not select. Moving x86 would therefore require installing the table from the x86-specific EFI stub and scanning it in the decompressor, not just selecting EFI_KHO.

LoongArch enablement and build fix:

The architecture patch now only enables ARCH_SUPPORTS_KEXEC_HANDOVER and selects the generic EFI channel. No LoongArch setup reader, kexec writer, or EFI system-table replacement remains.

The linux/mm.h build fix is moved from luo_session.c to kho_block.c, where the virt_to_phys() and phys_to_virt() calls reside after the liveupdate refactoring. This addresses Pratyush's review [4]. Adding linux/mm.h to asm/io.h was previously attempted, but creates an include cycle under CONFIG_KFENCE [5]. The fix precedes LoongArch enablement so every intermediate commit builds with CONFIG_KFENCE=y.

Selftest:

The LoongArch vmtest boots vmlinux.efi through EDK2 because the initial EFI stub invocation installs the channel being tested. QEMU_EFI can override the firmware filename for distributions that install it under a different name or path.

CONFIG_ACPI_SPCR_TABLE lets the bare earlycon parameter obtain the UART description from EDK2's SPCR table. CONFIG_PCI_HOST_GENERIC keeps i8042 enabled while ensuring that the QEMU virt machine's PCI I/O space is mapped before the legacy fallback probe, addressing Huacai's concern that the same kernel configuration should remain usable for hosts and guests.

With EFI runtime reset services available, panic=-1 and QEMU's existing -no-reboot option terminate the test normally. The generic QEMU runner therefore remains unchanged and does not mask failures by forcibly terminating QEMU after a timeout.

The LoongArch vmtest uses the default KHO scratch-sizing path. This series is based on the generic fix that calculates per-node scratch sizes before scratch allocation [6].

The KHO vmtest passes on:

* LoongArch with KVM using QEMU_EFI.fd from edk2-loongarch64.
* x86_64 with KVM, as regression coverage for the generic kexec/KHO changes.

Patch layout:

1. Add the generic EFI KHO channel and its ABI.
2. Synchronize the channel from the selected image at execution.
3. Fix the kho_block.c header dependency exposed by LoongArch/KFENCE.
4. Enable KHO on 64-bit LoongArch through the generic EFI channel.
5. Add LoongArch to the KHO QEMU selftest.

Changes since v4:

* Allocate and install the KHO table from the common EFI stub, following the EFI memreserve-table model (Pratyush).
* Parse, reserve, map, and update the channel in generic EFI code; remove

    the LoongArch-specific reader, writer, and st->tables replacement
    (Pratyush, Huacai).

* Synchronize the global channel at execution rather than image load; clear it for cold and crash images and use the scratch payload size.
* Rename the GUID to LINUX_EFI_KEXEC_HANDOVER_GUID (Huacai, Pratyush).
* Move the linux/mm.h include from luo_session.c to the actual caller, kho_block.c, and place the fix before architecture enablement (Pratyush, Huacai).
* Boot the vmtest through EDK2, allow QEMU_EFI to override the firmware, and use vmlinux.efi to exercise the EFI stub and channel.
* Keep i8042 enabled and select PCI_HOST_GENERIC instead of disabling the host configuration in the selftest (Huacai).
* Enable ACPI_SPCR_TABLE and use the SPCR-provided early console.
* Exercise the default KHO scratch-sizing path in the LoongArch vmtest; depend on the separately posted generic sizing fix [6].
* Drop the generic QEMU timeout now that EFI runtime reset services make the LoongArch guest terminate normally.
* Rebase onto Linux 7.3-rc1.

[1] Pratyush Yadav:

    https://lore.kernel.org/r/[email protected]/

[2] Huacai Chen:
https://lore.kernel.org/r/CAAhV-H4PKRNCa4g=6TGepP+trtM82JiMoWgVr3O7PqbZYP9uGw@mail.gmail.com/
[3] https://lore.kernel.org/r/[email protected]/
[4] https://lore.kernel.org/r/[email protected]/
[5] https://lore.kernel.org/r/[email protected]/
[6] https://lore.kernel.org/loongarch/[email protected]/

Previous version:

v4: https://lore.kernel.org/loongarch/[email protected]/

George Guo (5):
efi: add a KHO configuration table channel
liveupdate: synchronize EFI KHO channel at execution
liveupdate: kho_block: include linux/mm.h for virt/phys translation
LoongArch: enable kexec handover (KHO)
selftests/kho: add LoongArch vmtest support

 arch/loongarch/Kconfig                     |  4 ++
 drivers/firmware/efi/Kconfig               | 12 ++++
 drivers/firmware/efi/efi.c                 | 78 ++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c    | 25 +++++++
 include/linux/efi.h                        | 36 ++++++++++
 kernel/crash_core.c                        |  7 ++
 kernel/kexec_core.c                        |  5 ++
 kernel/kexec_internal.h                    |  3 +
 kernel/liveupdate/kexec_handover.c         | 33 +++++++++
 kernel/liveupdate/kho_block.c              |  1 +
 tools/testing/selftests/kho/loongarch.conf | 11 +++
 tools/testing/selftests/kho/vmtest.sh      |  3 +-
 12 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
prerequisite-patch-id: a2f06addb17cc379b9f98674f087a1642588dc6e

Signature · 1 line
2.53.0
maintainer
#16 lore raw
Quoted 10 lines · Baoquan He
Quoted 8 lines · George Guo

This series enables Kexec HandOver (KHO) on 64-bit LoongArch and adds LoongArch coverage to the KHO QEMU selftest. KHO is the remaining architecture gate needed by Live Update (LUO) on LoongArch.

The transport is the central problem. Arm64 and riscv can pass the KHO state FDT and scratch area through properties under /chosen in a boot FDT. LoongArch boots through EFI without a boot FDT, so that path is not available.

Quoted 7 lines

I didn't look into your patchset very carefully, but I doubt you are reinventing the wheel. X86 didn't have FDT, seems it introduces FDT for KHO support. LoongArch doesn't have FDT, so you reworks the EFI transport. Is there a reason you don't want to follow the standard KHO way using FDT too?

Please correct me if I am wrong.

I was wrong. x86 doesn't introduce FDT, it just adds a SETUP_KEXEC_KHO entry into setup_data in setup_kho(). Please forgot about it, and sorry for the noise.

Quoted 150 lines
Quoted 150 lines

EFI KHO channel:

v5 reworks the EFI transport following Pratyush's and Huacai's reviews [1, 2]. Instead of rebuilding the EFI configuration table in LoongArch code and switching st->tables before kexec, the common EFI stub allocates and installs a persistent table under LINUX_EFI_KEXEC_HANDOVER_GUID. This follows the model used by LINUX_EFI_MEMRESERVE_TABLE_GUID.

The common EFI table parser reserves the stub-allocated table, reads it during early boot, and calls kho_populate(). An early initcall keeps the table persistently mapped so it can also be updated on the crash kexec path. The implementation is architecture-independent; LoongArch only selects EFI_KHO when KEXEC_HANDOVER is enabled.

The EFI table is global, but kexec can keep separate normal and crash images and can replace a loaded candidate. Updating the table while a candidate image is being loaded could therefore leave it pointing at a failed candidate while the previously installed image remains the one that will be executed. v5 records the KHO data in struct kimage and synchronizes the channel from the image selected for execution. Images without KHO data, including legacy and crash images, clear the channel so the next kernel boots cold rather than reviving stale state.

The GUID name is changed to LINUX_EFI_KEXEC_HANDOVER_GUID as suggested by Huacai and Pratyush [3]. Existing x86 KHO support continues to use its setup_data transport. Besides supporting non-UEFI boot, that entry is consumed by the x86 decompressor before normal EFI table parsing, so KASLR only uses KHO scratch areas and does not overwrite preserved memory. The new channel is installed by the generic EFI-stub entry path and relies on EFI_GENERIC_STUB, which x86 does not select. Moving x86 would therefore require installing the table from the x86-specific EFI stub and scanning it in the decompressor, not just selecting EFI_KHO.

LoongArch enablement and build fix:

The architecture patch now only enables ARCH_SUPPORTS_KEXEC_HANDOVER and selects the generic EFI channel. No LoongArch setup reader, kexec writer, or EFI system-table replacement remains.

The linux/mm.h build fix is moved from luo_session.c to kho_block.c, where the virt_to_phys() and phys_to_virt() calls reside after the liveupdate refactoring. This addresses Pratyush's review [4]. Adding linux/mm.h to asm/io.h was previously attempted, but creates an include cycle under CONFIG_KFENCE [5]. The fix precedes LoongArch enablement so every intermediate commit builds with CONFIG_KFENCE=y.

Selftest:

The LoongArch vmtest boots vmlinux.efi through EDK2 because the initial EFI stub invocation installs the channel being tested. QEMU_EFI can override the firmware filename for distributions that install it under a different name or path.

CONFIG_ACPI_SPCR_TABLE lets the bare earlycon parameter obtain the UART description from EDK2's SPCR table. CONFIG_PCI_HOST_GENERIC keeps i8042 enabled while ensuring that the QEMU virt machine's PCI I/O space is mapped before the legacy fallback probe, addressing Huacai's concern that the same kernel configuration should remain usable for hosts and guests.

With EFI runtime reset services available, panic=-1 and QEMU's existing -no-reboot option terminate the test normally. The generic QEMU runner therefore remains unchanged and does not mask failures by forcibly terminating QEMU after a timeout.

The LoongArch vmtest uses the default KHO scratch-sizing path. This series is based on the generic fix that calculates per-node scratch sizes before scratch allocation [6].

The KHO vmtest passes on:

* LoongArch with KVM using QEMU_EFI.fd from edk2-loongarch64.
* x86_64 with KVM, as regression coverage for the generic kexec/KHO changes.

Patch layout:

1. Add the generic EFI KHO channel and its ABI.
2. Synchronize the channel from the selected image at execution.
3. Fix the kho_block.c header dependency exposed by LoongArch/KFENCE.
4. Enable KHO on 64-bit LoongArch through the generic EFI channel.
5. Add LoongArch to the KHO QEMU selftest.

Changes since v4:

* Allocate and install the KHO table from the common EFI stub, following the EFI memreserve-table model (Pratyush).
* Parse, reserve, map, and update the channel in generic EFI code; remove

    the LoongArch-specific reader, writer, and st->tables replacement
    (Pratyush, Huacai).

* Synchronize the global channel at execution rather than image load; clear it for cold and crash images and use the scratch payload size.
* Rename the GUID to LINUX_EFI_KEXEC_HANDOVER_GUID (Huacai, Pratyush).
* Move the linux/mm.h include from luo_session.c to the actual caller, kho_block.c, and place the fix before architecture enablement (Pratyush, Huacai).
* Boot the vmtest through EDK2, allow QEMU_EFI to override the firmware, and use vmlinux.efi to exercise the EFI stub and channel.
* Keep i8042 enabled and select PCI_HOST_GENERIC instead of disabling the host configuration in the selftest (Huacai).
* Enable ACPI_SPCR_TABLE and use the SPCR-provided early console.
* Exercise the default KHO scratch-sizing path in the LoongArch vmtest; depend on the separately posted generic sizing fix [6].
* Drop the generic QEMU timeout now that EFI runtime reset services make the LoongArch guest terminate normally.
* Rebase onto Linux 7.3-rc1.

[1] Pratyush Yadav:

    https://lore.kernel.org/r/[email protected]/

[2] Huacai Chen:
https://lore.kernel.org/r/CAAhV-H4PKRNCa4g=6TGepP+trtM82JiMoWgVr3O7PqbZYP9uGw@mail.gmail.com/
[3] https://lore.kernel.org/r/[email protected]/
[4] https://lore.kernel.org/r/[email protected]/
[5] https://lore.kernel.org/r/[email protected]/
[6] https://lore.kernel.org/loongarch/[email protected]/

Previous version:

v4: https://lore.kernel.org/loongarch/[email protected]/

George Guo (5):
efi: add a KHO configuration table channel
liveupdate: synchronize EFI KHO channel at execution
liveupdate: kho_block: include linux/mm.h for virt/phys translation
LoongArch: enable kexec handover (KHO)
selftests/kho: add LoongArch vmtest support

 arch/loongarch/Kconfig                     |  4 ++
 drivers/firmware/efi/Kconfig               | 12 ++++
 drivers/firmware/efi/efi.c                 | 78 ++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c    | 25 +++++++
 include/linux/efi.h                        | 36 ++++++++++
 kernel/crash_core.c                        |  7 ++
 kernel/kexec_core.c                        |  5 ++
 kernel/kexec_internal.h                    |  3 +
 kernel/liveupdate/kexec_handover.c         | 33 +++++++++
 kernel/liveupdate/kho_block.c              |  1 +
 tools/testing/selftests/kho/loongarch.conf | 11 +++
 tools/testing/selftests/kho/vmtest.sh      |  3 +-
 12 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
prerequisite-patch-id: a2f06addb17cc379b9f98674f087a1642588dc6e

Signature · 1 line
2.53.0
maintainer
#17 lore raw
In reply to George Guo

Hi, George,

Quoted 126 lines · George Guo

This series enables Kexec HandOver (KHO) on 64-bit LoongArch and adds LoongArch coverage to the KHO QEMU selftest. KHO is the remaining architecture gate needed by Live Update (LUO) on LoongArch.

The transport is the central problem. Arm64 and riscv can pass the KHO state FDT and scratch area through properties under /chosen in a boot FDT. LoongArch boots through EFI without a boot FDT, so that path is not available.

EFI KHO channel:

v5 reworks the EFI transport following Pratyush's and Huacai's reviews [1, 2]. Instead of rebuilding the EFI configuration table in LoongArch code and switching st->tables before kexec, the common EFI stub allocates and installs a persistent table under LINUX_EFI_KEXEC_HANDOVER_GUID. This follows the model used by LINUX_EFI_MEMRESERVE_TABLE_GUID.

The common EFI table parser reserves the stub-allocated table, reads it during early boot, and calls kho_populate(). An early initcall keeps the table persistently mapped so it can also be updated on the crash kexec path. The implementation is architecture-independent; LoongArch only selects EFI_KHO when KEXEC_HANDOVER is enabled.

The EFI table is global, but kexec can keep separate normal and crash images and can replace a loaded candidate. Updating the table while a candidate image is being loaded could therefore leave it pointing at a failed candidate while the previously installed image remains the one that will be executed. v5 records the KHO data in struct kimage and synchronizes the channel from the image selected for execution. Images without KHO data, including legacy and crash images, clear the channel so the next kernel boots cold rather than reviving stale state.

The GUID name is changed to LINUX_EFI_KEXEC_HANDOVER_GUID as suggested by Huacai and Pratyush [3]. Existing x86 KHO support continues to use its setup_data transport. Besides supporting non-UEFI boot, that entry is consumed by the x86 decompressor before normal EFI table parsing, so KASLR only uses KHO scratch areas and does not overwrite preserved memory. The new channel is installed by the generic EFI-stub entry path and relies on EFI_GENERIC_STUB, which x86 does not select. Moving x86 would therefore require installing the table from the x86-specific EFI stub and scanning it in the decompressor, not just selecting EFI_KHO.

LoongArch enablement and build fix:

The architecture patch now only enables ARCH_SUPPORTS_KEXEC_HANDOVER and selects the generic EFI channel. No LoongArch setup reader, kexec writer, or EFI system-table replacement remains.

The linux/mm.h build fix is moved from luo_session.c to kho_block.c, where the virt_to_phys() and phys_to_virt() calls reside after the liveupdate refactoring. This addresses Pratyush's review [4]. Adding linux/mm.h to asm/io.h was previously attempted, but creates an include cycle under CONFIG_KFENCE [5]. The fix precedes LoongArch enablement so every intermediate commit builds with CONFIG_KFENCE=y.

Selftest:

The LoongArch vmtest boots vmlinux.efi through EDK2 because the initial EFI stub invocation installs the channel being tested. QEMU_EFI can override the firmware filename for distributions that install it under a different name or path.

CONFIG_ACPI_SPCR_TABLE lets the bare earlycon parameter obtain the UART description from EDK2's SPCR table. CONFIG_PCI_HOST_GENERIC keeps i8042 enabled while ensuring that the QEMU virt machine's PCI I/O space is mapped before the legacy fallback probe, addressing Huacai's concern that the same kernel configuration should remain usable for hosts and guests.

With EFI runtime reset services available, panic=-1 and QEMU's existing -no-reboot option terminate the test normally. The generic QEMU runner therefore remains unchanged and does not mask failures by forcibly terminating QEMU after a timeout.

The LoongArch vmtest uses the default KHO scratch-sizing path. This series is based on the generic fix that calculates per-node scratch sizes before scratch allocation [6].

The KHO vmtest passes on:

* LoongArch with KVM using QEMU_EFI.fd from edk2-loongarch64.
* x86_64 with KVM, as regression coverage for the generic kexec/KHO changes.

Patch layout:

1. Add the generic EFI KHO channel and its ABI.
2. Synchronize the channel from the selected image at execution.
3. Fix the kho_block.c header dependency exposed by LoongArch/KFENCE.
4. Enable KHO on 64-bit LoongArch through the generic EFI channel.
5. Add LoongArch to the KHO QEMU selftest.

Changes since v4:

* Allocate and install the KHO table from the common EFI stub, following the EFI memreserve-table model (Pratyush).
* Parse, reserve, map, and update the channel in generic EFI code; remove

    the LoongArch-specific reader, writer, and st->tables replacement
    (Pratyush, Huacai).

* Synchronize the global channel at execution rather than image load; clear it for cold and crash images and use the scratch payload size.
* Rename the GUID to LINUX_EFI_KEXEC_HANDOVER_GUID (Huacai, Pratyush).
* Move the linux/mm.h include from luo_session.c to the actual caller, kho_block.c, and place the fix before architecture enablement (Pratyush, Huacai).
* Boot the vmtest through EDK2, allow QEMU_EFI to override the firmware, and use vmlinux.efi to exercise the EFI stub and channel.
* Keep i8042 enabled and select PCI_HOST_GENERIC instead of disabling the host configuration in the selftest (Huacai).
* Enable ACPI_SPCR_TABLE and use the SPCR-provided early console.
* Exercise the default KHO scratch-sizing path in the LoongArch vmtest; depend on the separately posted generic sizing fix [6].
* Drop the generic QEMU timeout now that EFI runtime reset services make the LoongArch guest terminate normally.
* Rebase onto Linux 7.3-rc1.

[1] Pratyush Yadav:

    https://lore.kernel.org/r/[email protected]/

[2] Huacai Chen:
https://lore.kernel.org/r/CAAhV-H4PKRNCa4g=6TGepP+trtM82JiMoWgVr3O7PqbZYP9uGw@mail.gmail.com/
[3] https://lore.kernel.org/r/[email protected]/
[4] https://lore.kernel.org/r/[email protected]/
[5] https://lore.kernel.org/r/[email protected]/
[6] https://lore.kernel.org/loongarch/[email protected]/

Quoted 6 lines

Previous version:

v4: https://lore.kernel.org/loongarch/[email protected]/

George Guo (5):
efi: add a KHO configuration table channel

Add....

Quoted 1 line

liveupdate: synchronize EFI KHO channel at execution

Synchronize.....

Quoted 1 line

liveupdate: kho_block: include linux/mm.h for virt/phys translation

Include..... (and I think kho_block can be removed)

Quoted 1 line

LoongArch: enable kexec handover (KHO)

Enable.....

Quoted 1 line

selftests/kho: add LoongArch vmtest support

Add.....

Huacai

Quoted 21 lines
 arch/loongarch/Kconfig                     |  4 ++
 drivers/firmware/efi/Kconfig               | 12 ++++
 drivers/firmware/efi/efi.c                 | 78 ++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c    | 25 +++++++
 include/linux/efi.h                        | 36 ++++++++++
 kernel/crash_core.c                        |  7 ++
 kernel/kexec_core.c                        |  5 ++
 kernel/kexec_internal.h                    |  3 +
 kernel/liveupdate/kexec_handover.c         | 33 +++++++++
 kernel/liveupdate/kho_block.c              |  1 +
 tools/testing/selftests/kho/loongarch.conf | 11 +++
 tools/testing/selftests/kho/vmtest.sh      |  3 +-
 12 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
prerequisite-patch-id: a2f06addb17cc379b9f98674f087a1642588dc6e --
2.53.0