From 01fd11c0b90689aa253e2bfe3c8fb31b154b422f Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 e2aa0df1..788585ac 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -407,6 +407,9 @@ find_special_section_data() { "aarch64") check[a]=true # alt_instr ;; + "loongarch64") + check[a]=true # alt_instr + ;; esac # Kernel CONFIG_ features From 8779c4514b731763969bf0729a765eee303a7cc9 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 09160030..b445e0af 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"); @@ -771,6 +774,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) @@ -2598,22 +2606,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, }, @@ -2634,7 +2642,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 11ce4554..b702cf37 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 4a4c5a56..7efd1647 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 2dd2bde999425e42d19c6b6f3cd175a4bbb47ab9 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 b445e0af..c6be5e16 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -4067,6 +4067,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"); } @@ -4325,6 +4340,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 b33336be671e9e4ade66391167d8f44872402279 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 b702cf37..d418ecda 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 335598a1f5cd501ab783e8f4a9d1ce82b91ca703 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 c6be5e16..a5cbd532 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -3065,6 +3065,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 34e73011c157e83820b940f15be0a32a38009f1b Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +0800 Subject: [PATCH 06/11] kpatch/LoongArch: enable kpatch build Since kpatch now supports LoongArch basically, enable the build. Signed-off-by: George Guo --- README.md | 1 + kpatch-build/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5054ccdb..ff771344 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Supported Architectures - [x] ppc64le - [x] arm64 - [x] s390 [upstream prerequisites](doc/s390-upstream-prerequisites.md) +- [x] loongarch64 Installation ------------ diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile index 1f7ee4b1..c8f3bbaf 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 50ebd498c5bed825bf66d21bce2597ba876091fb Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 7efd1647..92e3bb68 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 05dc6e37dc87ec7d26488de54f02e718239e762c Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 fc9433ad..ad23df93 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 c955ec2230025c1037bb5411999dca162f932693 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 See also kernel commit 38b10b269d04540aee05c34a059dcf304cfce0a8 (LoongArch: Tweak CFLAGS for Clang compatibility) which said "This is actually a nice-to-have optimization that can reduce GOT accesses... ". Kernel adds "-mdirect-extern-access" to improve performance with the commit. Tested-by: Kexin Liu Signed-off-by: George Guo --- kpatch-build/kpatch-build | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 788585ac..e1d3b13d 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -319,6 +319,17 @@ find_core_symvers() { [[ -e "$SYMVERSFILE" ]] } +cc_option_check() { + local compiler="$1" + local option="$2" + + if "$compiler" -Werror "$option" -c -x c /dev/null -o /dev/null 2>/dev/null; then + return 0 + fi + + return 1 +} + gcc_version_from_file() { "$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*' } @@ -341,6 +352,11 @@ gcc_version_check() { return 1 fi + if [[ "$ARCH" = "loongarch64" ]]; then + cc_option_check "$GCC" "-mno-direct-extern-access" || \ + die "gcc version ($gccver) doesn't support -mno-direct-extern-access" + fi + out="$("$GCC" -c -gz=none -o "$o" "$c" 2>&1)" if [[ -z "$out" ]]; then DEBUG_KCFLAGS="-gz=none" @@ -371,6 +387,11 @@ clang_version_check() { clangver=$("$CLANG" --version | grep -m 1 -Eo 'clang version [0-9.]+') kclangver="$(clang_version_from_file "$target")" + if [[ "$ARCH" = "loongarch64" ]]; then + cc_option_check "$CLANG" "-fno-direct-access-external-data" || \ + die "clang version ($clangver) doesn't support -fno-direct-access-external-data" + fi + # ensure clang version matches that used to build the kernel if [[ "$clangver" != "$kclangver" ]]; then warn "clang/kernel version mismatch" @@ -1258,6 +1279,7 @@ remove_patches cp -LR "$DATADIR/patch" "$TEMPDIR" || die chmod -R u+rw "$TEMPDIR" || die +declare -a ARCH_MAKEVARS if [[ "$ARCH" = "ppc64le" ]]; then ARCH_KCFLAGS="-mcmodel=large -fplugin=$PLUGINDIR/ppc64le-plugin.so" fi @@ -1267,6 +1289,14 @@ if [[ "$ARCH" = "s390x" ]]; then ! kernel_version_gte 6.10.0 && ARCH_KCFLAGS+=" -fPIE" fi +if [[ "$ARCH" = "loongarch64" ]]; then + if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then + ARCH_MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=-fno-direct-access-external-data") + else + ARCH_MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=-mno-direct-extern-access") + fi +fi + export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \ $ARCH_KCFLAGS $DEBUG_KCFLAGS" @@ -1305,7 +1335,7 @@ fi # $TARGETS used as list, no quotes. # shellcheck disable=SC2086 -make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die +make "${ARCH_MAKEVARS[@]}" "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die # Save original module symvers cp -f "$BUILDDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die @@ -1318,7 +1348,7 @@ export KPATCH_GCC_SRCDIR="$BUILDDIR" save_env # $TARGETS used as list, no quotes. # shellcheck disable=SC2086 -KBUILD_MODPOST_WARN=1 make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die +KBUILD_MODPOST_WARN=1 make "${ARCH_MAKEVARS[@]}" "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die # source.c:(.section+0xFF): undefined reference to `symbol' grep "undefined reference" "$LOGFILE" | sed -r "s/^.*\`(.*)'$/\\1/" \ From f392b591002fd5a1bc57558deaa003bbfb11ce63 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 | 1 + 1 file changed, 1 insertion(+) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index e1d3b13d..996a866a 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -1290,6 +1290,7 @@ if [[ "$ARCH" = "s390x" ]]; then fi if [[ "$ARCH" = "loongarch64" ]]; then + ARCH_KCFLAGS="-fPIC" if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then ARCH_MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=-fno-direct-access-external-data") else From 36c59735975143a574c2ad5a9bdf434170607670 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sun, 4 Jan 2026 16:38:09 +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 e3ed7d71..91efbde3 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 4ad64a06..bf463645 160000 --- a/test/unit/objs +++ b/test/unit/objs @@ -1 +1 @@ -Subproject commit 4ad64a06b6d0a9b779348f04823f82b03e91942e +Subproject commit bf463645367ec892b0c0ba265d2deacbd6289581