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 diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index b1496270..91d4e30d 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, }, { @@ -3048,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"); @@ -4050,6 +4063,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"); } @@ -4311,6 +4339,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"); } diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 3343f37d..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 @@ -405,6 +421,9 @@ find_special_section_data() { "aarch64") check[a]=true # alt_instr ;; + "loongarch64") + check[a]=true # alt_instr + ;; esac # Kernel CONFIG_ features @@ -1288,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 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|\ diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 11ce4554..42ce24a4 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: @@ -349,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, @@ -614,6 +634,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"); } @@ -647,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; } diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h index 4a4c5a56..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 * ****************/ @@ -117,6 +122,7 @@ enum architecture { X86_64 = 0x1 << 1, S390 = 0x1 << 2, AARCH64 = 0x1 << 3, + LOONGARCH64 = 0x1 << 4, }; struct kpatch_elf {