diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-04-25 12:35:26 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-05-07 15:12:38 -0400 |
commit | 23a4d7fd34856da8218c4cfc23dba7a6ec0a423a (patch) | |
tree | f6bf7c9d6e0f61af64bba6877562e63793b8e4c1 | |
parent | 97489e0663fa700d6e7febddc43b58df98d7bcda (diff) |
s390/ftrace: use expoline for indirect branches
The return from the ftrace_stub, _mcount, ftrace_caller and
return_to_handler functions is done with "br %r14" and "br %r1".
These are indirect branches as well and need to use execute
trampolines for CONFIG_EXPOLINE=y.
The ftrace_caller function is a special case as it returns to the
start of a function and may only use %r0 and %r1. For a pre z10
machine the standard execute trampoline uses a LARL + EX to do
this, but this requires *two* registers in the range %r1..%r15.
To get around this the 'br %r1' located in the lowcore is used,
then the EX instruction does not need an address register.
But the lowcore trick may only be used for pre z14 machines,
with noexec=on the mapping for the first page may not contain
instructions. The solution for that is an ALTERNATIVE in the
expoline THUNK generated by 'GEN_BR_THUNK %r1' to switch to
EXRL, this relies on the fact that a machine that supports
noexec=on has EXRL as well.
Cc: stable@vger.kernel.org # 4.16
Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches")
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/nospec-insn.h | 12 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/mcount.S | 14 |
3 files changed, 22 insertions, 5 deletions
diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h index 440689cbcf51..7d7640e1cf90 100644 --- a/arch/s390/include/asm/nospec-insn.h +++ b/arch/s390/include/asm/nospec-insn.h | |||
@@ -2,12 +2,16 @@ | |||
2 | #ifndef _ASM_S390_NOSPEC_ASM_H | 2 | #ifndef _ASM_S390_NOSPEC_ASM_H |
3 | #define _ASM_S390_NOSPEC_ASM_H | 3 | #define _ASM_S390_NOSPEC_ASM_H |
4 | 4 | ||
5 | #include <asm/alternative-asm.h> | ||
6 | #include <asm/asm-offsets.h> | ||
5 | #include <asm/dwarf.h> | 7 | #include <asm/dwarf.h> |
6 | 8 | ||
7 | #ifdef __ASSEMBLY__ | 9 | #ifdef __ASSEMBLY__ |
8 | 10 | ||
9 | #ifdef CONFIG_EXPOLINE | 11 | #ifdef CONFIG_EXPOLINE |
10 | 12 | ||
13 | _LC_BR_R1 = __LC_BR_R1 | ||
14 | |||
11 | /* | 15 | /* |
12 | * The expoline macros are used to create thunks in the same format | 16 | * The expoline macros are used to create thunks in the same format |
13 | * as gcc generates them. The 'comdat' section flag makes sure that | 17 | * as gcc generates them. The 'comdat' section flag makes sure that |
@@ -78,13 +82,21 @@ | |||
78 | .endm | 82 | .endm |
79 | 83 | ||
80 | .macro __THUNK_EX_BR reg,ruse | 84 | .macro __THUNK_EX_BR reg,ruse |
85 | # Be very careful when adding instructions to this macro! | ||
86 | # The ALTERNATIVE replacement code has a .+10 which targets | ||
87 | # the "br \reg" after the code has been patched. | ||
81 | #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES | 88 | #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES |
82 | exrl 0,555f | 89 | exrl 0,555f |
83 | j . | 90 | j . |
84 | #else | 91 | #else |
92 | .ifc \reg,%r1 | ||
93 | ALTERNATIVE "ex %r0,_LC_BR_R1", ".insn ril,0xc60000000000,0,.+10", 35 | ||
94 | j . | ||
95 | .else | ||
85 | larl \ruse,555f | 96 | larl \ruse,555f |
86 | ex 0,0(\ruse) | 97 | ex 0,0(\ruse) |
87 | j . | 98 | j . |
99 | .endif | ||
88 | #endif | 100 | #endif |
89 | 555: br \reg | 101 | 555: br \reg |
90 | .endm | 102 | .endm |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index eb2a5c0443cd..11aea745a2a6 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -181,6 +181,7 @@ int main(void) | |||
181 | OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags); | 181 | OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags); |
182 | OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count); | 182 | OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count); |
183 | OFFSET(__LC_GMAP, lowcore, gmap); | 183 | OFFSET(__LC_GMAP, lowcore, gmap); |
184 | OFFSET(__LC_BR_R1, lowcore, br_r1_trampoline); | ||
184 | /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ | 185 | /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ |
185 | OFFSET(__LC_DUMP_REIPL, lowcore, ipib); | 186 | OFFSET(__LC_DUMP_REIPL, lowcore, ipib); |
186 | /* hardware defined lowcore locations 0x1000 - 0x18ff */ | 187 | /* hardware defined lowcore locations 0x1000 - 0x18ff */ |
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 82df7d80fab2..27110f3294ed 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S | |||
@@ -9,13 +9,17 @@ | |||
9 | #include <linux/linkage.h> | 9 | #include <linux/linkage.h> |
10 | #include <asm/asm-offsets.h> | 10 | #include <asm/asm-offsets.h> |
11 | #include <asm/ftrace.h> | 11 | #include <asm/ftrace.h> |
12 | #include <asm/nospec-insn.h> | ||
12 | #include <asm/ptrace.h> | 13 | #include <asm/ptrace.h> |
13 | #include <asm/export.h> | 14 | #include <asm/export.h> |
14 | 15 | ||
16 | GEN_BR_THUNK %r1 | ||
17 | GEN_BR_THUNK %r14 | ||
18 | |||
15 | .section .kprobes.text, "ax" | 19 | .section .kprobes.text, "ax" |
16 | 20 | ||
17 | ENTRY(ftrace_stub) | 21 | ENTRY(ftrace_stub) |
18 | br %r14 | 22 | BR_EX %r14 |
19 | 23 | ||
20 | #define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE) | 24 | #define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE) |
21 | #define STACK_PTREGS (STACK_FRAME_OVERHEAD) | 25 | #define STACK_PTREGS (STACK_FRAME_OVERHEAD) |
@@ -23,7 +27,7 @@ ENTRY(ftrace_stub) | |||
23 | #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW) | 27 | #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW) |
24 | 28 | ||
25 | ENTRY(_mcount) | 29 | ENTRY(_mcount) |
26 | br %r14 | 30 | BR_EX %r14 |
27 | 31 | ||
28 | EXPORT_SYMBOL(_mcount) | 32 | EXPORT_SYMBOL(_mcount) |
29 | 33 | ||
@@ -53,7 +57,7 @@ ENTRY(ftrace_caller) | |||
53 | #endif | 57 | #endif |
54 | lgr %r3,%r14 | 58 | lgr %r3,%r14 |
55 | la %r5,STACK_PTREGS(%r15) | 59 | la %r5,STACK_PTREGS(%r15) |
56 | basr %r14,%r1 | 60 | BASR_EX %r14,%r1 |
57 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 61 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
58 | # The j instruction gets runtime patched to a nop instruction. | 62 | # The j instruction gets runtime patched to a nop instruction. |
59 | # See ftrace_enable_ftrace_graph_caller. | 63 | # See ftrace_enable_ftrace_graph_caller. |
@@ -68,7 +72,7 @@ ftrace_graph_caller_end: | |||
68 | #endif | 72 | #endif |
69 | lg %r1,(STACK_PTREGS_PSW+8)(%r15) | 73 | lg %r1,(STACK_PTREGS_PSW+8)(%r15) |
70 | lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15) | 74 | lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15) |
71 | br %r1 | 75 | BR_EX %r1 |
72 | 76 | ||
73 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 77 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
74 | 78 | ||
@@ -81,6 +85,6 @@ ENTRY(return_to_handler) | |||
81 | aghi %r15,STACK_FRAME_OVERHEAD | 85 | aghi %r15,STACK_FRAME_OVERHEAD |
82 | lgr %r14,%r2 | 86 | lgr %r14,%r2 |
83 | lmg %r2,%r5,32(%r15) | 87 | lmg %r2,%r5,32(%r15) |
84 | br %r14 | 88 | BR_EX %r14 |
85 | 89 | ||
86 | #endif | 90 | #endif |