diff --git a/0049-add-initial-riscv64-support.patch b/0049-add-initial-riscv64-support.patch new file mode 100644 index 0000000..6bbfdab --- /dev/null +++ b/0049-add-initial-riscv64-support.patch @@ -0,0 +1,305 @@ +From c6b399359956bf798f685f5b3aaf47fcf02de523 Mon Sep 17 00:00:00 2001 +From: laokz +Date: Fri, 20 Oct 2023 20:53:32 +0800 +Subject: [PATCH] add initial riscv64 support + +Per the RISC-V psABI, PCREL_HI20 and PCREL_LO12 must +sit in the same section. PCREL_HI20 may be a global +symbol and might be moved to .klp.rela section, so +thouth PCREL_LO12 is a local symbol ".L0 " it must +also be moved to .klp.rela section. This break the +current livepatch specification, but it is inevitable. + +Only support openEuler LIVEPATCH_WO_FTRACE mechanism. + +Signed-off-by: wangjunqiang +Signed-off-by: laokz +--- + kpatch-build/Makefile | 2 +- + kpatch-build/create-diff-object.c | 40 +++++++++++++++++++++++++++--- + kpatch-build/create-klp-module.c | 41 +++++++++++++++++++++++++++++++ + kpatch-build/kpatch-elf.c | 26 ++++++++++++++++++++ + kpatch-build/kpatch-elf.h | 1 + + 5 files changed, 105 insertions(+), 5 deletions(-) + +diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile +index 5037677..f24165b 100644 +--- a/kpatch-build/Makefile ++++ b/kpatch-build/Makefile +@@ -22,7 +22,7 @@ PLUGIN_CFLAGS := $(filter-out -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 riscv64),) + $(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 0e91513..cca2781 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -177,6 +177,7 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, + case S390: + return false; + case ARM64: ++ case RISCV64: + return false; + default: + ERROR("unsupported arch"); +@@ -444,6 +445,18 @@ static int kpatch_mangled_strcmp(char *s1, char *s2) + if (!strncmp(s1, "__UNIQUE_ID_", 12)) + return __kpatch_unique_id_strcmp(s1, s2); + ++#ifdef __riscv ++ /* ++ * Normally, .L local symbols are not saved in object files. But on RISC-V it IS! ++ * Their names are volatile even with minor changes in other place. So we can ++ * not compare their names reliably. If we must do comparison, just think them ++ * all have the same name. ++ * In fact, we neither correlate them nor give them NEW status. ++ */ ++ if (!strncmp(s1, ".L", 2) && !strncmp(s2, ".L", 2)) ++ return 0; ++#endif ++ + while (*s1 == *s2) { + if (!*s1) + return 0; +@@ -703,6 +716,10 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr) + + break; + ++ case RISCV64: ++ /* Not implemented and I think it has less meaning. */ ++ break; ++ + default: + ERROR("unsupported arch"); + } +@@ -970,6 +987,10 @@ static void kpatch_compare_symbols(struct list_head *symlist) + if (sym->twin) + kpatch_compare_correlated_symbol(sym); + else ++#ifdef __riscv ++ /* Don't set NEW status for .L local symbols. */ ++ if (strncmp(sym->name, ".L", 2)) ++#endif + sym->status = NEW; + + log_debug("symbol %s is %s\n", sym->name, status_str(sym->status)); +@@ -1112,6 +1133,11 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig, + list_for_each_entry(sym_orig, symlist_orig, list) { + if (sym_orig->twin) + continue; ++#ifdef __riscv ++ /* Don't correlate .L local symbols. */ ++ if (!strncmp(sym_orig->name, ".L", 2)) ++ continue; ++#endif + list_for_each_entry(sym_patched, symlist_patched, list) { + if (kpatch_mangled_strcmp(sym_orig->name, sym_patched->name) || + sym_orig->type != sym_patched->type || sym_patched->twin) +@@ -2327,7 +2353,7 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset) + static struct special_section special_sections[] = { + { + .name = "__bug_table", +- .arch = X86_64 | PPC64 | S390 | ARM64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64, + .group_size = bug_table_group_size, + }, + { +@@ -2337,17 +2363,17 @@ static struct special_section special_sections[] = { + }, + { + .name = "__ex_table", /* must come after .fixup */ +- .arch = X86_64 | PPC64 | S390 | ARM64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64, + .group_size = ex_table_group_size, + }, + { + .name = "__jump_table", +- .arch = X86_64 | PPC64 | S390 | ARM64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64, + .group_size = jump_table_group_size, + }, + { + .name = ".printk_index", +- .arch = X86_64 | PPC64 | S390 | ARM64, ++ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64, + .group_size = printk_index_group_size, + }, + { +@@ -2916,6 +2942,10 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) + strsec->secsym->include = 1; + + name = strsec->data->d_buf + rela->addend; ++ /* RISC-V use st_value as offset into string table, addend always 0. */ ++ if (kelf->arch == RISCV64) ++ name += rela->sym->sym.st_value; ++ + ignoresec = find_section_by_name(&kelf->sections, name); + if (!ignoresec) + ERROR("KPATCH_IGNORE_SECTION: can't find %s", name); +@@ -3812,6 +3842,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) + + switch(kelf->arch) { + case PPC64: ++ case RISCV64: + case ARM64: { + bool found = false; + +@@ -4048,6 +4079,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) + + switch(kelf->arch) { + case PPC64: ++ case RISCV64: + case ARM64: + list_for_each_entry(rela, &sym->sec->rela->relas, list) { + if (!strcmp(rela->sym->name, "_mcount")) { +diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c +index b77028f..dbf4ad4 100644 +--- a/kpatch-build/create-klp-module.c ++++ b/kpatch-build/create-klp-module.c +@@ -162,6 +162,43 @@ static struct section *find_or_add_klp_relasec(struct kpatch_elf *kelf, + return relasec; + } + ++/* ++ * Per the RISC-V psABI: ++ * ++ * In the linker relaxation optimization, we introduce a concept called relocation ++ * group; a relocation group consists of 1) relocations associated with the same ++ * target symbol and can be applied with the same relaxation, or 2) relocations ++ * with the linkage relationship (e.g. `R_RISCV_PCREL_LO12_S` linked with ++ * a `R_RISCV_PCREL_HI20`); all relocations in a single group must be present in ++ * the same section, otherwise will split into another relocation group. ++ * ++ * I think that PCREL_L012 must always be in the same section with PCREL_HI20 ++ * in any cases, and noticed that linux kernel does the same assumption. ++ * ++ * So here we have to move PCREL_L012 to .klp.rela section along with its PCREL_HI20 ++ * part. Note it's still a normal relocation entry, not a klp entry, and the kernel ++ * should recognize it. ++ */ ++static void rv64_mv_lo12_to_klp_rela(struct kpatch_elf *kelf, unsigned short shndx, ++ unsigned int hi20offset, struct section *klp_relasec) ++{ ++ struct rela *relalo12, *n; ++ struct section *sec = find_section_by_index(&kelf->sections, shndx); ++ ++ if (!sec) ++ ERROR("rv64_mv_lo12_to_klp_rela"); ++ ++ list_for_each_entry_safe(relalo12, n, &sec->rela->relas, list) { ++ if (hi20offset == relalo12->sym->sym.st_value && ++ (relalo12->type == R_RISCV_PCREL_LO12_I || ++ relalo12->type == R_RISCV_PCREL_LO12_S)) { ++ list_del(&relalo12->list); ++ list_add_tail(&relalo12->list, &klp_relasec->relas); ++ return; ++ } ++ } ++} ++ + /* + * Create klp relocation sections and klp symbols from .kpatch.relocations + * and .kpatch.symbols sections +@@ -240,6 +277,10 @@ static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section + rela->type = krelas[index].type; + rela->sym = sym; + rela->addend = krelas[index].addend; ++ ++ if ((kelf->arch == RISCV64) && ++ (rela->type == R_RISCV_PCREL_HI20 || rela->type == R_RISCV_GOT_HI20)) ++ rv64_mv_lo12_to_klp_rela(kelf, dest->sym.st_shndx, dest_off, klp_relasec); + } + } + +diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c +index 572f272..40ea6a8 100644 +--- a/kpatch-build/kpatch-elf.c ++++ b/kpatch-build/kpatch-elf.c +@@ -144,6 +144,8 @@ unsigned int absolute_rela_type(struct kpatch_elf *kelf) + return R_390_64; + case ARM64: + return R_AARCH64_ABS64; ++ case RISCV64: ++ return R_RISCV_64; + default: + ERROR("unsupported arch"); + } +@@ -209,6 +211,7 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, + switch(kelf->arch) { + case PPC64: + case ARM64: ++ case RISCV64: + add_off = 0; + break; + case X86_64: +@@ -278,6 +281,11 @@ unsigned int insn_length(struct kpatch_elf *kelf, void *addr) + return 6; + } + ++ case RISCV64: ++ if ((insn[0] & 0x3) == 0x3) ++ return 4; ++ return 2; ++ + default: + ERROR("unsupported arch"); + } +@@ -508,6 +516,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name) + case EM_AARCH64: + kelf->arch = ARM64; + break; ++ case EM_RISCV: ++ kelf->arch = RISCV64; ++ break; + default: + ERROR("Unsupported target architecture"); + } +@@ -902,6 +913,17 @@ void kpatch_rebuild_rela_section_data(struct section *sec) + size_t size; + + list_for_each_entry(rela, &sec->relas, list) ++#ifdef __riscv ++ /* ++ * R_RISCV_ALIGN is used for LTO and shall be consumed by linker. ++ * Kernel'll see it as an error if encountered. ++ * But kpatch-build only does partial linking($LD -r) and later ++ * strip has no way to remove the relocation entries alone. That ++ * would cause it been left in the .ko falsely. ++ * Here we have to discard it. ++ */ ++ if(rela->type != R_RISCV_ALIGN) ++#endif + nr++; + + size = nr * sizeof(*relas); +@@ -916,6 +938,10 @@ void kpatch_rebuild_rela_section_data(struct section *sec) + sec->sh.sh_size = size; + + list_for_each_entry(rela, &sec->relas, list) { ++#ifdef __riscv ++ if(rela->type == R_RISCV_ALIGN) ++ continue; ++#endif + relas[index].r_offset = rela->offset; + relas[index].r_addend = rela->addend; + relas[index].r_info = GELF_R_INFO(rela->sym->index, rela->type); +diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h +index d887812..6624b2d 100644 +--- a/kpatch-build/kpatch-elf.h ++++ b/kpatch-build/kpatch-elf.h +@@ -114,6 +114,7 @@ enum architecture { + X86_64 = 0x1 << 1, + S390 = 0x1 << 2, + ARM64 = 0x1 << 3, ++ RISCV64= 0x1 << 4, + }; + + struct kpatch_elf { +-- +2.42.0 + diff --git a/kpatch.spec b/kpatch.spec index 001f640..06041d0 100644 --- a/kpatch.spec +++ b/kpatch.spec @@ -1,7 +1,7 @@ Name: kpatch Epoch: 1 Version: 0.9.7 -Release: 6 +Release: 7 Summary: A Linux dynamic kernel patching infrastructure License: GPLv2 @@ -64,6 +64,7 @@ Patch0048:0052-patch-author-guide-update-jump-label-static-call-des.patch Patch0049:0056-kpatch-build-ignore-init-version-timestamp.o.patch Patch0050:0066-INSTALL.md-update-OpenEuler-prereqs-formatting.patch Patch0051:0070-Fix-undefined-behavior-problem-when-using-list_forea.patch +Patch0052:0049-add-initial-riscv64-support.patch BuildRequires: gcc elfutils-libelf-devel kernel-devel git Requires: bc make gcc patch bison flex openssl-devel @@ -124,6 +125,12 @@ popd %{_mandir}/man1/*.1.gz %changelog +* Fri Dec 1 2023 laokz -1:0.9.7-7 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add initial riscv64 support + * Thu Nov 30 2023 Zhipeng Xie -1:0.9.7-6 - Type:enhancement - ID:NA