Skip to contentSkip to conversation

LoongArch: add KHO support and selftests

PATCH Superseded George Guo 4 participants 21 messages Aug 7 – Sep 4

Subsystems (7)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

George Guo

author
#0 lore raw

v4 cover LoongArch: add KHO support and selftests

This series enables Kexec Handover (KHO) on LoongArch, making it the third architecture (after x86 and arm64) to set ARCH_SUPPORTS_KEXEC_HANDOVER. That is the only remaining gate for Live Update (LUO) to run on LoongArch.

The hard part is the transport: how the first kernel hands the KHO state (the KHO FDT and the scratch region) to the second kernel across kexec.

Why not the command line or an FDT
----------------------------------

LoongArch boots from EFI, but unlike arm64 and riscv its efistub does not build a boot FDT. It passes the EFI system table and the command line straight to the core kernel [1]. There is no /chosen node to carry the blob, so the arm64 path (drivers/of/kexec.c:kho_add_chosen() writes linux,kho-fdt and linux,kho-scratch; drivers/of/fdt.c:
early_init_dt_check_kho() reads them) does not apply.

Two earlier transports were tried and rejected:

* v1 put the handover addresses on the kernel command line. Pratyush found that odd and asked for a DT-based alternative.

* v2/v3 synthesized an FDT and rewrote the DEVICE_TREE_GUID entry in the EFI config table so the generic FDT reader would find it. Pratyush called that "even more hacky" than the command line [2].

The v4 transport
----------------

v4 follows the x86 setup_data idea, in EFI terms. The first kernel packs the KHO state into a small struct (linux_efi_kho_data: fdt addr/size and scratch addr/size), appends a pointer to it under a dedicated LINUX_EFI_KHO_TABLE_GUID entry in a new EFI config table, loads both as kexec segments, and switches st->tables before jumping. The second kernel scans the config table for that GUID in setup_arch() and calls kho_populate() directly. This is the approach proposed in [3].

It addresses both objections: nothing is exposed on the command line, and no FDT is synthesized. It also meets Huacai's constraint: it reuses the EFI system table LoongArch already has, with no dependency on a boot FDT the efistub never creates.

Patch layout
------------

Patches 1-2 implement the transport. Patch 1 adds the EFI config table GUID and the handover struct to include/linux/efi.h. It is split out so the EFI maintainers can review it on its own. Patch 2 wires up the LoongArch side: ARCH_SUPPORTS_KEXEC_HANDOVER, the write side in machine_kexec_file.c, the st->tables switch in machine_kexec(), and the reader in setup_arch().

Patch 3 is a build fix for kernel/liveupdate/luo_session.c that the series depends on under CONFIG_KFENCE=y on LoongArch. It was sent standalone as v2 and acked by Mike. It is folded in here at his request to send it along with this series [4].

Patch 4 adds LoongArch vmtest support to the KHO selftests and folds in the two points Mike raised on v3 (use "VM" instead of the ad-hoc "virt machine"; run every architecture under timeout(1), not only LoongArch).

Patch 1 is aimed at the EFI tree. Patches 2-4 are aimed at the LoongArch and KHO trees. I expect the whole series to go through the KHO tree with Ard's and Huacai's acks.

Changes since v3
----------------

* Rework the transport: drop the synthesized FDT and the DEVICE_TREE_GUID rewrite. Pass the KHO state through a dedicated EFI configuration table GUID and call kho_populate() directly (patches 1, 2).
* Fold in the luo_session build fix (previously standalone v2, acked by Mike) as patch 3, at his request.
* selftests: address Mike's v3 review (use "VM"; always run under

    timeout(1)).

* Rebase onto v7.2-rc6.

[1] Huacai Chen: https://lore.kernel.org/r/CAAhV-H5B6Mj2-AffkstJ4f8EEmvvPOGXoDy2QNudKD2kSz2XkA@mail.gmail.com/
[2] Pratyush Yadav: https://lore.kernel.org/r/[email protected]/
[3] https://lore.kernel.org/r/[email protected]/
[4] Mike Rapoport: https://lore.kernel.org/r/[email protected]/

George Guo (4):
efi: add a KHO configuration table GUID
LoongArch: kexec: add KHO support
liveupdate: luo_session: include linux/mm.h for virt/phys translation selftests/kho: add LoongArch vmtest support

 arch/loongarch/Kconfig                     |   3 +
 arch/loongarch/include/asm/kexec.h         |   7 ++
 arch/loongarch/kernel/machine_kexec.c      |  16 +++
 arch/loongarch/kernel/machine_kexec_file.c | 131 +++++++++++++++++++++
 arch/loongarch/kernel/setup.c              |  41 +++++++
 include/linux/efi.h                        |  24 ++++
 kernel/liveupdate/luo_session.c            |   1 +
 tools/testing/selftests/kho/loongarch.conf |  11 ++
 tools/testing/selftests/kho/vmtest.sh      |  22 ++--
 9 files changed, 249 insertions(+), 7 deletions(-)
 create mode 100644 tools/testing/selftests/kho/loongarch.conf
Signature · 1 line
2.53.0
author
#1 lore raw

PATCH v4 1/4 efi: add a KHO configuration table GUID

From: George Guo <[email protected]>

Kexec Handover (KHO) passes the address of its state FDT and of its scratch area from the current kernel to the next one. On architectures that boot with a device tree, the current kernel writes the linux,kho-fdt and linux,kho-scratch properties into /chosen, and the next kernel reads them back in early_init_dt_check_kho().

Architectures that boot through EFI without a device tree have no such channel. LoongArch is one of them: its efistub passes the EFI system table and the command line to the core kernel directly and never creates an FDT. x86 has the same problem and carries the state out of band instead, in a struct kho_data in the setup_data chain of its boot protocol.

Add an out-of-band channel for EFI: a LINUX_EFI_KHO_TABLE_GUID configuration table entry, under a randomly generated GUID, pointing at a struct linux_efi_kho_data. The
current kernel loads the structure and an extended configuration table as kexec segments, then switches the EFI system table to the new table before jumping. The next kernel finds the entry by GUID and calls kho_populate().

The structure carries no version field. An incompatible change to the layout must use a new GUID, which is the usual rule for EFI configuration tables. The handover payload itself is versioned separately, by the compatible string of the KHO state FDT that kho_populate() checks.

This patch adds the definitions only. LoongArch is the first user; any other EFI architecture without a boot FDT can use the same channel.

---
 include/linux/efi.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/efi.h +24 -0
index ccbc35479684..789ab9e4312a 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_KHO_TABLE_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)
 
@@ -1271,6 +1272,29 @@ struct linux_efi_memreserve {
 
 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
 
+/*
+ * The LINUX_EFI_KHO_TABLE_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, where the /chosen linux,kho-fdt and linux,kho-scratch
+ * properties read by early_init_dt_check_kho() are not available.  The current
+ * kernel loads the structure and an extended configuration table as kexec
+ * segments; the next kernel finds it by GUID and calls kho_populate().
+ *
+ * The layout is an ABI between the two kernels and is fixed.  It carries no
+ * version field: an incompatible change must use a new GUID, and 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;
+
 /*
  * 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 v4 1/4] efi: add a KHO configuration table GUID

Hi, George,

Quoted 42 lines · George Guo

From: George Guo <[email protected]>

Kexec Handover (KHO) passes the address of its state FDT and of its scratch area from the current kernel to the next one. On architectures that boot with a device tree, the current kernel writes the linux,kho-fdt and linux,kho-scratch properties into /chosen, and the next kernel reads them back in early_init_dt_check_kho().

Architectures that boot through EFI without a device tree have no such channel. LoongArch is one of them: its efistub passes the EFI system table and the command line to the core kernel directly and never creates an FDT. x86 has the same problem and carries the state out of band instead, in a struct kho_data in the setup_data chain of its boot protocol.

Add an out-of-band channel for EFI: a LINUX_EFI_KHO_TABLE_GUID configuration table entry, under a randomly generated GUID, pointing at a struct linux_efi_kho_data. The
current kernel loads the structure and an extended configuration table as kexec segments, then switches the EFI system table to the new table before jumping. The next kernel finds the entry by GUID and calls kho_populate().

The structure carries no version field. An incompatible change to the layout must use a new GUID, which is the usual rule for EFI configuration tables. The handover payload itself is versioned separately, by the compatible string of the KHO state FDT that kho_populate() checks.

This patch adds the definitions only. LoongArch is the first user; any other EFI architecture without a boot FDT can use the same channel.

---
 include/linux/efi.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/efi.h +0 -0
index ccbc35479684..789ab9e4312a 100644

include/linux/efi.h void efi_native_runtime_setup(void); · line 425

Quoted 4 lines
include/linux/efi.h +1 -0
@@ -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_KHO_TABLE_GUID               EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)

I don't know whether it is allowed to define a new TABLE ID while doesn't touch the UEFI SPEC.

Huacai

Quoted 36 lines
include/linux/efi.h +23 -1
 #define RISCV_EFI_BOOT_PROTOCOL_GUID           EFI_GUID(0xccd15fec, 0x6f73, 0x4eec,  0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
 
@@ -1271,6 +1272,29 @@ struct linux_efi_memreserve {
 
 void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
 
+/*
+ * The LINUX_EFI_KHO_TABLE_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, where the /chosen linux,kho-fdt and linux,kho-scratch
+ * properties read by early_init_dt_check_kho() are not available.  The current
+ * kernel loads the structure and an extended configuration table as kexec
+ * segments; the next kernel finds it by GUID and calls kho_populate().
+ *
+ * The layout is an ABI between the two kernels and is fixed.  It carries no
+ * version field: an incompatible change must use a new GUID, and 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;
+
 /*
  * 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 v4 1/4] efi: add a KHO configuration table GUID

Quoted 40 lines · Huacai Chen

Hi, George,

Quoted 37 lines · George Guo

From: George Guo <[email protected]>

Kexec Handover (KHO) passes the address of its state FDT and of its scratch area from the current kernel to the next one. On architectures that boot with a device tree, the current kernel writes the linux,kho-fdt and linux,kho-scratch properties into /chosen, and the next kernel reads them back in early_init_dt_check_kho().

Architectures that boot through EFI without a device tree have no such channel. LoongArch is one of them: its efistub passes the EFI system table and the command line to the core kernel directly and never creates an FDT. x86 has the same problem and carries the state out of band instead, in a struct kho_data in the setup_data chain of its boot protocol.

Add an out-of-band channel for EFI: a LINUX_EFI_KHO_TABLE_GUID configuration table entry, under a randomly generated GUID, pointing at a struct linux_efi_kho_data. The
current kernel loads the structure and an extended configuration table as kexec segments, then switches the EFI system table to the new table before jumping. The next kernel finds the entry by GUID and calls kho_populate().

The structure carries no version field. An incompatible change to the layout must use a new GUID, which is the usual rule for EFI configuration tables. The handover payload itself is versioned separately, by the compatible string of the KHO state FDT that kho_populate() checks.

This patch adds the definitions only. LoongArch is the first user; any other EFI architecture without a boot FDT can use the same channel.

---
 include/linux/efi.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
Quoted 12 lines

include/linux/efi.h void efi_native_runtime_setup(void); · line 425

Quoted 9 lines
include/linux/efi.h +1 -0
index ccbc35479684..789ab9e4312a 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_KHO_TABLE_GUID               EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)

I don't know whether it is allowed to define a new TABLE ID while doesn't touch the UEFI SPEC.

That is fine in principle: the whole reason for using GUIDs as identifiers in UEFI is that everyone can invent their own, and the risk of conflicts is negligible.

All LINUX_EFI_* GUIDs are Linux inventions, and are not mentioned in the UEFI spec at all.

maintainer
#4 lore raw

Re: [PATCH v4 1/4] efi: add a KHO configuration table GUID

Quoted 57 lines · Ard Biesheuvel
Quoted 40 lines · Huacai Chen

Hi, George,

Quoted 37 lines · George Guo

From: George Guo <[email protected]>

Kexec Handover (KHO) passes the address of its state FDT and of its scratch area from the current kernel to the next one. On architectures that boot with a device tree, the current kernel writes the linux,kho-fdt and linux,kho-scratch properties into /chosen, and the next kernel reads them back in early_init_dt_check_kho().

Architectures that boot through EFI without a device tree have no such channel. LoongArch is one of them: its efistub passes the EFI system table and the command line to the core kernel directly and never creates an FDT. x86 has the same problem and carries the state out of band instead, in a struct kho_data in the setup_data chain of its boot protocol.

Add an out-of-band channel for EFI: a LINUX_EFI_KHO_TABLE_GUID configuration table entry, under a randomly generated GUID, pointing at a struct linux_efi_kho_data. The
current kernel loads the structure and an extended configuration table as kexec segments, then switches the EFI system table to the new table before jumping. The next kernel finds the entry by GUID and calls kho_populate().

The structure carries no version field. An incompatible change to the layout must use a new GUID, which is the usual rule for EFI configuration tables. The handover payload itself is versioned separately, by the compatible string of the KHO state FDT that kho_populate() checks.

This patch adds the definitions only. LoongArch is the first user; any other EFI architecture without a boot FDT can use the same channel.

---
 include/linux/efi.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
Quoted 12 lines

include/linux/efi.h void efi_native_runtime_setup(void); · line 425

Quoted 9 lines
include/linux/efi.h +1 -0
index ccbc35479684..789ab9e4312a 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_KHO_TABLE_GUID               EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)

I don't know whether it is allowed to define a new TABLE ID while doesn't touch the UEFI SPEC.

Quoted 6 lines

That is fine in principle: the whole reason for using GUIDs as identifiers in UEFI is that everyone can invent their own, and the risk of conflicts is negligible.

All LINUX_EFI_* GUIDs are Linux inventions, and are not mentioned in the UEFI spec at all.

OK, then I think the direction of this series is correct now, and I hope there will be more archs share this GUID.

BTW, I think LINUX_EFI_KEXEC_HANDOVER_GUID may be a little better than LINUX_EFI_KHO_TABLE_GUID.

Huacai

Quoted 1 line
maintainer
#5 lore raw

Re: [PATCH v4 1/4] efi: add a KHO configuration table GUID

Quoted 58 lines · Huacai Chen
Quoted 57 lines · Ard Biesheuvel
Quoted 52 lines · Huacai Chen

Hi, George,

Quoted 42 lines · George Guo

From: George Guo <[email protected]>

Kexec Handover (KHO) passes the address of its state FDT and of its scratch area from the current kernel to the next one. On architectures that boot with a device tree, the current kernel writes the linux,kho-fdt and linux,kho-scratch properties into /chosen, and the next kernel reads them back in early_init_dt_check_kho().

Architectures that boot through EFI without a device tree have no such channel. LoongArch is one of them: its efistub passes the EFI system table and the command line to the core kernel directly and never creates an FDT. x86 has the same problem and carries the state out of band instead, in a struct kho_data in the setup_data chain of its boot protocol.

Add an out-of-band channel for EFI: a LINUX_EFI_KHO_TABLE_GUID configuration table entry, under a randomly generated GUID, pointing at a struct linux_efi_kho_data. The
current kernel loads the structure and an extended configuration table as kexec segments, then switches the EFI system table to the new table before jumping. The next kernel finds the entry by GUID and calls kho_populate().

The structure carries no version field. An incompatible change to the layout must use a new GUID, which is the usual rule for EFI configuration tables. The handover payload itself is versioned separately, by the compatible string of the KHO state FDT that kho_populate() checks.

This patch adds the definitions only. LoongArch is the first user; any other EFI architecture without a boot FDT can use the same channel.

---
 include/linux/efi.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/efi.h +0 -0
index ccbc35479684..789ab9e4312a 100644

include/linux/efi.h void efi_native_runtime_setup(void); · line 425

Quoted 4 lines
include/linux/efi.h +1 -0
@@ -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_KHO_TABLE_GUID               EFI_GUID(0xc941b6c7, 0x7b3f, 0x4af6,  0x9e, 0x50, 0xfc, 0xb3, 0xa8, 0x86, 0x8a, 0x17)

I don't know whether it is allowed to define a new TABLE ID while doesn't touch the UEFI SPEC.

Quoted 8 lines
Quoted 6 lines

That is fine in principle: the whole reason for using GUIDs as identifiers in UEFI is that everyone can invent their own, and the risk of conflicts is negligible.

All LINUX_EFI_* GUIDs are Linux inventions, and are not mentioned in the UEFI spec at all.

OK, then I think the direction of this series is correct now, and I hope there will be more archs share this GUID.

Agreed.

Perhaps we can move x86 over to use this as well? If I understand correctly, pretty much all modern x86 systems have UEFI, so it would make sense for KHO to directly use the generic UEFI bits for x86 as well instead of having it via setup data.

Quoted 3 lines

BTW, I think LINUX_EFI_KEXEC_HANDOVER_GUID may be a little better than LINUX_EFI_KHO_TABLE_GUID.

+1, that sounds better.

Signature · 2 lines
Regards,
Pratyush Yadav
author
#6 lore raw

PATCH v4 2/4 LoongArch: kexec: add KHO support

In reply to George Guo

From: George Guo <[email protected]>

Enable Kexec Handover (KHO) on LoongArch64.

LoongArch has no boot FDT: the efistub passes the EFI system table and the command line to the core kernel directly, so the arm64 /chosen path (append linux,kho-fdt / linux,kho-scratch and let early_init_dt_check_kho() read them) does not apply. Follow the x86 model instead, which has no boot FDT either: carry the KHO pointer out of band and call kho_populate() directly. The channel is the EFI configuration table entry added by the previous patch.

- Kconfig: ARCH_SUPPORTS_KEXEC_HANDOVER is def_bool 64BIT.
- machine_kexec_file.c: kho_load_data() builds a small handover blob (struct linux_efi_kho_data) holding the KHO state FDT and scratch addresses, and a new EFI configuration table with a LINUX_EFI_KHO_TABLE_GUID entry pointing to it; both are loaded as kexec segments.
- machine_kexec.c: before jumping to the next kernel, switch the EFI system table to the extended configuration table.
- setup.c: kho_populate_from_efi() scans the configuration table for LINUX_EFI_KHO_TABLE_GUID and calls kho_populate() from setup_arch(), after efi_init() and before memblock_init().

Handover is set up by the kexec_file_load() syscall only. kho_load_data() runs from load_other_segments(), which the older kexec_load() syscall does not reach. This matches x86, where KHO lives in the bzImage64 loader.

Tested on a LoongArch machine booting through ACPI/UEFI. After the kexec, the second kernel reports

KHO: found kexec handover data.

and the two-stage test passes: luo_kexec_simple --stage 1, kexec into the second kernel, then luo_kexec_simple --stage 2.

---
 arch/loongarch/Kconfig                     |   3 +
 arch/loongarch/include/asm/kexec.h         |   7 ++
 arch/loongarch/kernel/machine_kexec.c      |  16 +++
 arch/loongarch/kernel/machine_kexec_file.c | 131 +++++++++++++++++++++
 arch/loongarch/kernel/setup.c              |  41 +++++++
 5 files changed, 198 insertions(+)
arch/loongarch/Kconfig +3 -0
index d8d252325017..698828ef70f0 100644
@@ -684,6 +684,9 @@ config ARCH_SUPPORTS_KEXEC
 config ARCH_SUPPORTS_KEXEC_FILE
 	def_bool 64BIT
 
+config ARCH_SUPPORTS_KEXEC_HANDOVER
+	def_bool 64BIT
+
 config ARCH_SELECTS_KEXEC_FILE
 	def_bool 64BIT
 	depends on KEXEC_FILE
arch/loongarch/include/asm/kexec.h +7 -0
index 6be136e9f0a0..2bcc8bc0d3cc 100644
@@ -39,6 +39,13 @@ struct kimage_arch {
 	unsigned long efi_boot;
 	unsigned long cmdline_ptr;
 	unsigned long systable_ptr;
+#ifdef CONFIG_KEXEC_HANDOVER
+	void *kho_data;			/* KHO handover blob buffer (virtual) */
+	unsigned long kho_data_mem;	/* physical address of the KHO handover blob */
+	void *efi_tables;		/* new EFI config table buffer (virtual) */
+	unsigned long efi_tables_mem;	/* physical address of new EFI config table */
+	unsigned long efi_tables_cnt;	/* number of entries in new EFI config table */
+#endif
 };
 
 struct kimage;
arch/loongarch/kernel/machine_kexec.c +16 -0
index 1883cae93bc3..c98a5607684d 100644
@@ -6,6 +6,7 @@
  */
 #include <linux/compiler.h>
 #include <linux/cpu.h>
+#include <linux/efi.h>
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 #include <linux/delay.h>
@@ -287,6 +288,21 @@ void machine_kexec(struct kimage *image)
 	pr_notice("We will call new kernel at 0x%lx\n", start_addr);
 	pr_notice("Bye ...\n");
 
+#ifdef CONFIG_KEXEC_HANDOVER
+	/*
+	 * KHO: switch the EFI system table to the extended configuration table
+	 * built in kho_load_data(), which carries the LINUX_EFI_KHO_TABLE_GUID
+	 * entry the next kernel reads to find the KHO handover blob.
+	 */
+	if (internal->efi_tables_mem) {
+		efi_system_table_t *st =
+			(efi_system_table_t *)TO_CACHE(systable_ptr);
+
+		st->tables    = internal->efi_tables_mem;
+		st->nr_tables = internal->efi_tables_cnt;
+	}
+#endif
+
 	/* Make reboot code buffer available to the boot CPU. */
 	flush_cache_all();
 
arch/loongarch/kernel/machine_kexec_file.c +131 -0

161 lines not on this page · raw message

arch/loongarch/kernel/setup.c +41 -0

59 lines not on this page · raw message

Signature · 1 line
2.53.0
maintainer
#7 lore raw

Re: [PATCH v4 2/4] LoongArch: kexec: add KHO support

Hi, George,

Quoted 181 lines · George Guo

From: George Guo <[email protected]>

Enable Kexec Handover (KHO) on LoongArch64.

LoongArch has no boot FDT: the efistub passes the EFI system table and the command line to the core kernel directly, so the arm64 /chosen path (append linux,kho-fdt / linux,kho-scratch and let early_init_dt_check_kho() read them) does not apply. Follow the x86 model instead, which has no boot FDT either: carry the KHO pointer out of band and call kho_populate() directly. The channel is the EFI configuration table entry added by the previous patch.

- Kconfig: ARCH_SUPPORTS_KEXEC_HANDOVER is def_bool 64BIT.
- machine_kexec_file.c: kho_load_data() builds a small handover blob (struct linux_efi_kho_data) holding the KHO state FDT and scratch addresses, and a new EFI configuration table with a LINUX_EFI_KHO_TABLE_GUID entry pointing to it; both are loaded as kexec segments.
- machine_kexec.c: before jumping to the next kernel, switch the EFI system table to the extended configuration table.
- setup.c: kho_populate_from_efi() scans the configuration table for LINUX_EFI_KHO_TABLE_GUID and calls kho_populate() from setup_arch(), after efi_init() and before memblock_init().

Handover is set up by the kexec_file_load() syscall only. kho_load_data() runs from load_other_segments(), which the older kexec_load() syscall does not reach. This matches x86, where KHO lives in the bzImage64 loader.

Tested on a LoongArch machine booting through ACPI/UEFI. After the kexec, the second kernel reports

KHO: found kexec handover data.

and the two-stage test passes: luo_kexec_simple --stage 1, kexec into the second kernel, then luo_kexec_simple --stage 2.

---
 arch/loongarch/Kconfig                     |   3 +
 arch/loongarch/include/asm/kexec.h         |   7 ++
 arch/loongarch/kernel/machine_kexec.c      |  16 +++
 arch/loongarch/kernel/machine_kexec_file.c | 131 +++++++++++++++++++++
 arch/loongarch/kernel/setup.c              |  41 +++++++
 5 files changed, 198 insertions(+)
arch/loongarch/Kconfig +3 -0
index d8d252325017..698828ef70f0 100644
@@ -684,6 +684,9 @@ config ARCH_SUPPORTS_KEXEC
 config ARCH_SUPPORTS_KEXEC_FILE
        def_bool 64BIT
 
+config ARCH_SUPPORTS_KEXEC_HANDOVER
+       def_bool 64BIT
+
 config ARCH_SELECTS_KEXEC_FILE
        def_bool 64BIT
        depends on KEXEC_FILE
arch/loongarch/include/asm/kexec.h +7 -0
index 6be136e9f0a0..2bcc8bc0d3cc 100644
@@ -39,6 +39,13 @@ struct kimage_arch {
        unsigned long efi_boot;
        unsigned long cmdline_ptr;
        unsigned long systable_ptr;
+#ifdef CONFIG_KEXEC_HANDOVER
+       void *kho_data;                 /* KHO handover blob buffer (virtual) */
+       unsigned long kho_data_mem;     /* physical address of the KHO handover blob */
+       void *efi_tables;               /* new EFI config table buffer (virtual) */
+       unsigned long efi_tables_mem;   /* physical address of new EFI config table */
+       unsigned long efi_tables_cnt;   /* number of entries in new EFI config table */
+#endif
 };
 
 struct kimage;
arch/loongarch/kernel/machine_kexec.c +16 -0
index 1883cae93bc3..c98a5607684d 100644
@@ -6,6 +6,7 @@
  */
 #include <linux/compiler.h>
 #include <linux/cpu.h>
+#include <linux/efi.h>
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 #include <linux/delay.h>
@@ -287,6 +288,21 @@ void machine_kexec(struct kimage *image)
        pr_notice("We will call new kernel at 0x%lx\n", start_addr);
        pr_notice("Bye ...\n");
 
+#ifdef CONFIG_KEXEC_HANDOVER
+       /*
+        * KHO: switch the EFI system table to the extended configuration table
+        * built in kho_load_data(), which carries the LINUX_EFI_KHO_TABLE_GUID
+        * entry the next kernel reads to find the KHO handover blob.
+        */
+       if (internal->efi_tables_mem) {
+               efi_system_table_t *st =
+                       (efi_system_table_t *)TO_CACHE(systable_ptr);
+
+               st->tables    = internal->efi_tables_mem;
+               st->nr_tables = internal->efi_tables_cnt;
+       }
+#endif
+
        /* Make reboot code buffer available to the boot CPU. */
        flush_cache_all();
 
arch/loongarch/kernel/machine_kexec_file.c +38 -0
index 5584b798ba46..d4c2243b6cb0 100644
@@ -10,6 +10,7 @@
 
 #define pr_fmt(fmt) "kexec_file: " fmt
 
+#include <linux/efi.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
@@ -18,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
+#include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
@@ -32,6 +34,13 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
        image->elf_headers = NULL;
        image->elf_headers_sz = 0;
 
+#ifdef CONFIG_KEXEC_HANDOVER
+       kfree(image->arch.kho_data);
+       image->arch.kho_data = NULL;
+       kvfree(image->arch.efi_tables);
+       image->arch.efi_tables = NULL;
+#endif
+
        return kexec_image_post_load_cleanup_default(image);
 }
 
@@ -55,6 +64,121 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
        *cmdline_tmplen += initrd_strlen;
 }
 
+#ifdef CONFIG_KEXEC_HANDOVER
+/*
+ * Hand the KHO state to the next kernel through a dedicated EFI configuration
+ * table entry.
+ *
+ * LoongArch has no boot FDT: the efistub passes the EFI system table and the
+ * command line to the core kernel directly.  So instead of the arm64 /chosen
+ * FDT path, build a small handover blob (struct linux_efi_kho_data) holding the
+ * KHO state FDT and scratch addresses, register it in the EFI configuration
+ * table under LINUX_EFI_KHO_TABLE_GUID, and let the next kernel read it and
+ * call kho_populate() directly.
+ *
+ * Both the blob and the extended configuration table are loaded as kexec
+ * segments; machine_kexec() switches st->tables to the new table before jumping.
+ *
+ * image->kho.fdt and image->kho.scratch are filled in by kho_fill_kimage()
+ * before the arch loader runs, so they are valid here.
+ */
+static int kho_load_data(struct kimage *image)
+{
+       struct linux_efi_kho_data *kho;
+       efi_system_table_t *st;
+       efi_config_table_t *ct, *new_ct;
+       size_t old_sz, new_sz;
+       struct kexec_buf kbuf = {
+               .image          = image,
+               .buf_min        = 0,
+               .buf_max        = ULONG_MAX,
+               .top_down       = true,

arch/loongarch/kernel/machine_kexec_file.c static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl · line 105

Quoted 10 lines
arch/loongarch/kernel/machine_kexec_file.c +10 -0
+       };
+       int ret;
+
+       if (!image->kho.fdt || !image->kho.scratch)
+               return 0;
+
+       if (!fw_arg2) {
+               pr_err("KHO requires an EFI boot, no EFI system table found\n");
+               return -EINVAL;
+       }

This check is unnecessary, if no EFI system table, you cannot boot your system, and have no chance for kexec.

Quoted 134 lines
arch/loongarch/kernel/machine_kexec_file.c +83 -0
+
+       /* Build the handover blob and load it as a kexec segment. */
+       kho = kzalloc(sizeof(*kho), GFP_KERNEL);
+       if (!kho)
+               return -ENOMEM;
+
+       kho->fdt_addr     = image->kho.fdt;
+       kho->fdt_size     = PAGE_SIZE;
+       kho->scratch_addr = image->kho.scratch->mem;
+       kho->scratch_size = image->kho.scratch->memsz;
+
+       kbuf.buffer     = kho;
+       kbuf.bufsz      = sizeof(*kho);
+       kbuf.memsz      = sizeof(*kho);
+       kbuf.buf_align  = sizeof(u64);
+       kbuf.mem        = KEXEC_BUF_MEM_UNKNOWN;
+
+       ret = kexec_add_buffer(&kbuf);
+       if (ret) {
+               kfree(kho);
+               return ret;
+       }
+       image->arch.kho_data     = kho;
+       image->arch.kho_data_mem = kbuf.mem;
+
+       kexec_dprintk("Loaded KHO handover blob at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+                     image->arch.kho_data_mem, kbuf.bufsz, kbuf.memsz);
+       kexec_dprintk("KHO fdt at 0x%llx, scratch at 0x%llx size 0x%llx\n",
+                     kho->fdt_addr, kho->scratch_addr, kho->scratch_size);
+
+       /*
+        * Build a new EFI configuration table with a LINUX_EFI_KHO_TABLE_GUID
+        * entry appended, pointing at the handover blob, and load it as a kexec
+        * segment.  machine_kexec() updates st->tables / st->nr_tables to point
+        * to it before jumping.
+        *
+        * fw_arg2 is the EFI system table physical address passed by the
+        * firmware/bootloader.  Use it directly because image->arch.systable_ptr
+        * is set later in machine_kexec_prepare(), which runs after this.
+        */
+       st = (efi_system_table_t *)TO_CACHE(fw_arg2);
+       ct = (efi_config_table_t *)TO_CACHE((unsigned long)st->tables);
+       old_sz = st->nr_tables * sizeof(efi_config_table_t);
+       new_sz = old_sz + sizeof(efi_config_table_t);
+
+       new_ct = kvmalloc(new_sz, GFP_KERNEL);
+       if (!new_ct)
+               return -ENOMEM;
+
+       memcpy(new_ct, ct, old_sz);
+       new_ct[st->nr_tables].guid  = LINUX_EFI_KHO_TABLE_GUID;
+       new_ct[st->nr_tables].table = (void *)image->arch.kho_data_mem;
+
+       kbuf.buffer     = new_ct;
+       kbuf.bufsz      = new_sz;
+       kbuf.memsz      = new_sz;
+       kbuf.buf_align  = sizeof(void *);
+       kbuf.mem        = KEXEC_BUF_MEM_UNKNOWN;
+
+       ret = kexec_add_buffer(&kbuf);
+       if (ret) {
+               kvfree(new_ct);
+               return ret;
+       }
+       image->arch.efi_tables     = new_ct;
+       image->arch.efi_tables_mem = kbuf.mem;
+       image->arch.efi_tables_cnt = st->nr_tables + 1;
+
+       kexec_dprintk("Loaded EFI config table at 0x%lx bufsz=0x%lx memsz=0x%lx nr_tables=%lu\n",
+                     image->arch.efi_tables_mem, kbuf.bufsz, kbuf.memsz,
+                     image->arch.efi_tables_cnt);
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_CRASH_DUMP
 
 static int prepare_elf_headers(void **addr, unsigned long *sz)
@@ -220,6 +344,13 @@ int load_other_segments(struct kimage *image,
                cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
        }
 
+#ifdef CONFIG_KEXEC_HANDOVER
+       /* Load the KHO handover blob and the extended EFI configuration table */
+       ret = kho_load_data(image);
+       if (ret)
+               goto out_err;
+#endif
+
        if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
                pr_err("Appending command line exceeds COMMAND_LINE_SIZE\n");
                ret = -EINVAL;
arch/loongarch/kernel/setup.c +26 -0
index 6fa4a22a58fd..1e2fbf37aecf 100644
@@ -20,6 +20,7 @@
 #include <linux/initrd.h>
 #include <linux/ioport.h>
 #include <linux/kexec.h>
+#include <linux/kexec_handover.h>
 #include <linux/crash_dump.h>
 #include <linux/root_dev.h>
 #include <linux/console.h>
@@ -280,6 +281,45 @@ static void __init arch_reserve_crashkernel(void)
        reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
 }
 
+#ifdef CONFIG_KEXEC_HANDOVER
+/*
+ * On a KHO kexec boot the previous kernel registered a handover blob in the EFI
+ * configuration table under LINUX_EFI_KHO_TABLE_GUID (see
+ * arch/loongarch/kernel/machine_kexec_file.c).  Scan the configuration table
+ * for it, read the KHO state FDT and scratch addresses, and hand them to the
+ * KHO core.  fw_arg2 is the EFI system table physical address.
+ *
+ * This runs from setup_arch(), after efi_init() and before memblock_init(),
+ * which is where the generic reader early_init_dt_check_kho() would call
+ * kho_populate().
+ */
+static void __init kho_populate_from_efi(void)
+{
+       efi_system_table_t *st;
+       efi_config_table_t *ct;
+       struct linux_efi_kho_data *kho;
+       unsigned long i;
+
+       if (!fw_arg2)
+               return;
+
+       st = (efi_system_table_t *)TO_CACHE(fw_arg2);
+       ct = (efi_config_table_t *)TO_CACHE((unsigned long)st->tables);
+

arch/loongarch/kernel/setup.c static void __init arch_reserve_crashkernel(void) · line 318

Quoted 10 lines
arch/loongarch/kernel/setup.c +10 -0
+       for (i = 0; i < st->nr_tables; i++) {
+               if (efi_guidcmp(ct[i].guid, LINUX_EFI_KHO_TABLE_GUID))
+                       continue;
+
+               kho = (struct linux_efi_kho_data *)TO_CACHE((unsigned long)ct[i].table);
+               kho_populate(kho->fdt_addr, kho->fdt_size,
+                            kho->scratch_addr, kho->scratch_size);
+               break;
+       }
+}

If you do this in efi.c, you can significantly simplify the code. By defining the KHO table in arch_tables[], you almost only need to call kho_populate() at the end of efi_init().

Huacai

Quoted 18 lines
arch/loongarch/kernel/setup.c +5 -1
+#else
+static void __init kho_populate_from_efi(void) { }
+#endif
+
 static void __init fdt_setup(void)
 {
 #ifdef CONFIG_OF_EARLY_FLATTREE
@@ -599,6 +639,7 @@ void __init setup_arch(char **cmdline_p)
 
        init_environ();
        efi_init();
+       kho_populate_from_efi();
        fdt_setup();
        memblock_init();
        pagetable_init();
--

2.53.0

maintainer
#8 lore raw

Re: [PATCH v4 2/4] LoongArch: kexec: add KHO support

In reply to George Guo
Quoted 39 lines · George Guo

From: George Guo <[email protected]>

Enable Kexec Handover (KHO) on LoongArch64.

LoongArch has no boot FDT: the efistub passes the EFI system table and the command line to the core kernel directly, so the arm64 /chosen path (append linux,kho-fdt / linux,kho-scratch and let early_init_dt_check_kho() read them) does not apply. Follow the x86 model instead, which has no boot FDT either: carry the KHO pointer out of band and call kho_populate() directly. The channel is the EFI configuration table entry added by the previous patch.

- Kconfig: ARCH_SUPPORTS_KEXEC_HANDOVER is def_bool 64BIT.
- machine_kexec_file.c: kho_load_data() builds a small handover blob (struct linux_efi_kho_data) holding the KHO state FDT and scratch addresses, and a new EFI configuration table with a LINUX_EFI_KHO_TABLE_GUID entry pointing to it; both are loaded as kexec segments.
- machine_kexec.c: before jumping to the next kernel, switch the EFI system table to the extended configuration table.
- setup.c: kho_populate_from_efi() scans the configuration table for LINUX_EFI_KHO_TABLE_GUID and calls kho_populate() from setup_arch(), after efi_init() and before memblock_init().

Handover is set up by the kexec_file_load() syscall only. kho_load_data() runs from load_other_segments(), which the older kexec_load() syscall does not reach. This matches x86, where KHO lives in the bzImage64 loader.

Tested on a LoongArch machine booting through ACPI/UEFI. After the kexec, the second kernel reports

KHO: found kexec handover data.

and the two-stage test passes: luo_kexec_simple --stage 1, kexec into the second kernel, then luo_kexec_simple --stage 2.

[...]

Quoted 73 lines
arch/loongarch/kernel/machine_kexec_file.c +69 -0
@@ -55,6 +64,121 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
 	*cmdline_tmplen += initrd_strlen;
 }
 
+#ifdef CONFIG_KEXEC_HANDOVER
+/*
+ * Hand the KHO state to the next kernel through a dedicated EFI configuration
+ * table entry.
+ *
+ * LoongArch has no boot FDT: the efistub passes the EFI system table and the
+ * command line to the core kernel directly.  So instead of the arm64 /chosen
+ * FDT path, build a small handover blob (struct linux_efi_kho_data) holding the
+ * KHO state FDT and scratch addresses, register it in the EFI configuration
+ * table under LINUX_EFI_KHO_TABLE_GUID, and let the next kernel read it and
+ * call kho_populate() directly.
+ *
+ * Both the blob and the extended configuration table are loaded as kexec
+ * segments; machine_kexec() switches st->tables to the new table before jumping.
+ *
+ * image->kho.fdt and image->kho.scratch are filled in by kho_fill_kimage()
+ * before the arch loader runs, so they are valid here.
+ */
+static int kho_load_data(struct kimage *image)
+{
+	struct linux_efi_kho_data *kho;
+	efi_system_table_t *st;
+	efi_config_table_t *ct, *new_ct;
+	size_t old_sz, new_sz;
+	struct kexec_buf kbuf = {
+		.image		= image,
+		.buf_min	= 0,
+		.buf_max	= ULONG_MAX,
+		.top_down	= true,
+	};
+	int ret;
+
+	if (!image->kho.fdt || !image->kho.scratch)
+		return 0;
+
+	if (!fw_arg2) {
+		pr_err("KHO requires an EFI boot, no EFI system table found\n");
+		return -EINVAL;
+	}
+
+	/* Build the handover blob and load it as a kexec segment. */
+	kho = kzalloc(sizeof(*kho), GFP_KERNEL);
+	if (!kho)
+		return -ENOMEM;
+
+	kho->fdt_addr     = image->kho.fdt;
+	kho->fdt_size     = PAGE_SIZE;
+	kho->scratch_addr = image->kho.scratch->mem;
+	kho->scratch_size = image->kho.scratch->memsz;
+
+	kbuf.buffer	= kho;
+	kbuf.bufsz	= sizeof(*kho);
+	kbuf.memsz	= sizeof(*kho);
+	kbuf.buf_align	= sizeof(u64);
+	kbuf.mem	= KEXEC_BUF_MEM_UNKNOWN;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret) {
+		kfree(kho);
+		return ret;
+	}
+	image->arch.kho_data	 = kho;
+	image->arch.kho_data_mem = kbuf.mem;
+
+	kexec_dprintk("Loaded KHO handover blob at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		      image->arch.kho_data_mem, kbuf.bufsz, kbuf.memsz);
+	kexec_dprintk("KHO fdt at 0x%llx, scratch at 0x%llx size 0x%llx\n",
+		      kho->fdt_addr, kho->scratch_addr, kho->scratch_size);
+

arch/loongarch/kernel/machine_kexec_file.c static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl · line 145

Quoted 10 lines
arch/loongarch/kernel/machine_kexec_file.c +10 -0
+	/*
+	 * Build a new EFI configuration table with a LINUX_EFI_KHO_TABLE_GUID
+	 * entry appended, pointing at the handover blob, and load it as a kexec
+	 * segment.  machine_kexec() updates st->tables / st->nr_tables to point
+	 * to it before jumping.
+	 *
+	 * fw_arg2 is the EFI system table physical address passed by the
+	 * firmware/bootloader.  Use it directly because image->arch.systable_ptr
+	 * is set later in machine_kexec_prepare(), which runs after this.
+	 */

This looks wrong. I don't think you should be modifying the EFI configuration table in this way. You also should have this in architecture-agnostic code.

I'm not an EFI expert, but I took a look at how the other Linux-specific tables work. I picked LINUX_EFI_MEMRESERVE_TABLE_GUID as my example. The table is allocated and installed from the EFI stub (see install_memreserve_table()). Then efi_memreserve_map_root() maps the table and it is used by efi_mem_reserve_persistent().

You should do something similar. Allocate and install the table from the stub, and then just update it on kexec. This would also let other architectures use this GUID without having to reinvent this again.

Quoted 53 lines
arch/loongarch/kernel/machine_kexec_file.c +43 -0
+	st = (efi_system_table_t *)TO_CACHE(fw_arg2);
+	ct = (efi_config_table_t *)TO_CACHE((unsigned long)st->tables);
+	old_sz = st->nr_tables * sizeof(efi_config_table_t);
+	new_sz = old_sz + sizeof(efi_config_table_t);
+
+	new_ct = kvmalloc(new_sz, GFP_KERNEL);
+	if (!new_ct)
+		return -ENOMEM;
+
+	memcpy(new_ct, ct, old_sz);
+	new_ct[st->nr_tables].guid  = LINUX_EFI_KHO_TABLE_GUID;
+	new_ct[st->nr_tables].table = (void *)image->arch.kho_data_mem;
+
+	kbuf.buffer	= new_ct;
+	kbuf.bufsz	= new_sz;
+	kbuf.memsz	= new_sz;
+	kbuf.buf_align	= sizeof(void *);
+	kbuf.mem	= KEXEC_BUF_MEM_UNKNOWN;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret) {
+		kvfree(new_ct);
+		return ret;
+	}
+	image->arch.efi_tables	   = new_ct;
+	image->arch.efi_tables_mem = kbuf.mem;
+	image->arch.efi_tables_cnt = st->nr_tables + 1;
+
+	kexec_dprintk("Loaded EFI config table at 0x%lx bufsz=0x%lx memsz=0x%lx nr_tables=%lu\n",
+		      image->arch.efi_tables_mem, kbuf.bufsz, kbuf.memsz,
+		      image->arch.efi_tables_cnt);
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_CRASH_DUMP
 
 static int prepare_elf_headers(void **addr, unsigned long *sz)
@@ -220,6 +344,13 @@ int load_other_segments(struct kimage *image,
 		cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
 	}
 
+#ifdef CONFIG_KEXEC_HANDOVER
+	/* Load the KHO handover blob and the extended EFI configuration table */
+	ret = kho_load_data(image);
+	if (ret)
+		goto out_err;
+#endif
+
 	if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
 		pr_err("Appending command line exceeds COMMAND_LINE_SIZE\n");
 		ret = -EINVAL;

[...]

Signature · 2 lines
Regards,
Pratyush Yadav
author
#9 lore raw

PATCH v4 3/4 liveupdate: luo_session: include linux/mm.h for virt/phys translation

In reply to George Guo

From: George Guo <[email protected]>

luo_session.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 luo_session.c only includes <linux/io.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.

---
 kernel/liveupdate/luo_session.c | 1 +
 1 file changed, 1 insertion(+)
kernel/liveupdate/luo_session.c +1 -0
index f38b5b18f3f8..31490ac7b63d 100644
@@ -94,6 +94,7 @@
 #include <linux/kho/abi/luo.h>
 #include <linux/list.h>
 #include <linux/liveupdate.h>
+#include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
Signature · 1 line
2.53.0
maintainer
#10 lore raw

Re: [PATCH v4 3/4] liveupdate: luo_session: include linux/mm.h for virt/phys translation

Hi, George,

This should be the 2nd patch.

Huacai

Quoted 39 lines · George Guo

From: George Guo <[email protected]>

luo_session.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 luo_session.c only includes <linux/io.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.

---
 kernel/liveupdate/luo_session.c | 1 +
 1 file changed, 1 insertion(+)
kernel/liveupdate/luo_session.c +1 -1
index f38b5b18f3f8..31490ac7b63d 100644
@@ -94,6 +94,7 @@
 #include <linux/kho/abi/luo.h>
 #include <linux/list.h>
 #include <linux/liveupdate.h>
+#include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
--

2.53.0

maintainer Reviewed-by
#11 lore raw

Re: [PATCH v4 3/4] liveupdate: luo_session: include linux/mm.h for virt/phys translation

Quoted 3 lines · Huacai Chen

Hi, George,

This should be the 2nd patch.

Agreed.

With that done,

Quoted 43 lines

Huacai

Quoted 39 lines · George Guo

From: George Guo <[email protected]>

luo_session.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 luo_session.c only includes <linux/io.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.

---
 kernel/liveupdate/luo_session.c | 1 +
 1 file changed, 1 insertion(+)
kernel/liveupdate/luo_session.c +1 -1
index f38b5b18f3f8..31490ac7b63d 100644
@@ -94,6 +94,7 @@
 #include <linux/kho/abi/luo.h>
 #include <linux/list.h>
 #include <linux/liveupdate.h>
+#include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
--

2.53.0

Signature · 2 lines
Regards,
Pratyush Yadav
maintainer
#12 lore raw

Re: [PATCH v4 3/4] liveupdate: luo_session: include linux/mm.h for virt/phys translation

Quoted 11 lines · Pratyush Yadav
Quoted 3 lines · Huacai Chen

Hi, George,

This should be the 2nd patch.

Agreed.

With that done,

Actually, I take this back. Sashiko has found some problems. See below.

Quoted 11 lines
Quoted 11 lines

Huacai

Quoted 6 lines · George Guo

From: George Guo <[email protected]>

luo_session.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>.

https://sashiko.dev/#/patchset/[email protected]

Is this description accurate? Looking at luo_session.c, it does not actually call virt_to_phys().
The implicit declaration error appears to originate from arch_kfence_init_pool() in arch/loongarch/include/asm/kfence.h, which is implicitly included via <linux/slab.h>. arch/loongarch/include/asm/kfence.h:arch_kfence_init_pool() {
...
virt_to_phys((void *)kfence_pool), PAGE_KERNEL);
...
}
Could the fix be applied to the architecture header instead, to prevent any other kernel C file on LoongArch with CONFIG_KFENCE=y from suffering the same build failure if it includes <linux/slab.h> before <linux/mm.h>?

I at least don't see any virt_to_phys() or phys_to_virt() in luo_session.c. So you need to go and take another look at what the real problem is and what the fix should be.

Quoted 33 lines
Quoted 33 lines
Quoted 33 lines

Since luo_session.c only includes <linux/io.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.

---
 kernel/liveupdate/luo_session.c | 1 +
 1 file changed, 1 insertion(+)
kernel/liveupdate/luo_session.c +1 -1
index f38b5b18f3f8..31490ac7b63d 100644
@@ -94,6 +94,7 @@
 #include <linux/kho/abi/luo.h>
 #include <linux/list.h>
 #include <linux/liveupdate.h>
+#include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
--

2.53.0

Signature · 2 lines
Regards,
Pratyush Yadav
author
#13 lore raw

Re: [PATCH v4 3/4] liveupdate: luo_session: include linux/mm.h for virt/phys translation

Hi Pratyush,

You are right: the current luo_session.c does not call virt_to_phys() or phys_to_virt(). I failed to update the target of this fix when rebasing the patch. The calls that trigger the current failure are in kernel/liveupdate/kho_block.c. Sorry about that.

I also checked the include chain. asm/kfence.h is not included by this translation unit. include/linux/slab.h does not include linux/kfence.h; that inclusion is in the MM-private mm/slab.h. Moreover, asm/kfence.h itself includes linux/kfence.h, which includes linux/mm.h, so arch_kfence_init_pool() already has the required declarations.

The actual failure is:

kernel/liveupdate/kho_block.c: In function 'kho_block_set_is_cyclic':
./arch/loongarch/include/asm/io.h:81:9: error: implicit declaration of function 'page_address' kernel/liveupdate/kho_block.c:210:16: note: in expansion of macro 'phys_to_virt'

The underlying issue is that LoongArch's CONFIG_KFENCE version of phys_to_virt() uses page_address(), which is provided by linux/mm.h.

Your broader point about fixing this at the architecture level is valid. I previously tried including linux/mm.h from asm/io.h [1], but that introduces a circular include through:

linux/slab.h -> linux/kasan.h -> asm/kasan.h -> asm/io.h -> linux/mm.h -> linux/slab.h

As reported by the kernel test robot [2], this leaves kfree() undeclared while linux/mm.h is being parsed. A proper architecture-wide fix therefore requires refactoring the address conversion helpers rather than adding that include to asm/io.h.

For this series I will move the linux/mm.h include from luo_session.c to the actual user, kho_block.c, and consider the architecture-wide cleanup separately.

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

Thanks,
George

author
#14 lore raw

PATCH v4 4/4 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 (VM) with a la464 CPU, enable the 8250 serial console, and set the kernel image to vmlinux.efi. Extend vmtest.sh to recognise loongarch64 as a supported target and map it to the 'loongarch' kernel arch name.

QEMU's LoongArch VM provides no ACPI tables and relies on FDT to describe hardware. Without 'earlycon' on the kernel command line, the FDT is not scanned for a console UART, no output reaches the console, and vmtest.sh's console log stays empty causing the test to always fail. Add 'earlycon' to KERNEL_CMDLINE in loongarch.conf.

QEMU's LoongArch VM has no i8042 PS/2 controller. When PNP detection finds nothing, i8042_init() falls back to probing the ports directly. On LoongArch the I/O ports are memory-mapped, and the i8042 port addresses are not backed by any device on the VM, so i8042_flush() takes a page fault and the kernel panics:

i8042: PNP: No PS/2 controller found.
i8042: Probing ports directly.
CPU 0 Unable to handle kernel paging request at virtual address ffff800000008064
ERA: i8042_flush+0x50/0x198
RA: i8042_init+0x2a8/0x35c

  Kernel panic - not syncing: Attempted to kill init!

Disable SERIO_I8042 and its dependents (KEYBOARD_ATKBD, MOUSE_PS2) in the QEMU_KCONFIG fragment to prevent the driver from being built. All three options are scoped to loongarch.conf; no other architecture is affected.

Wrap the QEMU invocation in run_qemu() with timeout(1) using a local time limit so the test always terminates, even when QEMU does not exit on its own. This is useful for every architecture; on LoongArch, for example, QEMU provides no EFI runtime services and machine_restart() falls through to an idle loop after kexec, so QEMU would never exit otherwise.

---
 tools/testing/selftests/kho/loongarch.conf | 11 +++++++++++
 tools/testing/selftests/kho/vmtest.sh      | 22 +++++++++++++++-------
 2 files changed, 26 insertions(+), 7 deletions(-)
 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..e45fe1014cf3
@@ -0,0 +1,11 @@
+QEMU_CMD="qemu-system-loongarch64 -M virt -cpu la464"
+QEMU_KCONFIG="
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SPARSEMEM_MANUAL=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+"
+KERNEL_IMAGE="vmlinux.efi"
+KERNEL_CMDLINE="console=ttyS0 earlycon kho_scratch=16M,16M,16M"
tools/testing/selftests/kho/vmtest.sh +15 -7
index 0014bd76e88d..de6aa59cf5a0 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, x86_64, loongarch64
 	-h)	display this help
 EOF
 }
@@ -111,12 +111,19 @@ function run_qemu() {
 
 	cmdline="$cmdline kho=on panic=-1"
 
-	$qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
-		  -accel kvm -accel hvf -accel tcg  \
-		  -serial file:"$serial" \
-		  -append "$cmdline" \
-		  -kernel "$kernel" \
-		  -initrd "$initrd"
+	local qemu_args=(
+		-m 1G -smp 2 -no-reboot -nographic -nodefaults
+		-accel kvm -accel hvf -accel tcg
+		-serial file:"$serial"
+		-append "$cmdline"
+		-kernel "$kernel"
+		-initrd "$initrd"
+	)
+
+	# Bound the QEMU run so the test always terminates, even when QEMU
+	# does not exit on its own (e.g. no EFI runtime services after kexec).
+	local qemu_timeout=60
+	timeout "$qemu_timeout" $qemu_cmd "${qemu_args[@]}" || true
 
 	grep "KHO restore succeeded" "$serial" &> /dev/null || fail "KHO failed"
 }
@@ -127,6 +134,7 @@ function target_to_arch() {
 	case $target in
 	     aarch64) echo "arm64" ;;
 	     x86_64) echo "x86" ;;
+	     loongarch64) echo "loongarch" ;;
 	     *) skip "architecture $target is not supported"
 	esac
 }
Signature · 1 line
2.53.0
maintainer
#15 lore raw

Re: [PATCH v4 4/4] selftests/kho: add LoongArch vmtest support

Hi, George,

Quoted 20 lines · George Guo

From: George Guo <[email protected]>

Add loongarch.conf to configure QEMU's LoongArch virtual machine (VM) with a la464 CPU, enable the 8250 serial console, and set the kernel image to vmlinux.efi. Extend vmtest.sh to recognise loongarch64 as a supported target and map it to the 'loongarch' kernel arch name.

QEMU's LoongArch VM provides no ACPI tables and relies on FDT to describe hardware. Without 'earlycon' on the kernel command line, the FDT is not scanned for a console UART, no output reaches the console, and vmtest.sh's console log stays empty causing the test to always fail. Add 'earlycon' to KERNEL_CMDLINE in loongarch.conf.

QEMU's LoongArch VM has no i8042 PS/2 controller. When PNP detection finds nothing, i8042_init() falls back to probing the ports directly. On LoongArch the I/O ports are memory-mapped, and the i8042 port addresses are not backed by any device on the VM, so i8042_flush() takes a page fault and the kernel panics:

Quoted 6 lines

i8042: PNP: No PS/2 controller found.
i8042: Probing ports directly.
CPU 0 Unable to handle kernel paging request at virtual address ffff800000008064
ERA: i8042_flush+0x50/0x198
RA: i8042_init+0x2a8/0x35c

  Kernel panic - not syncing: Attempted to kill init!

You never answer me why in your test you should disable i8042 from V1 until V4. In normal use we use a single kernel for both host and guest.

Huacai

Quoted 89 lines

Disable SERIO_I8042 and its dependents (KEYBOARD_ATKBD, MOUSE_PS2) in the QEMU_KCONFIG fragment to prevent the driver from being built. All three options are scoped to loongarch.conf; no other architecture is affected.

Wrap the QEMU invocation in run_qemu() with timeout(1) using a local time limit so the test always terminates, even when QEMU does not exit on its own. This is useful for every architecture; on LoongArch, for example, QEMU provides no EFI runtime services and machine_restart() falls through to an idle loop after kexec, so QEMU would never exit otherwise.

---
 tools/testing/selftests/kho/loongarch.conf | 11 +++++++++++
 tools/testing/selftests/kho/vmtest.sh      | 22 +++++++++++++++-------
 2 files changed, 26 insertions(+), 7 deletions(-)
 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..e45fe1014cf3
@@ -0,0 +1,11 @@
+QEMU_CMD="qemu-system-loongarch64 -M virt -cpu la464"
+QEMU_KCONFIG="
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SPARSEMEM_MANUAL=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+"
+KERNEL_IMAGE="vmlinux.efi"
+KERNEL_CMDLINE="console=ttyS0 earlycon kho_scratch=16M,16M,16M"
tools/testing/selftests/kho/vmtest.sh +15 -8
index 0014bd76e88d..de6aa59cf5a0 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, x86_64, loongarch64
        -h)     display this help
 EOF
 }
@@ -111,12 +111,19 @@ function run_qemu() {
 
        cmdline="$cmdline kho=on panic=-1"
 
-       $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
-                 -accel kvm -accel hvf -accel tcg  \
-                 -serial file:"$serial" \
-                 -append "$cmdline" \
-                 -kernel "$kernel" \
-                 -initrd "$initrd"
+       local qemu_args=(
+               -m 1G -smp 2 -no-reboot -nographic -nodefaults
+               -accel kvm -accel hvf -accel tcg
+               -serial file:"$serial"
+               -append "$cmdline"
+               -kernel "$kernel"
+               -initrd "$initrd"
+       )
+
+       # Bound the QEMU run so the test always terminates, even when QEMU
+       # does not exit on its own (e.g. no EFI runtime services after kexec).
+       local qemu_timeout=60
+       timeout "$qemu_timeout" $qemu_cmd "${qemu_args[@]}" || true
 
        grep "KHO restore succeeded" "$serial" &> /dev/null || fail "KHO failed"
 }
@@ -127,6 +134,7 @@ function target_to_arch() {
        case $target in
             aarch64) echo "arm64" ;;
             x86_64) echo "x86" ;;
+            loongarch64) echo "loongarch" ;;
             *) skip "architecture $target is not supported"
        esac
 }
--

2.53.0

author
#16 lore raw

Re: [PATCH v4 4/4] selftests/kho: add LoongArch vmtest support

Hi Huacai,

Quoted 2 lines · Huacai Chen

You never answer me why in your test you should disable i8042 from V1 until V4. In normal use we use a single kernel for both host and guest.

I owe you an apology: I did not actually understand your question. I thought the commit message had already explained the reason (the i8042_flush() panic), so I treated it as answered and never addressed what you were really asking. Let me answer it directly now.

You are right that this is not just a selftest detail. i8042 is built on every LoongArch kernel: arch/loongarch/Kconfig selects ARCH_MIGHT_HAVE_PC_SERIO, and KEYBOARD_ATKBD and MOUSE_PS2 (both default
y) select SERIO_I8042 under it. So your "single kernel for host and guest" point is correct -- a normal defconfig kernel has i8042 built in.

On the QEMU virtual machine there is no i8042, so PNP finds nothing and i8042_pnp_init() falls back to probing the i8042 status and data registers (I8042_STATUS_REG, I8042_DATA_REG) directly. On LoongArch those registers are memory-mapped, and on the virtual machine they are not backed by any device, so i8042_flush() takes a page fault and the kernel panics before userspace. A normal LoongArch defconfig kernel booted as a QEMU guest hits the same panic -- the "# CONFIG_SERIO_I8042 is not set" in loongarch.conf is only a workaround to let the KHO selftest boot, not a fix.

The real fix is separate from the KHO series: make i8042 bail out on LoongArch when ACPI/PNP does not describe a controller, so the direct-port fallback never runs. I have prepared that as a standalone patch -- the relevant hunk is below -- and will send the full patch separately. The selftest workaround can be dropped once it lands.

drivers/input/serio/i8042-acpipnpio.h +0 -0
@@ -1633,8 +1633,14 @@ static int __init i8042_pnp_init(void)
 #else
		pr_info("PNP: No PS/2 controller found.\n");

#if defined(__loongarch__)
- if (acpi_disabled == 0)
- return -ENODEV;
+ /*
+ * LoongArch legacy I/O ports are memory-mapped and are not
+ * safely probeable when no controller is present: a direct
+ * probe faults on the QEMU virtual machine and on any FDT-based
+ * boot. Do not fall back to probing them directly; if ACPI/PNP
+ * did not describe a controller, assume there is none.
+ */
+ return -ENODEV;

 #else
                if (x86_platform.legacy.i8042 !=
                                X86_LEGACY_I8042_EXPECTED_PRESENT)

Thanks,
George

maintainer
#17 lore raw

Re: [PATCH v4 4/4] selftests/kho: add LoongArch vmtest support

Quoted 28 lines · George Guo

Hi Huacai,

Quoted 2 lines · Huacai Chen

You never answer me why in your test you should disable i8042 from V1 until V4. In normal use we use a single kernel for both host and guest.

I owe you an apology: I did not actually understand your question. I thought the commit message had already explained the reason (the i8042_flush() panic), so I treated it as answered and never addressed what you were really asking. Let me answer it directly now.

You are right that this is not just a selftest detail. i8042 is built on every LoongArch kernel: arch/loongarch/Kconfig selects ARCH_MIGHT_HAVE_PC_SERIO, and KEYBOARD_ATKBD and MOUSE_PS2 (both default
y) select SERIO_I8042 under it. So your "single kernel for host and guest" point is correct -- a normal defconfig kernel has i8042 built in.

On the QEMU virtual machine there is no i8042, so PNP finds nothing and i8042_pnp_init() falls back to probing the i8042 status and data registers (I8042_STATUS_REG, I8042_DATA_REG) directly. On LoongArch those registers are memory-mapped, and on the virtual machine they are not backed by any device, so i8042_flush() takes a page fault and the kernel panics before userspace. A normal LoongArch defconfig kernel booted as a QEMU guest hits the same panic -- the "# CONFIG_SERIO_I8042 is not set" in loongarch.conf is only a workaround to let the KHO selftest boot, not a fix.

Quoted 5 lines

The real fix is separate from the KHO series: make i8042 bail out on LoongArch when ACPI/PNP does not describe a controller, so the direct-port fallback never runs. I have prepared that as a standalone patch -- the relevant hunk is below -- and will send the full patch separately. The selftest workaround can be dropped once it lands.

You nearly answered nothing.

Does your employer use different kernels for host and guest in KylinOS?

Huacai

Quoted 24 lines
drivers/input/serio/i8042-acpipnpio.h +8 -2
@@ -1633,8 +1633,14 @@ static int __init i8042_pnp_init(void)
 #else
                pr_info("PNP: No PS/2 controller found.\n");
 #if defined(__loongarch__)
-               if (acpi_disabled == 0)
-                       return -ENODEV;
+               /*
+                * LoongArch legacy I/O ports are memory-mapped and are not
+                * safely probeable when no controller is present: a direct
+                * probe faults on the QEMU virtual machine and on any FDT-based
+                * boot.  Do not fall back to probing them directly; if ACPI/PNP
+                * did not describe a controller, assume there is none.
+                */
+               return -ENODEV;
 #else
                if (x86_platform.legacy.i8042 !=
                                X86_LEGACY_I8042_EXPECTED_PRESENT)

Thanks,
George

author
#18 lore raw

Re: [PATCH v4 4/4] selftests/kho: add LoongArch vmtest support

Hi Huacai,

Quoted 3 lines

You nearly answered nothing.

Does your employer use different kernels for host and guest in KylinOS?

No. Host and guests run the same distro kernel in KylinOS, and guests boot with edk2 firmware, so ACPI is delivered and i8042 bails out through the PNP path. That is the normal case and it never panics.

I have since finished the investigation, also for the firmware-less case. The same QEMU command with two kernels gives two different results, and the difference is the kernel configuration:

- A distro kernel (CONFIG_PCI_HOST_GENERIC=y) maps the PCI_IOBASE I/O window through DT PCIe host enumeration, so even without firmware the i8042 probe reads garbage and fails cleanly ("No controller found").
- The selftest's minimal kernel maps nothing there, so the same read takes a page fault in i8042_flush() and panics before userspace.

So the panic needs three conditions together: a firmware-less boot, SERIO_I8042=y (the Kconfig default), and no registered PIO range -- which is only the selftest-style kernel. I agree the mainline fix is not necessary. For the selftest I will enable CONFIG_PCI_HOST_GENERIC=y in loongarch.conf instead of disabling i8042, so the selftest kernel stays closer to a normal one; the standalone patch will not be sent.

Thanks,
George

author
#19 lore raw

Re: [PATCH v4 4/4] selftests/kho: add LoongArch vmtest support

In reply to George Guo

Hi,

While preparing v5, I retested the LoongArch vmtest without the explicit kho_scratch=16M,16M,16M setting. That setting was masking a pre-existing bug in the generic percentage-based KHO scratch sizing.

The percentage heuristic itself is reasonable, but the old implementation calculated each per-node baseline after allocating the lowmem and global scratch areas. Since memblock allocations are marked MEMBLOCK_RSRV_KERN, those scratch areas were counted as new kernel demand and scaled again.

On the 1 GiB LoongArch guest, the 98.45 MiB reservation baseline and 32 MiB alignment made the old ordering request 224 MiB of lowmem scratch followed by 672 MiB for node 0. The node allocation failed and disabled KHO. I sent a separate generic fix here:

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

With that fix, the total aligned request is 448 MiB and the LoongArch vmtest passes using the default percentage-based sizing. I also ran the x86 KHO vmtest with the fix; it passes as well.

Therefore, I will remove kho_scratch=16M,16M,16M from loongarch.conf in v5 so that it tests the default sizing path, matching the existing x86 selftest behavior.

Thanks,
George

maintainer
#20 lore raw

Re: [PATCH v4 4/4] selftests/kho: add LoongArch vmtest support

Quoted 11 lines · George Guo

Hi,

While preparing v5, I retested the LoongArch vmtest without the explicit kho_scratch=16M,16M,16M setting. That setting was masking a pre-existing bug in the generic percentage-based KHO scratch sizing.

The percentage heuristic itself is reasonable, but the old implementation calculated each per-node baseline after allocating the lowmem and global scratch areas. Since memblock allocations are marked MEMBLOCK_RSRV_KERN, those scratch areas were counted as new kernel demand and scaled again.

Quoted 6 lines

On the 1 GiB LoongArch guest, the 98.45 MiB reservation baseline and 32 MiB alignment made the old ordering request 224 MiB of lowmem scratch followed by 672 MiB for node 0. The node allocation failed and disabled KHO. I sent a separate generic fix here:

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

Oh, cool! Nice find. I just wrote Sourabh (+Cc) an email [0] about this too.

I think there is other wonky stuff going on with scratch sizing, like global scratch being inflated. See my email [0] about that.

Let me go review that patch, since this seems to be causing a lot of pain.

[0] https://lore.kernel.org/kexec/[email protected]/T/#t

Quoted 11 lines

With that fix, the total aligned request is 448 MiB and the LoongArch vmtest passes using the default percentage-based sizing. I also ran the x86 KHO vmtest with the fix; it passes as well.

Therefore, I will remove kho_scratch=16M,16M,16M from loongarch.conf in v5 so that it tests the default sizing path, matching the existing x86 selftest behavior.

Thanks,
George

Signature · 2 lines
Regards,
Pratyush Yadav