From 2e0551d0e14018ae8049416781f1d1aae23d84ac Mon Sep 17 00:00:00 2001 From: George Guo Date: Thu, 8 Aug 2024 09:04:22 +0800 Subject: [PATCH 01/10] 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 3343f37d..7408026c 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 4835b29e3273da773662dc99b00ee971e5ec4c05 Mon Sep 17 00:00:00 2001 From: George Guo Date: Sat, 17 Aug 2024 13:04:22 +0800 Subject: [PATCH 02/10] 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 b1496270..a5422d18 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 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 daf937708f6be3fe19be67e738cb3005f8237704 Mon Sep 17 00:00:00 2001 From: George Guo Date: Thu, 5 Dec 2024 15:21:15 +0800 Subject: [PATCH 03/10] 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 | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index a5422d18..43aea8a1 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"); } @@ -4319,6 +4334,12 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) if (kpatch_symbol_has_pfe_entry(kelf, sym)) sym->has_func_profiling = 1; break; + case LOONGARCH64: + + if (kpatch_symbol_has_pfe_entry(kelf, sym)) + sym->has_func_profiling = 1; + break; + default: ERROR("unsupported arch"); } From a33aec9993b657d7211ae9c642ff27f5f855659b Mon Sep 17 00:00:00 2001 From: George Guo Date: Thu, 5 Dec 2024 15:17:43 +0800 Subject: [PATCH 04/10] 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 | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index b702cf37..42ce24a4 100755 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -353,6 +353,22 @@ 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 +670,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 018676a158f99ff0927b81e5a3cebef316edda34 Mon Sep 17 00:00:00 2001 From: George Guo Date: Tue, 10 Dec 2024 20:44:33 -0600 Subject: [PATCH 05/10] 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 43aea8a1..91d4e30d 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 c568de104df32d406ca6e84ac1f7f70c07ee0dc6 Mon Sep 17 00:00:00 2001 From: George Guo Date: Thu, 7 Nov 2024 11:13:50 +0800 Subject: [PATCH 06/10] 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 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 850331fe476f5f62ff2d11ea1361058377a0b24d Mon Sep 17 00:00:00 2001 From: George Guo Date: Fri, 8 Nov 2024 15:03:26 +0800 Subject: [PATCH 07/10] 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 eab48a0e288070f60b2ce2a7dff7036718aadb9e Mon Sep 17 00:00:00 2001 From: George Guo Date: Wed, 22 Jan 2025 10:43:42 +0800 Subject: [PATCH 08/10] 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 57d145888bf37bf61b46e690a3855dc0caab6d67 Mon Sep 17 00:00:00 2001 From: george Date: Tue, 23 Sep 2025 00:51:42 +0800 Subject: [PATCH 09/10] 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 7408026c..72ef438c 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,7 +1307,15 @@ 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 + if [[ "$ARCH" = "loongarch64" ]]; then + cc_option_check "-mno-direct-extern-access" + MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=${CC_OPTION}") + fi MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${GCC}") fi From 3d44f1bf6ef646502c7fe9a78166e0e09f14c0f1 Mon Sep 17 00:00:00 2001 From: George Guo Date: Mon, 17 Nov 2025 18:42:38 +0800 Subject: [PATCH 10/10] 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 Singed-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 72ef438c..cf9b3e5d 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"