2024-03-02 00:18:20 +08:00
|
|
|
From 154b990912bed67bbaeedec1d53fd0881900da85 Mon Sep 17 00:00:00 2001
|
2023-10-20 21:13:08 +08:00
|
|
|
From: laokz <zhangkai@iscas.ac.cn>
|
|
|
|
|
Date: Fri, 20 Oct 2023 20:53:32 +0800
|
2024-03-02 00:18:20 +08:00
|
|
|
Subject: [PATCH 37/38] add initial riscv64 support
|
2023-10-20 21:13:08 +08:00
|
|
|
|
|
|
|
|
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
|
2024-03-02 00:18:20 +08:00
|
|
|
index 0df6cd2..0d1efcf 100644
|
2023-10-20 21:13:08 +08:00
|
|
|
--- a/kpatch-build/create-diff-object.c
|
|
|
|
|
+++ b/kpatch-build/create-diff-object.c
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -182,6 +182,7 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf,
|
2023-10-20 21:13:08 +08:00
|
|
|
case S390:
|
|
|
|
|
return false;
|
|
|
|
|
case ARM64:
|
|
|
|
|
+ case RISCV64:
|
|
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
ERROR("unsupported arch");
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -456,6 +457,18 @@ static int kpatch_mangled_strcmp(char *s1, char *s2)
|
2023-10-20 21:13:08 +08:00
|
|
|
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;
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -715,6 +728,10 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr)
|
2023-10-20 21:13:08 +08:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
+ case RISCV64:
|
|
|
|
|
+ /* Not implemented and I think it has less meaning. */
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
default:
|
|
|
|
|
ERROR("unsupported arch");
|
|
|
|
|
}
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -982,6 +999,10 @@ static void kpatch_compare_symbols(struct list_head *symlist)
|
2023-10-20 21:13:08 +08:00
|
|
|
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));
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -1127,6 +1148,11 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig,
|
2023-10-20 21:13:08 +08:00
|
|
|
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)
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -2528,7 +2554,7 @@ static bool static_call_sites_group_filter(struct lookup_table *lookup,
|
2023-10-20 21:13:08 +08:00
|
|
|
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,
|
|
|
|
|
},
|
|
|
|
|
{
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -2538,18 +2564,18 @@ static struct special_section special_sections[] = {
|
2023-10-20 21:13:08 +08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.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,
|
2024-03-02 00:18:20 +08:00
|
|
|
.group_filter = jump_table_group_filter,
|
2023-10-20 21:13:08 +08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = ".printk_index",
|
|
|
|
|
- .arch = X86_64 | PPC64 | S390 | ARM64,
|
|
|
|
|
+ .arch = X86_64 | PPC64 | S390 | ARM64 | RISCV64,
|
|
|
|
|
.group_size = printk_index_group_size,
|
|
|
|
|
},
|
|
|
|
|
{
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -3020,6 +3046,10 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf)
|
2023-10-20 21:13:08 +08:00
|
|
|
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);
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -3916,6 +3946,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
|
2023-10-20 21:13:08 +08:00
|
|
|
|
|
|
|
|
switch(kelf->arch) {
|
|
|
|
|
case PPC64:
|
|
|
|
|
+ case RISCV64:
|
|
|
|
|
case ARM64: {
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -4159,6 +4190,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
|
2023-10-20 21:13:08 +08:00
|
|
|
|
|
|
|
|
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
|
2024-03-02 00:18:20 +08:00
|
|
|
index 89d37c8..2f41690 100644
|
2023-10-20 21:13:08 +08:00
|
|
|
--- 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
|
2024-03-02 00:18:20 +08:00
|
|
|
index b639bc2..d6398b3 100644
|
2023-10-20 21:13:08 +08:00
|
|
|
--- 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");
|
|
|
|
|
}
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -600,6 +608,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name)
|
2023-10-20 21:13:08 +08:00
|
|
|
case EM_AARCH64:
|
|
|
|
|
kelf->arch = ARM64;
|
|
|
|
|
break;
|
|
|
|
|
+ case EM_RISCV:
|
|
|
|
|
+ kelf->arch = RISCV64;
|
|
|
|
|
+ break;
|
|
|
|
|
default:
|
|
|
|
|
ERROR("Unsupported target architecture");
|
|
|
|
|
}
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -1006,6 +1017,17 @@ void kpatch_rebuild_rela_section_data(struct section *sec)
|
2023-10-20 21:13:08 +08:00
|
|
|
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);
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -1020,6 +1042,10 @@ void kpatch_rebuild_rela_section_data(struct section *sec)
|
2023-10-20 21:13:08 +08:00
|
|
|
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
|
2024-03-02 00:18:20 +08:00
|
|
|
index 47e3117..f2cf60a 100644
|
2023-10-20 21:13:08 +08:00
|
|
|
--- a/kpatch-build/kpatch-elf.h
|
|
|
|
|
+++ b/kpatch-build/kpatch-elf.h
|
2024-03-02 00:18:20 +08:00
|
|
|
@@ -116,6 +116,7 @@ enum architecture {
|
2023-10-20 21:13:08 +08:00
|
|
|
X86_64 = 0x1 << 1,
|
|
|
|
|
S390 = 0x1 << 2,
|
|
|
|
|
ARM64 = 0x1 << 3,
|
|
|
|
|
+ RISCV64= 0x1 << 4,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct kpatch_elf {
|
|
|
|
|
--
|
2024-03-02 00:18:20 +08:00
|
|
|
2.33.0
|
2023-10-20 21:13:08 +08:00
|
|
|
|