Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Supported Architectures
- [x] ppc64le
- [x] arm64
- [x] s390 [upstream prerequisites](doc/s390-upstream-prerequisites.md)
- [x] loongarch64

Installation
------------
Expand Down
2 changes: 1 addition & 1 deletion kpatch-build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
39 changes: 34 additions & 5 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -771,6 +774,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)
Expand Down Expand Up @@ -2598,22 +2606,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,
},
Expand All @@ -2634,7 +2642,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,
},
{
Expand Down Expand Up @@ -3057,6 +3065,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");
Expand Down Expand Up @@ -4059,6 +4072,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");
}
Expand Down Expand Up @@ -4317,6 +4345,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
sym->has_func_profiling = 1;
break;
case AARCH64:
case LOONGARCH64:
if (kpatch_symbol_has_pfe_entry(kelf, sym))
sym->has_func_profiling = 1;
break;
Expand Down
38 changes: 36 additions & 2 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,17 @@ find_core_symvers() {
[[ -e "$SYMVERSFILE" ]]
}

cc_option_check() {
local compiler="$1"
local option="$2"

if "$compiler" -Werror "$option" -c -x c /dev/null -o /dev/null 2>/dev/null; then
return 0
fi

return 1
}

gcc_version_from_file() {
"$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*'
}
Expand All @@ -341,6 +352,11 @@ gcc_version_check() {
return 1
fi

if [[ "$ARCH" = "loongarch64" ]]; then
cc_option_check "$GCC" "-mno-direct-extern-access" || \
die "gcc version ($gccver) doesn't support -mno-direct-extern-access"
fi

out="$("$GCC" -c -gz=none -o "$o" "$c" 2>&1)"
if [[ -z "$out" ]]; then
DEBUG_KCFLAGS="-gz=none"
Expand Down Expand Up @@ -371,6 +387,11 @@ clang_version_check() {
clangver=$("$CLANG" --version | grep -m 1 -Eo 'clang version [0-9.]+')
kclangver="$(clang_version_from_file "$target")"

if [[ "$ARCH" = "loongarch64" ]]; then
cc_option_check "$CLANG" "-fno-direct-access-external-data" || \
die "clang version ($clangver) doesn't support -fno-direct-access-external-data"
fi

# ensure clang version matches that used to build the kernel
if [[ "$clangver" != "$kclangver" ]]; then
warn "clang/kernel version mismatch"
Expand Down Expand Up @@ -407,6 +428,9 @@ find_special_section_data() {
"aarch64")
check[a]=true # alt_instr
;;
"loongarch64")
check[a]=true # alt_instr
;;
esac

# Kernel CONFIG_ features
Expand Down Expand Up @@ -1255,6 +1279,7 @@ remove_patches
cp -LR "$DATADIR/patch" "$TEMPDIR" || die
chmod -R u+rw "$TEMPDIR" || die

declare -a ARCH_MAKEVARS
if [[ "$ARCH" = "ppc64le" ]]; then
ARCH_KCFLAGS="-mcmodel=large -fplugin=$PLUGINDIR/ppc64le-plugin.so"
fi
Expand All @@ -1264,6 +1289,15 @@ if [[ "$ARCH" = "s390x" ]]; then
! kernel_version_gte 6.10.0 && ARCH_KCFLAGS+=" -fPIE"
fi

if [[ "$ARCH" = "loongarch64" ]]; then
ARCH_KCFLAGS="-fPIC"
if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then
ARCH_MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=-fno-direct-access-external-data")
else
ARCH_MAKEVARS+=("KBUILD_CFLAGS_KERNEL+=-mno-direct-extern-access")
fi
fi

export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \
$ARCH_KCFLAGS $DEBUG_KCFLAGS"

Expand Down Expand Up @@ -1302,7 +1336,7 @@ fi

# $TARGETS used as list, no quotes.
# shellcheck disable=SC2086
make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die
make "${ARCH_MAKEVARS[@]}" "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die

# Save original module symvers
cp -f "$BUILDDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die
Expand All @@ -1315,7 +1349,7 @@ export KPATCH_GCC_SRCDIR="$BUILDDIR"
save_env
# $TARGETS used as list, no quotes.
# shellcheck disable=SC2086
KBUILD_MODPOST_WARN=1 make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die
KBUILD_MODPOST_WARN=1 make "${ARCH_MAKEVARS[@]}" "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die

# source.c:(.section+0xFF): undefined reference to `symbol'
grep "undefined reference" "$LOGFILE" | sed -r "s/^.*\`(.*)'$/\\1/" \
Expand Down
1 change: 1 addition & 0 deletions kpatch-build/kpatch-cc
Original file line number Diff line number Diff line change
Expand Up @@ -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|\
Expand Down
34 changes: 34 additions & 0 deletions kpatch-build/kpatch-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -349,6 +353,21 @@ 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,
Expand Down Expand Up @@ -614,6 +633,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");
}
Expand Down Expand Up @@ -647,6 +669,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;
}

Expand Down
6 changes: 6 additions & 0 deletions kpatch-build/kpatch-elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
* ****************/
Expand Down Expand Up @@ -117,6 +122,7 @@ enum architecture {
X86_64 = 0x1 << 1,
S390 = 0x1 << 2,
AARCH64 = 0x1 << 3,
LOONGARCH64 = 0x1 << 4,
};

struct kpatch_elf {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARCHES ?= aarch64 ppc64le x86_64
ARCHES ?= loongarch64 aarch64 ppc64le x86_64

.PHONY: all clean submodule-check

Expand Down