-
Notifications
You must be signed in to change notification settings - Fork 335
Add LoongArch support for kpatch v2 #1427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2e0551d
4835b29
daf9377
a33aec9
018676a
c568de1
850331f
eab48a0
57d1458
3d44f1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: spacing, should be;
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, any idea why .rela.orc_unwind_ip is needed only on LoongArch64? What about .rela.orc_unwind ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| 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) | ||
georgejguo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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: | ||
|
|
||
georgejguo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (kpatch_symbol_has_pfe_entry(kelf, sym)) | ||
| sym->has_func_profiling = 1; | ||
| break; | ||
|
|
||
| default: | ||
| ERROR("unsupported arch"); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
| } | ||
|
|
||
georgejguo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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 | ||
|
|
@@ -1269,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" | ||
|
|
||
|
|
@@ -1288,7 +1311,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}") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: just a consistency nit here, can we set the arch
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It sounds like this:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| fi | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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); | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious, which kernel source files are generating these symbols?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okey, I will try to find it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: extra blank line here |
||
|
|
||
|
|
||
| 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; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I m not sure here, so just commit "to be done". Actually it can pass my simple test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used to detect when a section has changed only due to
__LINE__macro changes (e.g., in WARN() or might_sleep() calls). The current implementation will returnfalsefor LoongArch64, which means it won't detect__LINE__-only changes. This is acceptable as a temporary measure (the function will still work, just won't optimize away false positives), but shouldn't be hard to implement.I don't have a loongarch64 kernel handy, but with clang I see something like:
when I shift around the source lines of:
I would try editing a file like kernel/fork.c and add something like
pr_info("%d", __LINE__);to nr_processes() and a simplepr_info("kpatch");to copy_signal(). Then create a kpatch that moves the first change down a few lines in the source file and update the "kpatch" string. Ideally kpatch-build will only pull out the changes to copy_signal() and ignore the trivial debugging line number update in nr_processes().To handle this on loongarch64, hopefully it's as simple as adding the
li.wopcodes here (like the other arches). I'd be willing to merge w/o if you want to do this as a follow up, but thought I'd at least explain it here, let me know.