26
26
#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
27
27
#define TCALL_CNT (MAX_BPF_JIT_REG + 2)
28
28
#define TMP_REG_3 (MAX_BPF_JIT_REG + 3)
29
+ #define FP_BOTTOM (MAX_BPF_JIT_REG + 4)
29
30
30
31
#define check_imm (bits , imm ) do { \
31
32
if ((((imm) > 0) && ((imm) >> (bits))) || \
@@ -63,6 +64,7 @@ static const int bpf2a64[] = {
63
64
[TCALL_CNT ] = A64_R (26 ),
64
65
/* temporary register for blinding constants */
65
66
[BPF_REG_AX ] = A64_R (9 ),
67
+ [FP_BOTTOM ] = A64_R (27 ),
66
68
};
67
69
68
70
struct jit_ctx {
@@ -73,6 +75,7 @@ struct jit_ctx {
73
75
int exentry_idx ;
74
76
__le32 * image ;
75
77
u32 stack_size ;
78
+ int fpb_offset ;
76
79
};
77
80
78
81
static inline void emit (const u32 insn , struct jit_ctx * ctx )
@@ -218,7 +221,7 @@ static bool is_addsub_imm(u32 imm)
218
221
*
219
222
* offset = (u64)imm12 << scale
220
223
*/
221
- static bool is_lsi_offset (s16 offset , int scale )
224
+ static bool is_lsi_offset (int offset , int scale )
222
225
{
223
226
if (offset < 0 )
224
227
return false;
@@ -234,9 +237,9 @@ static bool is_lsi_offset(s16 offset, int scale)
234
237
235
238
/* Tail call offset to jump into */
236
239
#if IS_ENABLED (CONFIG_ARM64_BTI_KERNEL )
237
- #define PROLOGUE_OFFSET 8
240
+ #define PROLOGUE_OFFSET 10
238
241
#else
239
- #define PROLOGUE_OFFSET 7
242
+ #define PROLOGUE_OFFSET 9
240
243
#endif
241
244
242
245
static int build_prologue (struct jit_ctx * ctx , bool ebpf_from_cbpf )
@@ -248,6 +251,7 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
248
251
const u8 r9 = bpf2a64 [BPF_REG_9 ];
249
252
const u8 fp = bpf2a64 [BPF_REG_FP ];
250
253
const u8 tcc = bpf2a64 [TCALL_CNT ];
254
+ const u8 fpb = bpf2a64 [FP_BOTTOM ];
251
255
const int idx0 = ctx -> idx ;
252
256
int cur_offset ;
253
257
@@ -286,9 +290,11 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
286
290
emit (A64_PUSH (r6 , r7 , A64_SP ), ctx );
287
291
emit (A64_PUSH (r8 , r9 , A64_SP ), ctx );
288
292
emit (A64_PUSH (fp , tcc , A64_SP ), ctx );
293
+ emit (A64_PUSH (fpb , A64_R (28 ), A64_SP ), ctx );
289
294
290
295
/* Set up BPF prog stack base register */
291
296
emit (A64_MOV (1 , fp , A64_SP ), ctx );
297
+ emit (A64_SUB_I (1 , fpb , fp , ctx -> fpb_offset ), ctx );
292
298
293
299
if (!ebpf_from_cbpf ) {
294
300
/* Initialize tail_call_cnt */
@@ -553,10 +559,13 @@ static void build_epilogue(struct jit_ctx *ctx)
553
559
const u8 r8 = bpf2a64 [BPF_REG_8 ];
554
560
const u8 r9 = bpf2a64 [BPF_REG_9 ];
555
561
const u8 fp = bpf2a64 [BPF_REG_FP ];
562
+ const u8 fpb = bpf2a64 [FP_BOTTOM ];
556
563
557
564
/* We're done with BPF stack */
558
565
emit (A64_ADD_I (1 , A64_SP , A64_SP , ctx -> stack_size ), ctx );
559
566
567
+ /* Restore x27 and x28 */
568
+ emit (A64_POP (fpb , A64_R (28 ), A64_SP ), ctx );
560
569
/* Restore fs (x25) and x26 */
561
570
emit (A64_POP (fp , A64_R (26 ), A64_SP ), ctx );
562
571
@@ -650,6 +659,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
650
659
const u8 src = bpf2a64 [insn -> src_reg ];
651
660
const u8 tmp = bpf2a64 [TMP_REG_1 ];
652
661
const u8 tmp2 = bpf2a64 [TMP_REG_2 ];
662
+ const u8 fp = bpf2a64 [BPF_REG_FP ];
663
+ const u8 fpb = bpf2a64 [FP_BOTTOM ];
653
664
const s16 off = insn -> off ;
654
665
const s32 imm = insn -> imm ;
655
666
const int i = insn - ctx -> prog -> insnsi ;
@@ -658,6 +669,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
658
669
u8 jmp_cond ;
659
670
s32 jmp_offset ;
660
671
u32 a64_insn ;
672
+ u8 src_adj ;
673
+ u8 dst_adj ;
674
+ int off_adj ;
661
675
int ret ;
662
676
663
677
switch (code ) {
@@ -1012,34 +1026,41 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1012
1026
case BPF_LDX | BPF_PROBE_MEM | BPF_W :
1013
1027
case BPF_LDX | BPF_PROBE_MEM | BPF_H :
1014
1028
case BPF_LDX | BPF_PROBE_MEM | BPF_B :
1029
+ if (ctx -> fpb_offset > 0 && src == fp ) {
1030
+ src_adj = fpb ;
1031
+ off_adj = off + ctx -> fpb_offset ;
1032
+ } else {
1033
+ src_adj = src ;
1034
+ off_adj = off ;
1035
+ }
1015
1036
switch (BPF_SIZE (code )) {
1016
1037
case BPF_W :
1017
- if (is_lsi_offset (off , 2 )) {
1018
- emit (A64_LDR32I (dst , src , off ), ctx );
1038
+ if (is_lsi_offset (off_adj , 2 )) {
1039
+ emit (A64_LDR32I (dst , src_adj , off_adj ), ctx );
1019
1040
} else {
1020
1041
emit_a64_mov_i (1 , tmp , off , ctx );
1021
1042
emit (A64_LDR32 (dst , src , tmp ), ctx );
1022
1043
}
1023
1044
break ;
1024
1045
case BPF_H :
1025
- if (is_lsi_offset (off , 1 )) {
1026
- emit (A64_LDRHI (dst , src , off ), ctx );
1046
+ if (is_lsi_offset (off_adj , 1 )) {
1047
+ emit (A64_LDRHI (dst , src_adj , off_adj ), ctx );
1027
1048
} else {
1028
1049
emit_a64_mov_i (1 , tmp , off , ctx );
1029
1050
emit (A64_LDRH (dst , src , tmp ), ctx );
1030
1051
}
1031
1052
break ;
1032
1053
case BPF_B :
1033
- if (is_lsi_offset (off , 0 )) {
1034
- emit (A64_LDRBI (dst , src , off ), ctx );
1054
+ if (is_lsi_offset (off_adj , 0 )) {
1055
+ emit (A64_LDRBI (dst , src_adj , off_adj ), ctx );
1035
1056
} else {
1036
1057
emit_a64_mov_i (1 , tmp , off , ctx );
1037
1058
emit (A64_LDRB (dst , src , tmp ), ctx );
1038
1059
}
1039
1060
break ;
1040
1061
case BPF_DW :
1041
- if (is_lsi_offset (off , 3 )) {
1042
- emit (A64_LDR64I (dst , src , off ), ctx );
1062
+ if (is_lsi_offset (off_adj , 3 )) {
1063
+ emit (A64_LDR64I (dst , src_adj , off_adj ), ctx );
1043
1064
} else {
1044
1065
emit_a64_mov_i (1 , tmp , off , ctx );
1045
1066
emit (A64_LDR64 (dst , src , tmp ), ctx );
@@ -1070,36 +1091,43 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1070
1091
case BPF_ST | BPF_MEM | BPF_H :
1071
1092
case BPF_ST | BPF_MEM | BPF_B :
1072
1093
case BPF_ST | BPF_MEM | BPF_DW :
1094
+ if (ctx -> fpb_offset > 0 && dst == fp ) {
1095
+ dst_adj = fpb ;
1096
+ off_adj = off + ctx -> fpb_offset ;
1097
+ } else {
1098
+ dst_adj = dst ;
1099
+ off_adj = off ;
1100
+ }
1073
1101
/* Load imm to a register then store it */
1074
1102
emit_a64_mov_i (1 , tmp , imm , ctx );
1075
1103
switch (BPF_SIZE (code )) {
1076
1104
case BPF_W :
1077
- if (is_lsi_offset (off , 2 )) {
1078
- emit (A64_STR32I (tmp , dst , off ), ctx );
1105
+ if (is_lsi_offset (off_adj , 2 )) {
1106
+ emit (A64_STR32I (tmp , dst_adj , off_adj ), ctx );
1079
1107
} else {
1080
1108
emit_a64_mov_i (1 , tmp2 , off , ctx );
1081
1109
emit (A64_STR32 (tmp , dst , tmp2 ), ctx );
1082
1110
}
1083
1111
break ;
1084
1112
case BPF_H :
1085
- if (is_lsi_offset (off , 1 )) {
1086
- emit (A64_STRHI (tmp , dst , off ), ctx );
1113
+ if (is_lsi_offset (off_adj , 1 )) {
1114
+ emit (A64_STRHI (tmp , dst_adj , off_adj ), ctx );
1087
1115
} else {
1088
1116
emit_a64_mov_i (1 , tmp2 , off , ctx );
1089
1117
emit (A64_STRH (tmp , dst , tmp2 ), ctx );
1090
1118
}
1091
1119
break ;
1092
1120
case BPF_B :
1093
- if (is_lsi_offset (off , 0 )) {
1094
- emit (A64_STRBI (tmp , dst , off ), ctx );
1121
+ if (is_lsi_offset (off_adj , 0 )) {
1122
+ emit (A64_STRBI (tmp , dst_adj , off_adj ), ctx );
1095
1123
} else {
1096
1124
emit_a64_mov_i (1 , tmp2 , off , ctx );
1097
1125
emit (A64_STRB (tmp , dst , tmp2 ), ctx );
1098
1126
}
1099
1127
break ;
1100
1128
case BPF_DW :
1101
- if (is_lsi_offset (off , 3 )) {
1102
- emit (A64_STR64I (tmp , dst , off ), ctx );
1129
+ if (is_lsi_offset (off_adj , 3 )) {
1130
+ emit (A64_STR64I (tmp , dst_adj , off_adj ), ctx );
1103
1131
} else {
1104
1132
emit_a64_mov_i (1 , tmp2 , off , ctx );
1105
1133
emit (A64_STR64 (tmp , dst , tmp2 ), ctx );
@@ -1113,34 +1141,41 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1113
1141
case BPF_STX | BPF_MEM | BPF_H :
1114
1142
case BPF_STX | BPF_MEM | BPF_B :
1115
1143
case BPF_STX | BPF_MEM | BPF_DW :
1144
+ if (ctx -> fpb_offset > 0 && dst == fp ) {
1145
+ dst_adj = fpb ;
1146
+ off_adj = off + ctx -> fpb_offset ;
1147
+ } else {
1148
+ dst_adj = dst ;
1149
+ off_adj = off ;
1150
+ }
1116
1151
switch (BPF_SIZE (code )) {
1117
1152
case BPF_W :
1118
- if (is_lsi_offset (off , 2 )) {
1119
- emit (A64_STR32I (src , dst , off ), ctx );
1153
+ if (is_lsi_offset (off_adj , 2 )) {
1154
+ emit (A64_STR32I (src , dst_adj , off_adj ), ctx );
1120
1155
} else {
1121
1156
emit_a64_mov_i (1 , tmp , off , ctx );
1122
1157
emit (A64_STR32 (src , dst , tmp ), ctx );
1123
1158
}
1124
1159
break ;
1125
1160
case BPF_H :
1126
- if (is_lsi_offset (off , 1 )) {
1127
- emit (A64_STRHI (src , dst , off ), ctx );
1161
+ if (is_lsi_offset (off_adj , 1 )) {
1162
+ emit (A64_STRHI (src , dst_adj , off_adj ), ctx );
1128
1163
} else {
1129
1164
emit_a64_mov_i (1 , tmp , off , ctx );
1130
1165
emit (A64_STRH (src , dst , tmp ), ctx );
1131
1166
}
1132
1167
break ;
1133
1168
case BPF_B :
1134
- if (is_lsi_offset (off , 0 )) {
1135
- emit (A64_STRBI (src , dst , off ), ctx );
1169
+ if (is_lsi_offset (off_adj , 0 )) {
1170
+ emit (A64_STRBI (src , dst_adj , off_adj ), ctx );
1136
1171
} else {
1137
1172
emit_a64_mov_i (1 , tmp , off , ctx );
1138
1173
emit (A64_STRB (src , dst , tmp ), ctx );
1139
1174
}
1140
1175
break ;
1141
1176
case BPF_DW :
1142
- if (is_lsi_offset (off , 3 )) {
1143
- emit (A64_STR64I (src , dst , off ), ctx );
1177
+ if (is_lsi_offset (off_adj , 3 )) {
1178
+ emit (A64_STR64I (src , dst_adj , off_adj ), ctx );
1144
1179
} else {
1145
1180
emit_a64_mov_i (1 , tmp , off , ctx );
1146
1181
emit (A64_STR64 (src , dst , tmp ), ctx );
@@ -1167,6 +1202,70 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1167
1202
return 0 ;
1168
1203
}
1169
1204
1205
+ /*
1206
+ * Return 0 if FP may change at runtime, otherwise find the minimum negative
1207
+ * offset to FP and converts it to positive number.
1208
+ */
1209
+ static int find_fpb_offset (struct bpf_prog * prog )
1210
+ {
1211
+ int i ;
1212
+ int offset = 0 ;
1213
+
1214
+ for (i = 0 ; i < prog -> len ; i ++ ) {
1215
+ const struct bpf_insn * insn = & prog -> insnsi [i ];
1216
+ const u8 class = BPF_CLASS (insn -> code );
1217
+ const u8 mode = BPF_MODE (insn -> code );
1218
+ const u8 src = insn -> src_reg ;
1219
+ const u8 dst = insn -> dst_reg ;
1220
+ const s32 imm = insn -> imm ;
1221
+ const s16 off = insn -> off ;
1222
+
1223
+ switch (class ) {
1224
+ case BPF_STX :
1225
+ case BPF_ST :
1226
+ /* fp holds atomic operation result */
1227
+ if (class == BPF_STX && mode == BPF_ATOMIC &&
1228
+ ((imm == BPF_XCHG ||
1229
+ imm == (BPF_FETCH | BPF_ADD ) ||
1230
+ imm == (BPF_FETCH | BPF_AND ) ||
1231
+ imm == (BPF_FETCH | BPF_XOR ) ||
1232
+ imm == (BPF_FETCH | BPF_OR )) &&
1233
+ src == BPF_REG_FP ))
1234
+ return 0 ;
1235
+
1236
+ if (mode == BPF_MEM && dst == BPF_REG_FP &&
1237
+ off < offset )
1238
+ offset = insn -> off ;
1239
+ break ;
1240
+
1241
+ case BPF_JMP32 :
1242
+ case BPF_JMP :
1243
+ break ;
1244
+
1245
+ case BPF_LDX :
1246
+ case BPF_LD :
1247
+ /* fp holds load result */
1248
+ if (dst == BPF_REG_FP )
1249
+ return 0 ;
1250
+
1251
+ if (class == BPF_LDX && mode == BPF_MEM &&
1252
+ src == BPF_REG_FP && off < offset )
1253
+ offset = off ;
1254
+ break ;
1255
+
1256
+ case BPF_ALU :
1257
+ case BPF_ALU64 :
1258
+ default :
1259
+ /* fp holds ALU result */
1260
+ if (dst == BPF_REG_FP )
1261
+ return 0 ;
1262
+ }
1263
+ }
1264
+
1265
+ /* safely be converted to a positive 'int', since insn->off is 's16' */
1266
+ return - offset ;
1267
+ }
1268
+
1170
1269
static int build_body (struct jit_ctx * ctx , bool extra_pass )
1171
1270
{
1172
1271
const struct bpf_prog * prog = ctx -> prog ;
@@ -1288,6 +1387,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
1288
1387
goto out_off ;
1289
1388
}
1290
1389
1390
+ ctx .fpb_offset = find_fpb_offset (prog );
1391
+
1291
1392
/*
1292
1393
* 1. Initial fake pass to compute ctx->idx and ctx->offset.
1293
1394
*
0 commit comments