mirror of https://github.com/dynup/kpatch
Merge pull request #1203 from sumanthkorikkar/s390x-kpatch-support
S390x kpatch support
This commit is contained in:
commit
dc7e5cb03d
|
@ -41,7 +41,7 @@ Supported Architectures
|
|||
- [x] x86-64
|
||||
- [x] ppc64le
|
||||
- [ ] arm64
|
||||
- [ ] s390
|
||||
- [x] s390 [upstream prerequisites](doc/s390-upstream-prerequisites.md)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue