@@ -49,6 +49,7 @@ struct bpf_jit {
49
49
int r1_thunk_ip ; /* Address of expoline thunk for 'br %r1' */
50
50
int r14_thunk_ip ; /* Address of expoline thunk for 'br %r14' */
51
51
int tail_call_start ; /* Tail call start offset */
52
+ int excnt ; /* Number of exception table entries */
52
53
int labels [1 ]; /* Labels for local jumps */
53
54
};
54
55
@@ -588,6 +589,84 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
588
589
}
589
590
}
590
591
592
+ static int get_probe_mem_regno (const u8 * insn )
593
+ {
594
+ /*
595
+ * insn must point to llgc, llgh, llgf or lg, which have destination
596
+ * register at the same position.
597
+ */
598
+ if (insn [0 ] != 0xe3 ) /* common llgc, llgh, llgf and lg prefix */
599
+ return -1 ;
600
+ if (insn [5 ] != 0x90 && /* llgc */
601
+ insn [5 ] != 0x91 && /* llgh */
602
+ insn [5 ] != 0x16 && /* llgf */
603
+ insn [5 ] != 0x04 ) /* lg */
604
+ return -1 ;
605
+ return insn [1 ] >> 4 ;
606
+ }
607
+
608
+ static bool ex_handler_bpf (const struct exception_table_entry * x ,
609
+ struct pt_regs * regs )
610
+ {
611
+ int regno ;
612
+ u8 * insn ;
613
+
614
+ regs -> psw .addr = extable_fixup (x );
615
+ insn = (u8 * )__rewind_psw (regs -> psw , regs -> int_code >> 16 );
616
+ regno = get_probe_mem_regno (insn );
617
+ if (WARN_ON_ONCE (regno < 0 ))
618
+ /* JIT bug - unexpected instruction. */
619
+ return false;
620
+ regs -> gprs [regno ] = 0 ;
621
+ return true;
622
+ }
623
+
624
+ static int bpf_jit_probe_mem (struct bpf_jit * jit , struct bpf_prog * fp ,
625
+ int probe_prg , int nop_prg )
626
+ {
627
+ struct exception_table_entry * ex ;
628
+ s64 delta ;
629
+ u8 * insn ;
630
+ int prg ;
631
+ int i ;
632
+
633
+ if (!fp -> aux -> extable )
634
+ /* Do nothing during early JIT passes. */
635
+ return 0 ;
636
+ insn = jit -> prg_buf + probe_prg ;
637
+ if (WARN_ON_ONCE (get_probe_mem_regno (insn ) < 0 ))
638
+ /* JIT bug - unexpected probe instruction. */
639
+ return -1 ;
640
+ if (WARN_ON_ONCE (probe_prg + insn_length (* insn ) != nop_prg ))
641
+ /* JIT bug - gap between probe and nop instructions. */
642
+ return -1 ;
643
+ for (i = 0 ; i < 2 ; i ++ ) {
644
+ if (WARN_ON_ONCE (jit -> excnt >= fp -> aux -> num_exentries ))
645
+ /* Verifier bug - not enough entries. */
646
+ return -1 ;
647
+ ex = & fp -> aux -> extable [jit -> excnt ];
648
+ /* Add extable entries for probe and nop instructions. */
649
+ prg = i == 0 ? probe_prg : nop_prg ;
650
+ delta = jit -> prg_buf + prg - (u8 * )& ex -> insn ;
651
+ if (WARN_ON_ONCE (delta < INT_MIN || delta > INT_MAX ))
652
+ /* JIT bug - code and extable must be close. */
653
+ return -1 ;
654
+ ex -> insn = delta ;
655
+ /*
656
+ * Always land on the nop. Note that extable infrastructure
657
+ * ignores fixup field, it is handled by ex_handler_bpf().
658
+ */
659
+ delta = jit -> prg_buf + nop_prg - (u8 * )& ex -> fixup ;
660
+ if (WARN_ON_ONCE (delta < INT_MIN || delta > INT_MAX ))
661
+ /* JIT bug - landing pad and extable must be close. */
662
+ return -1 ;
663
+ ex -> fixup = delta ;
664
+ ex -> handler = (u8 * )ex_handler_bpf - (u8 * )& ex -> handler ;
665
+ jit -> excnt ++ ;
666
+ }
667
+ return 0 ;
668
+ }
669
+
591
670
/*
592
671
* Compile one eBPF instruction into s390x code
593
672
*
@@ -604,7 +683,14 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
604
683
u32 * addrs = jit -> addrs ;
605
684
s32 imm = insn -> imm ;
606
685
s16 off = insn -> off ;
686
+ int probe_prg = -1 ;
607
687
unsigned int mask ;
688
+ int nop_prg ;
689
+ int err ;
690
+
691
+ if (BPF_CLASS (insn -> code ) == BPF_LDX &&
692
+ BPF_MODE (insn -> code ) == BPF_PROBE_MEM )
693
+ probe_prg = jit -> prg ;
608
694
609
695
switch (insn -> code ) {
610
696
/*
@@ -1119,27 +1205,31 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
1119
1205
* BPF_LDX
1120
1206
*/
1121
1207
case BPF_LDX | BPF_MEM | BPF_B : /* dst = *(u8 *)(ul) (src + off) */
1208
+ case BPF_LDX | BPF_PROBE_MEM | BPF_B :
1122
1209
/* llgc %dst,0(off,%src) */
1123
1210
EMIT6_DISP_LH (0xe3000000 , 0x0090 , dst_reg , src_reg , REG_0 , off );
1124
1211
jit -> seen |= SEEN_MEM ;
1125
1212
if (insn_is_zext (& insn [1 ]))
1126
1213
insn_count = 2 ;
1127
1214
break ;
1128
1215
case BPF_LDX | BPF_MEM | BPF_H : /* dst = *(u16 *)(ul) (src + off) */
1216
+ case BPF_LDX | BPF_PROBE_MEM | BPF_H :
1129
1217
/* llgh %dst,0(off,%src) */
1130
1218
EMIT6_DISP_LH (0xe3000000 , 0x0091 , dst_reg , src_reg , REG_0 , off );
1131
1219
jit -> seen |= SEEN_MEM ;
1132
1220
if (insn_is_zext (& insn [1 ]))
1133
1221
insn_count = 2 ;
1134
1222
break ;
1135
1223
case BPF_LDX | BPF_MEM | BPF_W : /* dst = *(u32 *)(ul) (src + off) */
1224
+ case BPF_LDX | BPF_PROBE_MEM | BPF_W :
1136
1225
/* llgf %dst,off(%src) */
1137
1226
jit -> seen |= SEEN_MEM ;
1138
1227
EMIT6_DISP_LH (0xe3000000 , 0x0016 , dst_reg , src_reg , REG_0 , off );
1139
1228
if (insn_is_zext (& insn [1 ]))
1140
1229
insn_count = 2 ;
1141
1230
break ;
1142
1231
case BPF_LDX | BPF_MEM | BPF_DW : /* dst = *(u64 *)(ul) (src + off) */
1232
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW :
1143
1233
/* lg %dst,0(off,%src) */
1144
1234
jit -> seen |= SEEN_MEM ;
1145
1235
EMIT6_DISP_LH (0xe3000000 , 0x0004 , dst_reg , src_reg , REG_0 , off );
@@ -1485,6 +1575,23 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
1485
1575
pr_err ("Unknown opcode %02x\n" , insn -> code );
1486
1576
return -1 ;
1487
1577
}
1578
+
1579
+ if (probe_prg != -1 ) {
1580
+ /*
1581
+ * Handlers of certain exceptions leave psw.addr pointing to
1582
+ * the instruction directly after the failing one. Therefore,
1583
+ * create two exception table entries and also add a nop in
1584
+ * case two probing instructions come directly after each
1585
+ * other.
1586
+ */
1587
+ nop_prg = jit -> prg ;
1588
+ /* bcr 0,%0 */
1589
+ _EMIT2 (0x0700 );
1590
+ err = bpf_jit_probe_mem (jit , fp , probe_prg , nop_prg );
1591
+ if (err < 0 )
1592
+ return err ;
1593
+ }
1594
+
1488
1595
return insn_count ;
1489
1596
}
1490
1597
@@ -1527,6 +1634,7 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
1527
1634
jit -> lit32 = jit -> lit32_start ;
1528
1635
jit -> lit64 = jit -> lit64_start ;
1529
1636
jit -> prg = 0 ;
1637
+ jit -> excnt = 0 ;
1530
1638
1531
1639
bpf_jit_prologue (jit , stack_depth );
1532
1640
if (bpf_set_addr (jit , 0 ) < 0 )
@@ -1551,6 +1659,12 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
1551
1659
jit -> lit64_start = ALIGN (jit -> lit64_start , 8 );
1552
1660
jit -> size = jit -> lit64_start + lit64_size ;
1553
1661
jit -> size_prg = jit -> prg ;
1662
+
1663
+ if (WARN_ON_ONCE (fp -> aux -> extable &&
1664
+ jit -> excnt != fp -> aux -> num_exentries ))
1665
+ /* Verifier bug - too many entries. */
1666
+ return -1 ;
1667
+
1554
1668
return 0 ;
1555
1669
}
1556
1670
@@ -1565,6 +1679,29 @@ struct s390_jit_data {
1565
1679
int pass ;
1566
1680
};
1567
1681
1682
+ static struct bpf_binary_header * bpf_jit_alloc (struct bpf_jit * jit ,
1683
+ struct bpf_prog * fp )
1684
+ {
1685
+ struct bpf_binary_header * header ;
1686
+ u32 extable_size ;
1687
+ u32 code_size ;
1688
+
1689
+ /* We need two entries per insn. */
1690
+ fp -> aux -> num_exentries *= 2 ;
1691
+
1692
+ code_size = roundup (jit -> size ,
1693
+ __alignof__(struct exception_table_entry ));
1694
+ extable_size = fp -> aux -> num_exentries *
1695
+ sizeof (struct exception_table_entry );
1696
+ header = bpf_jit_binary_alloc (code_size + extable_size , & jit -> prg_buf ,
1697
+ 8 , jit_fill_hole );
1698
+ if (!header )
1699
+ return NULL ;
1700
+ fp -> aux -> extable = (struct exception_table_entry * )
1701
+ (jit -> prg_buf + code_size );
1702
+ return header ;
1703
+ }
1704
+
1568
1705
/*
1569
1706
* Compile eBPF program "fp"
1570
1707
*/
@@ -1631,7 +1768,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
1631
1768
/*
1632
1769
* Final pass: Allocate and generate program
1633
1770
*/
1634
- header = bpf_jit_binary_alloc ( jit . size , & jit . prg_buf , 8 , jit_fill_hole );
1771
+ header = bpf_jit_alloc ( & jit , fp );
1635
1772
if (!header ) {
1636
1773
fp = orig_fp ;
1637
1774
goto free_addrs ;
0 commit comments