2525#include <linux/bpf.h>
2626#include <asm/cacheflush.h>
2727#include <asm/dis.h>
28+ #include <asm/facility.h>
29+ #include <asm/nospec-branch.h>
2830#include <asm/set_memory.h>
2931#include "bpf_jit.h"
3032
@@ -41,6 +43,8 @@ struct bpf_jit {
4143 int base_ip ; /* Base address for literal pool */
4244 int ret0_ip ; /* Address of return 0 */
4345 int exit_ip ; /* Address of exit */
46+ int r1_thunk_ip ; /* Address of expoline thunk for 'br %r1' */
47+ int r14_thunk_ip ; /* Address of expoline thunk for 'br %r14' */
4448 int tail_call_start ; /* Tail call start offset */
4549 int labels [1 ]; /* Labels for local jumps */
4650};
@@ -250,6 +254,19 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
250254 REG_SET_SEEN(b2); \
251255})
252256
257+ #define EMIT6_PCREL_RILB (op , b , target ) \
258+ ({ \
259+ int rel = (target - jit->prg) / 2; \
260+ _EMIT6(op | reg_high(b) << 16 | rel >> 16, rel & 0xffff); \
261+ REG_SET_SEEN(b); \
262+ })
263+
264+ #define EMIT6_PCREL_RIL (op , target ) \
265+ ({ \
266+ int rel = (target - jit->prg) / 2; \
267+ _EMIT6(op | rel >> 16, rel & 0xffff); \
268+ })
269+
253270#define _EMIT6_IMM (op , imm ) \
254271({ \
255272 unsigned int __imm = (imm); \
@@ -469,8 +486,45 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
469486 EMIT4 (0xb9040000 , REG_2 , BPF_REG_0 );
470487 /* Restore registers */
471488 save_restore_regs (jit , REGS_RESTORE , stack_depth );
489+ if (IS_ENABLED (CC_USING_EXPOLINE ) && !nospec_disable ) {
490+ jit -> r14_thunk_ip = jit -> prg ;
491+ /* Generate __s390_indirect_jump_r14 thunk */
492+ if (test_facility (35 )) {
493+ /* exrl %r0,.+10 */
494+ EMIT6_PCREL_RIL (0xc6000000 , jit -> prg + 10 );
495+ } else {
496+ /* larl %r1,.+14 */
497+ EMIT6_PCREL_RILB (0xc0000000 , REG_1 , jit -> prg + 14 );
498+ /* ex 0,0(%r1) */
499+ EMIT4_DISP (0x44000000 , REG_0 , REG_1 , 0 );
500+ }
501+ /* j . */
502+ EMIT4_PCREL (0xa7f40000 , 0 );
503+ }
472504 /* br %r14 */
473505 _EMIT2 (0x07fe );
506+
507+ if (IS_ENABLED (CC_USING_EXPOLINE ) && !nospec_disable &&
508+ (jit -> seen & SEEN_FUNC )) {
509+ jit -> r1_thunk_ip = jit -> prg ;
510+ /* Generate __s390_indirect_jump_r1 thunk */
511+ if (test_facility (35 )) {
512+ /* exrl %r0,.+10 */
513+ EMIT6_PCREL_RIL (0xc6000000 , jit -> prg + 10 );
514+ /* j . */
515+ EMIT4_PCREL (0xa7f40000 , 0 );
516+ /* br %r1 */
517+ _EMIT2 (0x07f1 );
518+ } else {
519+ /* larl %r1,.+14 */
520+ EMIT6_PCREL_RILB (0xc0000000 , REG_1 , jit -> prg + 14 );
521+ /* ex 0,S390_lowcore.br_r1_tampoline */
522+ EMIT4_DISP (0x44000000 , REG_0 , REG_0 ,
523+ offsetof(struct lowcore , br_r1_trampoline ));
524+ /* j . */
525+ EMIT4_PCREL (0xa7f40000 , 0 );
526+ }
527+ }
474528}
475529
476530/*
@@ -966,8 +1020,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
9661020 /* lg %w1,<d(imm)>(%l) */
9671021 EMIT6_DISP_LH (0xe3000000 , 0x0004 , REG_W1 , REG_0 , REG_L ,
9681022 EMIT_CONST_U64 (func ));
969- /* basr %r14,%w1 */
970- EMIT2 (0x0d00 , REG_14 , REG_W1 );
1023+ if (IS_ENABLED (CC_USING_EXPOLINE ) && !nospec_disable ) {
1024+ /* brasl %r14,__s390_indirect_jump_r1 */
1025+ EMIT6_PCREL_RILB (0xc0050000 , REG_14 , jit -> r1_thunk_ip );
1026+ } else {
1027+ /* basr %r14,%w1 */
1028+ EMIT2 (0x0d00 , REG_14 , REG_W1 );
1029+ }
9711030 /* lgr %b0,%r2: load return value into %b0 */
9721031 EMIT4 (0xb9040000 , BPF_REG_0 , REG_2 );
9731032 if ((jit -> seen & SEEN_SKB ) &&
0 commit comments