!107 增加riscv64的初步支持
From: @laokz Reviewed-by: @xiezhipeng1 Signed-off-by: @xiezhipeng1
This commit is contained in:
commit
f1c9c54564
305
0049-add-initial-riscv64-support.patch
Normal file
305
0049-add-initial-riscv64-support.patch
Normal file
@ -0,0 +1,305 @@
|
||||
From c6b399359956bf798f685f5b3aaf47fcf02de523 Mon Sep 17 00:00:00 2001
|
||||
From: laokz <zhangkai@iscas.ac.cn>
|
||||
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 <wangjunqiang@iscas.ac.cn>
|
||||
Signed-off-by: laokz <zhangkai@iscas.ac.cn>
|
||||
---
|
||||
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
|
||||
|
||||
@ -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 <zhangkai@iscas.ac.cn> -1:0.9.7-7
|
||||
- Type:enhancement
|
||||
- ID:NA
|
||||
- SUG:NA
|
||||
- DESC:add initial riscv64 support
|
||||
|
||||
* Thu Nov 30 2023 Zhipeng Xie <xiezhipeng1@huawei.com> -1:0.9.7-6
|
||||
- Type:enhancement
|
||||
- ID:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user