diff options
| author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-04-24 09:32:08 -0400 |
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-05-07 15:12:42 -0400 |
| commit | 6deaa3bbca804b2a3627fd685f75de64da7be535 (patch) | |
| tree | a03bcb97809a6eba61a593e24858065220196065 | |
| parent | 9f18fff63cfd6f559daa1eaae60640372c65f84b (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.h | 57 | ||||
| -rw-r--r-- | arch/s390/kernel/nospec-branch.c | 25 |
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 | |||
| 101 | 555: br \reg | 126 | 555: 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 | ||
| 138 | 556: 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 |
| 111 | 557: __DECODE_RR __THUNK_BR,\reg,\ruse | 154 | 557: __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 | ||
| 161 | 558: __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 |
| 118 | 559: __DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse | 168 | 559: __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 | ||
