Merge pull request #1203 from sumanthkorikkar/s390x-kpatch-support

S390x kpatch support
This commit is contained in:
Joe Lawrence 2022-06-29 09:55:53 -04:00 committed by GitHub
commit dc7e5cb03d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 166 additions and 22 deletions

View File

@ -41,7 +41,7 @@ Supported Architectures
- [x] x86-64
- [x] ppc64le
- [ ] arm64
- [ ] s390
- [x] s390 [upstream prerequisites](doc/s390-upstream-prerequisites.md)
Installation
------------

View File

@ -0,0 +1,33 @@
### s390 backporting
**Prerequisite gcc patches (all backported to releases/gcc-11 branch):**
- gcc-mirror/gcc@a1c1b7a IBM Z: Define NO_PROFILE_COUNTERS
- gcc-mirror/gcc@0990d93 IBM Z: Use @PLT symbols for local functions in 64-bit mode
- gcc-mirror/gcc@935b522 S/390: New option -mpic-data-is-text-relative
- gcc-mirror/gcc@8753b13 IBM Z: fix section type conflict with -mindirect-branch-table
**Prerequisite kernel patches:**
**v5.19:**
- 69505e3d9a39 bug: Use normal relative pointers in 'struct bug_entry'
**v5.18:**
- 602bf1687e6f s390/nospec: align and size extern thunks
- 1d2ad084800e s390/nospec: add an option to use thunk-extern
- eed38cd2f46f s390/nospec: generate single register thunks if possible
- 2268169c14e5 s390: remove unused expoline to BC instructions
- f0003a9e4c18 s390/entry: remove unused expoline thunk
**v5.16:**
- torvalds/linux@f6ac18f sched: Improve try_invoke_on_locked_down_task()
- torvalds/linux@9b3c4ab sched,rcu: Rework try_invoke_on_locked_down_task()
- torvalds/linux@00619f7 sched,livepatch: Use task_call_func()
- torvalds/linux@8850cb6 sched: Simplify wake_up_*idle*()
- torvalds/linux@5de62ea sched,livepatch: Use wake_up_if_idle()
- torvalds/linux@96611c2 sched: Improve wake_up_all_idle_cpus() take #2
**v5.15**
- torvalds/linux@de5012b s390/ftrace: implement hotpatching
- torvalds/linux@67ccddf ftrace: Introduce ftrace_need_init_nop()
**v5.14:**
- torvalds/linux@7561c14 s390/vdso: add .got.plt in vdso linker script

View File

@ -21,7 +21,8 @@ GCC_PLUGINS_DIR := $(shell $(CROSS_COMPILE)gcc -print-file-name=plugin)
PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS))
PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \
-Igcc-plugins -fPIC -fno-rtti -O2 -Wall
else ifneq ($(ARCH),x86_64)
endif
ifeq ($(filter $(ARCH),s390x x86_64 ppc64le),)
$(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures)
endif

View File

@ -118,6 +118,16 @@ static bool is_bundleable(struct symbol *sym)
!strcmp(sym->sec->name + 13, sym->name))
return true;
if (sym->type == STT_OBJECT &&
!strncmp(sym->sec->name, ".data.rel.ro.local.", 19) &&
!strcmp(sym->sec->name + 19, sym->name))
return 1;
if (sym->type == STT_OBJECT &&
!strncmp(sym->sec->name, ".data.rel.local.", 16) &&
!strcmp(sym->sec->name + 16, sym->name))
return 1;
if (sym->type == STT_OBJECT &&
!strncmp(sym->sec->name, ".rodata.",8) &&
!strcmp(sym->sec->name + 8, sym->name))
@ -163,6 +173,8 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf,
sym->sym.st_value == 8);
case X86_64:
return false;
case S390:
return false;
default:
ERROR("unsupported arch");
}
@ -304,8 +316,7 @@ static bool is_dynamic_debug_symbol(struct symbol *sym)
static bool is_string_literal_section(struct section *sec)
{
return !strncmp(sec->name, ".rodata.", 8) &&
strstr(sec->name, ".str1.");
return !strncmp(sec->name, ".rodata.", 8) && strstr(sec->name, ".str");
}
/*
@ -2104,6 +2115,17 @@ static int fixup_barrier_nospec_group_size(struct kpatch_elf *kelf, int offset)
return 8;
}
/*
* .s390_indirect_jump, .s390_indirect_call, .s390_indirect_branches,
* .s390_return_reg, .s390_return_mem contains indirect branch locations. This
* is an array of 32 bit elements. These sections could be used during runtime
* to replace the expolines with the normal indirect jump.
*/
static int s390_expolines_group_size(struct kpatch_elf *kelf, int offset)
{
return 4;
}
/*
* The rela groups in the .fixup section vary in size. The beginning of each
* .fixup rela group is referenced by the __ex_table section. To find the size
@ -2157,27 +2179,27 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset)
static struct special_section special_sections[] = {
{
.name = "__bug_table",
.arch = X86_64 | PPC64,
.arch = X86_64 | PPC64 | S390,
.group_size = bug_table_group_size,
},
{
.name = ".fixup",
.arch = X86_64 | PPC64,
.arch = X86_64 | PPC64 | S390,
.group_size = fixup_group_size,
},
{
.name = "__ex_table", /* must come after .fixup */
.arch = X86_64 | PPC64,
.arch = X86_64 | PPC64 | S390,
.group_size = ex_table_group_size,
},
{
.name = "__jump_table",
.arch = X86_64 | PPC64,
.arch = X86_64 | PPC64 | S390,
.group_size = jump_table_group_size,
},
{
.name = ".printk_index",
.arch = X86_64 | PPC64,
.arch = X86_64 | PPC64 | S390,
.group_size = printk_index_group_size,
},
{
@ -2192,7 +2214,7 @@ static struct special_section special_sections[] = {
},
{
.name = ".altinstructions",
.arch = X86_64,
.arch = X86_64 | S390,
.group_size = altinstructions_group_size,
},
{
@ -2230,6 +2252,31 @@ static struct special_section special_sections[] = {
.arch = PPC64,
.group_size = fixup_barrier_nospec_group_size,
},
{
.name = ".s390_return_mem",
.arch = S390,
.group_size = s390_expolines_group_size,
},
{
.name = ".s390_return_reg",
.arch = S390,
.group_size = s390_expolines_group_size,
},
{
.name = ".s390_indirect_call",
.arch = S390,
.group_size = s390_expolines_group_size,
},
{
.name = ".s390_indirect_branches",
.arch = S390,
.group_size = s390_expolines_group_size,
},
{
.name = ".s390_indirect_jump",
.arch = S390,
.group_size = s390_expolines_group_size,
},
{},
};
@ -3024,6 +3071,11 @@ static bool kpatch_is_core_module_symbol(char *name)
!strcmp(name, "kpatch_shadow_get"));
}
static bool is_expoline(struct kpatch_elf *kelf, char *name)
{
return kelf->arch == S390 && !strncmp(name, "__s390_indirect_jump_r", 22);
}
static int function_ptr_rela(const struct rela *rela)
{
const struct rela *rela_toc = toc_rela(rela);
@ -3082,6 +3134,13 @@ static bool need_dynrela(struct kpatch_elf *kelf, struct lookup_table *table,
if (kpatch_is_core_module_symbol(rela->sym->name))
return false;
/*
* Allow references to s390 expolines to remain as normal relas. They
* will be generated in the module by the kernel module link.
*/
if (is_expoline(kelf, rela->sym->name))
return false;
if (rela->sym->sec) {
/*
* Internal symbols usually don't need dynrelas, because they
@ -3559,6 +3618,10 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
rela->type = R_X86_64_PC32;
break;
}
case S390: {
insn_offset = sym->sym.st_value;
break;
}
default:
ERROR("unsupported arch");
}
@ -3724,6 +3787,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
{
struct symbol *sym;
struct rela *rela;
unsigned char *insn;
list_for_each_entry(sym, &kelf->symbols, list) {
if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela)
continue;
@ -3748,6 +3812,14 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
sym->has_func_profiling = 1;
break;
case S390:
/* Check for compiler generated fentry nop - jgnop 0 */
insn = sym->sec->data->d_buf;
if (insn[0] == 0xc0 && insn[1] == 0x04 &&
insn[2] == 0x00 && insn[3] == 0x00 &&
insn[4] == 0x00 && insn[5] == 0x00)
sym->has_func_profiling = 1;
break;
default:
ERROR("unsupported arch");
}

View File

@ -343,12 +343,18 @@ find_special_section_data() {
check[e]=true # exception_table_entry
# Arch-specific features, without kernel CONFIG_ toggle
if [[ "$ARCH" = "x86_64" ]]; then
check[a]=true # alt_instr
kernel_version_gte 5.10.0 && check[s]=true # static_call_site
elif [[ "$ARCH" = "ppc64le" ]]; then
check[f]=true # fixup_entry
fi
case "$ARCH" in
"x86_64")
check[a]=true # alt_instr
kernel_version_gte 5.10.0 && check[s]=true # static_call_site
;;
"ppc64le")
check[f]=true # fixup_entry
;;
"s390x")
check[a]=true # alt_instr
;;
esac
# Kernel CONFIG_ features
[[ -n "$CONFIG_PRINTK_INDEX" ]] && check[i]=true # pi_entry
@ -856,6 +862,7 @@ trace_on
die "openEuler kernel doesn't have 'CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY' enabled"
[[ -z "$CONFIG_DEBUG_INFO" ]] && die "kernel doesn't have 'CONFIG_DEBUG_INFO' enabled"
[[ "$ARCH" = "s390x" ]] && [[ -z "$CONFIG_EXPOLINE_EXTERN" ]] && [[ -n "$CONFIG_EXPOLINE" ]] && die "kernel doesn't have 'CONFIG_EXPOLINE_EXTERN' enabled"
# Build variables - Set some defaults, then adjust features
# according to .config and kernel version
@ -937,6 +944,10 @@ if [[ "$ARCH" = "ppc64le" ]]; then
ARCH_KCFLAGS="-mcmodel=large -fplugin=$PLUGINDIR/ppc64le-plugin.so"
fi
if [[ "$ARCH" = "s390x" ]]; then
ARCH_KCFLAGS="-mno-pic-data-is-text-relative -fno-section-anchors"
fi
export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \
$ARCH_KCFLAGS $DEBUG_KCFLAGS"

View File

@ -43,6 +43,9 @@ if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; th
drivers/firmware/efi/libstub/*|\
arch/powerpc/kernel/prom_init.o|\
arch/powerpc/kernel/vdso64/*|\
arch/s390/boot/*|\
arch/s390/purgatory/*|\
arch/s390/kernel/vdso64/*|\
lib/*|\
.*.o|\
*/.lib_exports.o)

View File

@ -140,6 +140,8 @@ unsigned int absolute_rela_type(struct kpatch_elf *kelf)
return R_PPC64_ADDR64;
case X86_64:
return R_X86_64_64;
case S390:
return R_390_64;
default:
ERROR("unsupported arch");
}
@ -222,6 +224,23 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec,
} else
ERROR("unhandled rela type %d", rela->type);
break;
case S390:
/*
* For branch and relative load instructions,
* add_off is -2.
*/
if (rela->type == R_390_GOTENT ||
rela->type == R_390_PLT32DBL ||
rela->type == R_390_PC32DBL)
add_off = -2;
else if (rela->type == R_390_32 ||
rela->type == R_390_64 ||
rela->type == R_390_PC32 ||
rela->type == R_390_PC64)
add_off = 0;
else
ERROR("unhandled rela type %d", rela->type);
break;
default:
ERROR("unsupported arch\n");
}
@ -479,6 +498,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name)
case EM_X86_64:
kelf->arch = X86_64;
break;
case EM_S390:
kelf->arch = S390;
break;
default:
ERROR("Unsupported target architecture");
}

View File

@ -272,12 +272,14 @@ static void symtab_read(struct lookup_table *table, char *path)
* tables. .dynsym is just a subset of .symtab, so skip it to
* avoid duplicates.
*/
if (strstr(line, ".dynsym")) {
skip = true;
continue;
} else if (strstr(line, ".symtab")) {
skip = false;
continue;
if (!strncmp(line, "Symbol table ", 13)) {
if (strstr(line, ".dynsym")) {
skip = true;
continue;
} else if (strstr(line, ".symtab")) {
skip = false;
continue;
}
}
if (skip)
continue;