From 1ee6f272dceed3c351a20cfe4d330306ee7fe5a4 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 01/11] kpatch/LoongArch: Add LoongArch specific features Add section alt_instr check support for LoongArch. Signed-off-by: George Guo --- kpatch-build/kpatch-build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 3343f37d8..7408026c2 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -405,6 +405,9 @@ find_special_section_data() { "aarch64") check[a]=true # alt_instr ;; + "loongarch64") + check[a]=true # alt_instr + ;; esac # Kernel CONFIG_ features From 19d35ca93fc6e5ee72969515c055caa1609e4606 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 02/11] kpatch/LoongArch: Add initial support for kpatch Add initial support for LoongArch. Signed-off-by: George Guo --- kpatch-build/create-diff-object.c | 18 +++++++++++++----- kpatch-build/kpatch-elf.c | 7 +++++++ kpatch-build/kpatch-elf.h | 1 + 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index b14962707..a5422d187 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -182,6 +182,8 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, return false; case S390: return false; + case LOONGARCH64: + return false; default: ERROR("unsupported arch"); } @@ -247,6 +249,7 @@ static bool kpatch_is_mapping_symbol(struct kpatch_elf *kelf, struct symbol *sym case X86_64: case PPC64: case S390: + case LOONGARCH64: return false; default: ERROR("unsupported arch"); @@ -762,6 +765,11 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr) break; + case LOONGARCH64: + /* to be done */ + + break; + case S390: /* arg2: lghi %r3, imm */ if (insn[0] == 0xa7 && insn[1] == 0x39) @@ -2589,22 +2597,22 @@ static bool static_call_sites_group_filter(struct lookup_table *lookup, static struct special_section special_sections[] = { { .name = "__bug_table", - .arch = AARCH64 | X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390 | LOONGARCH64, .group_size = bug_table_group_size, }, { .name = ".fixup", - .arch = AARCH64 | X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390 | LOONGARCH64, .group_size = fixup_group_size, }, { .name = "__ex_table", /* must come after .fixup */ - .arch = AARCH64 | X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390 | LOONGARCH64, .group_size = ex_table_group_size, }, { .name = "__jump_table", - .arch = AARCH64 | X86_64 | PPC64 | S390, + .arch = AARCH64 | X86_64 | PPC64 | S390 | LOONGARCH64, .group_size = jump_table_group_size, .group_filter = jump_table_group_filter, }, @@ -2625,7 +2633,7 @@ static struct special_section special_sections[] = { }, { .name = ".altinstructions", - .arch = AARCH64 | X86_64 | S390, + .arch = AARCH64 | X86_64 | S390 | LOONGARCH64, .group_size = altinstructions_group_size, }, { diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 11ce45543..b702cf378 100755 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -156,6 +156,8 @@ unsigned int absolute_rela_type(struct kpatch_elf *kelf) return R_390_64; case AARCH64: return R_AARCH64_ABS64; + case LOONGARCH64: + return R_LARCH_64; default: ERROR("unsupported arch"); } @@ -221,6 +223,7 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, switch(kelf->arch) { case PPC64: case AARCH64: + case LOONGARCH64: add_off = 0; break; case X86_64: @@ -278,6 +281,7 @@ unsigned int insn_length(struct kpatch_elf *kelf, void *addr) return decoded_insn.length; case PPC64: + case LOONGARCH64: return 4; case S390: @@ -614,6 +618,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name) case EM_AARCH64: kelf->arch = AARCH64; break; + case EM_LOONGARCH: + kelf->arch = LOONGARCH64; + break; default: ERROR("Unsupported target architecture"); } diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 4a4c5a56e..7efd1647e 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -117,6 +117,7 @@ enum architecture { X86_64 = 0x1 << 1, S390 = 0x1 << 2, AARCH64 = 0x1 << 3, + LOONGARCH64 = 0x1 << 4, }; struct kpatch_elf { From 19a2ceaceb6c6f443ba89bff6f7b085414f1c8bb Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 03/11] kpatch/LoongArch: process section __patchable_function_entries Generate 2 NOPs right at the beginning of each function with -fpatchable-function-entry=2 in LoongArch. Here process this situation. Co-developed-by: zhanghongchen Signed-off-by: zhanghongchen Signed-off-by: George Guo --- kpatch-build/create-diff-object.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index a5422d187..b36bf7f4e 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -4058,6 +4058,21 @@ static void kpatch_create_ftrace_callsite_sections(struct kpatch_elf *kelf) insn_offset = sym->sym.st_value; break; } + case LOONGARCH64: { + bool found = false; + unsigned char *insn = sym->sec->data->d_buf + sym->sym.st_value; + + /* 0x03400000 is NOP instruction for LoongArch. */ + if (insn[0] == 0x00 && insn[1] == 0x00 && insn[2] == 0x40 && insn[3] == 0x03 && + insn[4] == 0x00 && insn[5] == 0x00 && insn[6] == 0x40 && insn[7] == 0x03) + found = true; + + if (!found) + ERROR("%s: unexpected instruction at the start of the function", sym->name); + + insn_offset = 0; + break; + } default: ERROR("unsupported arch"); } @@ -4316,6 +4331,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) sym->has_func_profiling = 1; break; case AARCH64: + case LOONGARCH64: if (kpatch_symbol_has_pfe_entry(kelf, sym)) sym->has_func_profiling = 1; break; From a26c5e48775df1466581d36b08d71a89c139d137 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 04/11] kpatch/LoongArch: change local labels with sections symbols Here fix error like: "tcp.o: symbol changed sections: .LBB7266. create-diff-object: unreconcilable difference". Due to LoongArch GCC generating local labels such as .LBB7266, it is difficult to compare the modified sections in the corresponding object files of the two files before and after the patch, so change them with sections symbols in rela section, and delete them in other sections. Co-developed-by: zhanghongchen Signed-off-by: zhanghongchen Signed-off-by: George Guo --- kpatch-build/kpatch-elf.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index b702cf378..d418ecda5 100755 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -353,6 +353,21 @@ static void kpatch_create_rela_list(struct kpatch_elf *kelf, rela->sym->name, rela->addend); } + if (kelf->arch == LOONGARCH64) { + /* + * LoongArch GCC creates local labels such as .LBB7266, + * replace them with section symbols. + */ + if (rela->sym->sec && rela->sym->type == STT_NOTYPE && + rela->sym->bind == STB_LOCAL) { + log_debug("local label: %s -> ", rela->sym->name); + rela->addend += rela->sym->sym.st_value; + rela->sym = rela->sym->sec->secsym; + log_debug("section symbol: %s\n", rela->sym->name); + } + } + + if (skip) continue; log_debug("offset %d, type %d, %s %s %ld", rela->offset, @@ -654,6 +669,18 @@ struct kpatch_elf *kpatch_elf_open(const char *name) } } + if (kelf->arch == LOONGARCH64) { + struct symbol *sym, *tmp; + + /* Delete local labels created by LoongArch GCC */ + list_for_each_entry_safe(sym, tmp, &kelf->symbols, list) { + if (sym->sec && !is_rela_section(sym->sec) && + sym->type == STT_NOTYPE && + sym->bind == STB_LOCAL) + list_del(&sym->list); + } + } + return kelf; } From 7f88756e82727c6edbf07e1c7db12d6167c02315 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 05/11] kpatch/LoongArch: skip section .rela.orc_unwind_ip Fix error: "changed section .rela.orc_unwind_ip not selected for inclusion". This section is about arch-specific differences on LoongArch, which is generated by LoongArch gcc. Signed-off-by: George Guo --- kpatch-build/create-diff-object.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index b36bf7f4e..199d5b2fe 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -3056,6 +3056,11 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) !strcmp(sec->name, "__patchable_function_entries")) sec->ignore = 1; } + + if (kelf->arch == LOONGARCH64) { + if (!strncmp(sec->name, ".rela.orc_unwind_ip", 19)) + sec->ignore = 1; + } } sec = find_section_by_name(&kelf->sections, ".kpatch.ignore.sections"); From 54e51c9274db8f4211f512be8363a3e6de4051e7 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 06/11] kpatch/LoongArch: enable kpatch build Since kpatch now supports LoongArch basically, enable the build. Signed-off-by: George Guo --- kpatch-build/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile index 1f7ee4b16..c8f3bbaff 100644 --- a/kpatch-build/Makefile +++ b/kpatch-build/Makefile @@ -21,7 +21,7 @@ PLUGIN_CFLAGS := $(filter-out -std=gnu11 -Wconversion, $(CFLAGS)) PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \ -Igcc-plugins -fPIC -fno-rtti -O2 -Wall endif -ifeq ($(filter $(ARCH),s390x x86_64 ppc64le aarch64),) +ifeq ($(filter $(ARCH),s390x x86_64 ppc64le aarch64 loongarch64),) $(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures) endif From 733ac8e60107d07b7f7cd2bd50d15ac6df0b20a3 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 07/11] kpatch/LoongArch: fix build error on non-LoongArch architectures Added conditional compilation to prevent 'R_LARCH_64' and 'EM_LOONGARCH' from being referenced on x86 and other non-LoongArch architectures. This ensures the code works across different architectures without errors. Signed-off-by: George Guo --- kpatch-build/kpatch-elf.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 7efd1647e..92e3bb68b 100644 --- a/kpatch-build/kpatch-elf.h +++ b/kpatch-build/kpatch-elf.h @@ -31,6 +31,11 @@ #define SHF_RELA_LIVEPATCH 0x00100000 #define SHN_LIVEPATCH 0xff20 +#ifndef __loongarch__ +#define EM_LOONGARCH 258 /* LoongArch */ +#define R_LARCH_64 2 +#endif + /******************* * Data structures * ****************/ From 6e6d6e990abfd219f1558661ede1df939d98100b Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 08/11] kpatch/LoongArch: ignore arch/loongarch/vdso Add arch/loongarch/vdso to the list of object files that kpatch-cc won't add to its changed_objs list. Signed-off-by: George Guo --- kpatch-build/kpatch-cc | 1 + 1 file changed, 1 insertion(+) diff --git a/kpatch-build/kpatch-cc b/kpatch-build/kpatch-cc index fc9433ad6..ad23df932 100755 --- a/kpatch-build/kpatch-cc +++ b/kpatch-build/kpatch-cc @@ -43,6 +43,7 @@ if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; th arch/s390/boot/*|\ arch/s390/purgatory/*|\ arch/s390/kernel/vdso64/*|\ + arch/loongarch/vdso/*|\ drivers/firmware/efi/libstub/*|\ init/version.o|\ init/version-timestamp.o|\ From 9db2ecc895d8ae0cbc07811af77b03fea5771810 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 09/11] kpatch/LoongArch: disable direct-extern-access for livepatches to fix kernel panic On LoongArch systems, livepatch modules containing references to EXTERNAL global variables trigger kernel panics when the core kernel is built with -mdirect-extern-access optimization. Root cause: The -mdirect-extern-access optimization replaces GOT-based external symbol access with direct addressing for improved performance. However, this breaks the kernel module loading mechanism which relies on GOT entries for proper relocation of EXTERNAL symbol references. Direct access to global variables from livepatch modules causes invalid memory accesses and kernel panics. Solution: For LoongArch kpatch builds, conditionally disable direct-extern-access by adding: - -mno-direct-extern-access for GCC builds - -fno-direct-access-external-data for Clang builds Signed-off-by: George Guo --- kpatch-build/kpatch-build | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 7408026c2..74cdd8e60 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -61,6 +61,7 @@ KLP_REPLACE=1 GCC="${CROSS_COMPILE:-}gcc" CLANG="${CROSS_COMPILE:-}clang" +CC_OPTION="" LD="${CROSS_COMPILE:-}ld" LLD="${CROSS_COMPILE:-}ld.lld" READELF="${CROSS_COMPILE:-}readelf" @@ -382,6 +383,21 @@ clang_version_check() { return } +cc_option_check() { + local option="$1" + local compiler="" + + if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then + compiler="$CLANG" + else + compiler="$GCC" + fi + + if $compiler -Werror "$option" -c -x c /dev/null -o /dev/null 2>/dev/null; then + CC_OPTION+=" $option"; + fi +} + find_special_section_data() { local -A check @@ -1291,8 +1307,16 @@ declare -a MAKEVARS if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${CLANG}") MAKEVARS+=("HOSTCC=clang") + if [[ "$ARCH" = "loongarch64" ]]; then + cc_option_check "-fno-direct-access-external-data" + MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=${CC_OPTION}") + fi else MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${GCC}") + if [[ "$ARCH" = "loongarch64" ]]; then + cc_option_check "-mno-direct-extern-access" + MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=${CC_OPTION}") + fi fi if [[ -n "$CONFIG_LD_IS_LLD" ]]; then From 03412f0f38adee7d93a897150b47056129e6b821 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 10/11] kpatch/LoongArch: fix kernel panic with -fPIC for same-compilation-unit symbol references Add architecture-specific -fPIC compiler flag for LoongArch64 to prevent kernel panics when applying livepatches containing references to symbols defined in the same compilation unit. Root cause: In the kpatch workflow, when a function is livepatched, it's extracted from the original object file and compiled into a separate kernel module. When the patched function references symbols defined in the same compilation unit (like 'uts_sem' in kernel/sys.c), these references break if not compiled as position-independent code. On LoongArch64, without -fPIC, references to same-compilation-unit symbols use absolute addressing that assumes fixed memory locations. When the function is relocated into the livepatch module, these absolute addresses become invalid, causing kernel panics. Example failure case: - SYSCALL_DEFINE1(newuname) references the same-compilation-unit symbol 'uts_sem' - When kpatch extracts this function into a module, the reference to 'uts_sem' must be properly relocated - Without -fPIC, the absolute address reference causes invalid memory access and kernel panic Solution: Force -fPIC compilation for all LoongArch64 kpatch builds. This ensures that references to same-compilation-unit symbols use position-independent addressing, allowing proper relocation by the kernel module loader and preventing kernel panics in livepatch scenarios. Co-developed-by: Kexin Liu Signed-off-by: Kexin Liu Signed-off-by: George Guo --- kpatch-build/kpatch-build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 74cdd8e60..c85f82025 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -1288,6 +1288,10 @@ if [[ "$ARCH" = "s390x" ]]; then ! kernel_version_gte 6.10.0 && ARCH_KCFLAGS+=" -fPIE" fi +if [[ "$ARCH" = "loongarch64" ]]; then + ARCH_KCFLAGS="-fPIC" +fi + export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \ $ARCH_KCFLAGS $DEBUG_KCFLAGS" From 8cb28488ce4f934e956826056ba165c4f8f1b81f Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 29 Dec 2025 14:37:06 +0800 Subject: [PATCH 11/11] kpatch/LoongArch: test/unit/objs: Update reference for loongarch64 objs Loongarch64 test objects are now available in the kpatch-unit-test-objs repository with commit bf463645367e ("Merge pull request #52 from georgejguo/master") Update the submodule reference to the above commit so the objects are available to the test suite for loongarch64. Co-developed-by: Kexin Liu Signed-off-by: Kexin Liu Signed-off-by: George Guo --- test/unit/Makefile | 2 +- test/unit/objs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/Makefile b/test/unit/Makefile index e3ed7d718..91efbde3c 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -1,4 +1,4 @@ -ARCHES ?= aarch64 ppc64le x86_64 +ARCHES ?= loongarch64 aarch64 ppc64le x86_64 .PHONY: all clean submodule-check diff --git a/test/unit/objs b/test/unit/objs index 4ad64a06b..bf4636453 160000 --- a/test/unit/objs +++ b/test/unit/objs @@ -1 +1 @@ -Subproject commit 4ad64a06b6d0a9b779348f04823f82b03e91942e +Subproject commit bf463645367ec892b0c0ba265d2deacbd6289581