aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2018-04-24 09:32:08 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2018-05-07 15:12:42 -0400
commit6deaa3bbca804b2a3627fd685f75de64da7be535 (patch)
treea03bcb97809a6eba61a593e24858065220196065
parent9f18fff63cfd6f559daa1eaae60640372c65f84b (diff)
s390: extend expoline to BC instructions
The BPF JIT uses a 'b <disp>(%r<x>)' instruction in the definition of the sk_load_word and sk_load_half functions. Add support for branch-on-condition instructions contained in the thunk code of an expoline. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/nospec-insn.h57
-rw-r--r--arch/s390/kernel/nospec-branch.c25
2 files changed, 77 insertions, 5 deletions
diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h
index 7d7640e1cf90..a01f81186e86 100644
--- a/arch/s390/include/asm/nospec-insn.h
+++ b/arch/s390/include/asm/nospec-insn.h
@@ -35,10 +35,18 @@ _LC_BR_R1 = __LC_BR_R1
35 __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1 35 __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1
36 .endm 36 .endm
37 37
38 .macro __THUNK_PROLOG_BC d0,r1,r2
39 __THUNK_PROLOG_NAME __s390x_indirect_branch_\d0\()_\r2\()use_\r1
40 .endm
41
38 .macro __THUNK_BR r1,r2 42 .macro __THUNK_BR r1,r2
39 jg __s390x_indirect_jump_r\r2\()use_r\r1 43 jg __s390x_indirect_jump_r\r2\()use_r\r1
40 .endm 44 .endm
41 45
46 .macro __THUNK_BC d0,r1,r2
47 jg __s390x_indirect_branch_\d0\()_\r2\()use_\r1
48 .endm
49
42 .macro __THUNK_BRASL r1,r2,r3 50 .macro __THUNK_BRASL r1,r2,r3
43 brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2 51 brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2
44 .endm 52 .endm
@@ -81,6 +89,23 @@ _LC_BR_R1 = __LC_BR_R1
81 .endif 89 .endif
82 .endm 90 .endm
83 91
92 .macro __DECODE_DRR expand,disp,reg,ruse
93 .set __decode_fail,1
94 .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
95 .ifc \reg,%r\r1
96 .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
97 .ifc \ruse,%r\r2
98 \expand \disp,\r1,\r2
99 .set __decode_fail,0
100 .endif
101 .endr
102 .endif
103 .endr
104 .if __decode_fail == 1
105 .error "__DECODE_DRR failed"
106 .endif
107 .endm
108
84 .macro __THUNK_EX_BR reg,ruse 109 .macro __THUNK_EX_BR reg,ruse
85 # Be very careful when adding instructions to this macro! 110 # Be very careful when adding instructions to this macro!
86 # The ALTERNATIVE replacement code has a .+10 which targets 111 # The ALTERNATIVE replacement code has a .+10 which targets
@@ -101,12 +126,30 @@ _LC_BR_R1 = __LC_BR_R1
101555: br \reg 126555: br \reg
102 .endm 127 .endm
103 128
129 .macro __THUNK_EX_BC disp,reg,ruse
130#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
131 exrl 0,556f
132 j .
133#else
134 larl \ruse,556f
135 ex 0,0(\ruse)
136 j .
137#endif
138556: b \disp(\reg)
139 .endm
140
104 .macro GEN_BR_THUNK reg,ruse=%r1 141 .macro GEN_BR_THUNK reg,ruse=%r1
105 __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse 142 __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse
106 __THUNK_EX_BR \reg,\ruse 143 __THUNK_EX_BR \reg,\ruse
107 __THUNK_EPILOG 144 __THUNK_EPILOG
108 .endm 145 .endm
109 146
147 .macro GEN_B_THUNK disp,reg,ruse=%r1
148 __DECODE_DRR __THUNK_PROLOG_BC,\disp,\reg,\ruse
149 __THUNK_EX_BC \disp,\reg,\ruse
150 __THUNK_EPILOG
151 .endm
152
110 .macro BR_EX reg,ruse=%r1 153 .macro BR_EX reg,ruse=%r1
111557: __DECODE_RR __THUNK_BR,\reg,\ruse 154557: __DECODE_RR __THUNK_BR,\reg,\ruse
112 .pushsection .s390_indirect_branches,"a",@progbits 155 .pushsection .s390_indirect_branches,"a",@progbits
@@ -114,6 +157,13 @@ _LC_BR_R1 = __LC_BR_R1
114 .popsection 157 .popsection
115 .endm 158 .endm
116 159
160 .macro B_EX disp,reg,ruse=%r1
161558: __DECODE_DRR __THUNK_BC,\disp,\reg,\ruse
162 .pushsection .s390_indirect_branches,"a",@progbits
163 .long 558b-.
164 .popsection
165 .endm
166
117 .macro BASR_EX rsave,rtarget,ruse=%r1 167 .macro BASR_EX rsave,rtarget,ruse=%r1
118559: __DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse 168559: __DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse
119 .pushsection .s390_indirect_branches,"a",@progbits 169 .pushsection .s390_indirect_branches,"a",@progbits
@@ -125,10 +175,17 @@ _LC_BR_R1 = __LC_BR_R1
125 .macro GEN_BR_THUNK reg,ruse=%r1 175 .macro GEN_BR_THUNK reg,ruse=%r1
126 .endm 176 .endm
127 177
178 .macro GEN_B_THUNK disp,reg,ruse=%r1
179 .endm
180
128 .macro BR_EX reg,ruse=%r1 181 .macro BR_EX reg,ruse=%r1
129 br \reg 182 br \reg
130 .endm 183 .endm
131 184
185 .macro B_EX disp,reg,ruse=%r1
186 b \disp(\reg)
187 .endm
188
132 .macro BASR_EX rsave,rtarget,ruse=%r1 189 .macro BASR_EX rsave,rtarget,ruse=%r1
133 basr \rsave,\rtarget 190 basr \rsave,\rtarget
134 .endm 191 .endm
diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c
index 834cf29f2599..8ad6a7128b3a 100644
--- a/arch/s390/kernel/nospec-branch.c
+++ b/arch/s390/kernel/nospec-branch.c
@@ -93,7 +93,6 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end)
93 s32 *epo; 93 s32 *epo;
94 94
95 /* Second part of the instruction replace is always a nop */ 95 /* Second part of the instruction replace is always a nop */
96 memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4);
97 for (epo = start; epo < end; epo++) { 96 for (epo = start; epo < end; epo++) {
98 instr = (u8 *) epo + *epo; 97 instr = (u8 *) epo + *epo;
99 if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04) 98 if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
@@ -114,18 +113,34 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end)
114 br = thunk + (*(int *)(thunk + 2)) * 2; 113 br = thunk + (*(int *)(thunk + 2)) * 2;
115 else 114 else
116 continue; 115 continue;
117 if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0) 116 /* Check for unconditional branch 0x07f? or 0x47f???? */
117 if ((br[0] & 0xbf) != 0x07 || (br[1] & 0xf0) != 0xf0)
118 continue; 118 continue;
119
120 memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x07, 0x00 }, 4);
119 switch (type) { 121 switch (type) {
120 case BRCL_EXPOLINE: 122 case BRCL_EXPOLINE:
121 /* brcl to thunk, replace with br + nop */
122 insnbuf[0] = br[0]; 123 insnbuf[0] = br[0];
123 insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); 124 insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
125 if (br[0] == 0x47) {
126 /* brcl to b, replace with bc + nopr */
127 insnbuf[2] = br[2];
128 insnbuf[3] = br[3];
129 } else {
130 /* brcl to br, replace with bcr + nop */
131 }
124 break; 132 break;
125 case BRASL_EXPOLINE: 133 case BRASL_EXPOLINE:
126 /* brasl to thunk, replace with basr + nop */
127 insnbuf[0] = 0x0d;
128 insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); 134 insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
135 if (br[0] == 0x47) {
136 /* brasl to b, replace with bas + nopr */
137 insnbuf[0] = 0x4d;
138 insnbuf[2] = br[2];
139 insnbuf[3] = br[3];
140 } else {
141 /* brasl to br, replace with basr + nop */
142 insnbuf[0] = 0x0d;
143 }
129 break; 144 break;
130 } 145 }
131 146