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 9
238
241
#else
239
- #define PROLOGUE_OFFSET 7
242
+ #define PROLOGUE_OFFSET 8
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,6 +290,7 @@ 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 );
@@ -306,6 +311,8 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
306
311
emit (A64_BTI_J , ctx );
307
312
}
308
313
314
+ emit (A64_SUB_I (1 , fpb , fp , ctx -> fpb_offset ), ctx );
315
+
309
316
/* Stack must be multiples of 16B */
310
317
ctx -> stack_size = round_up (prog -> aux -> stack_depth , 16 );
311
318
@@ -553,10 +560,13 @@ static void build_epilogue(struct jit_ctx *ctx)
553
560
const u8 r8 = bpf2a64 [BPF_REG_8 ];
554
561
const u8 r9 = bpf2a64 [BPF_REG_9 ];
555
562
const u8 fp = bpf2a64 [BPF_REG_FP ];
563
+ const u8 fpb = bpf2a64 [FP_BOTTOM ];
556
564
557
565
/* We're done with BPF stack */
558
566
emit (A64_ADD_I (1 , A64_SP , A64_SP , ctx -> stack_size ), ctx );
559
567
568
+ /* Restore x27 and x28 */
569
+ emit (A64_POP (fpb , A64_R (28 ), A64_SP ), ctx );
560
570
/* Restore fs (x25) and x26 */
561
571
emit (A64_POP (fp , A64_R (26 ), A64_SP ), ctx );
562
572
@@ -650,6 +660,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
650
660
const u8 src = bpf2a64 [insn -> src_reg ];
651
661
const u8 tmp = bpf2a64 [TMP_REG_1 ];
652
662
const u8 tmp2 = bpf2a64 [TMP_REG_2 ];
663
+ const u8 fp = bpf2a64 [BPF_REG_FP ];
664
+ const u8 fpb = bpf2a64 [FP_BOTTOM ];
653
665
const s16 off = insn -> off ;
654
666
const s32 imm = insn -> imm ;
655
667
const int i = insn - ctx -> prog -> insnsi ;
@@ -658,6 +670,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
658
670
u8 jmp_cond ;
659
671
s32 jmp_offset ;
660
672
u32 a64_insn ;
673
+ u8 src_adj ;
674
+ u8 dst_adj ;
675
+ int off_adj ;
661
676
int ret ;
662
677
663
678
switch (code ) {
@@ -1012,34 +1027,41 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1012
1027
case BPF_LDX | BPF_PROBE_MEM | BPF_W :
1013
1028
case BPF_LDX | BPF_PROBE_MEM | BPF_H :
1014
1029
case BPF_LDX | BPF_PROBE_MEM | BPF_B :
1030
+ if (ctx -> fpb_offset > 0 && src == fp ) {
1031
+ src_adj = fpb ;
1032
+ off_adj = off + ctx -> fpb_offset ;
1033
+ } else {
1034
+ src_adj = src ;
1035
+ off_adj = off ;
1036
+ }
1015
1037
switch (BPF_SIZE (code )) {
1016
1038
case BPF_W :
1017
- if (is_lsi_offset (off , 2 )) {
1018
- emit (A64_LDR32I (dst , src , off ), ctx );
1039
+ if (is_lsi_offset (off_adj , 2 )) {
1040
+ emit (A64_LDR32I (dst , src_adj , off_adj ), ctx );
1019
1041
} else {
1020
1042
emit_a64_mov_i (1 , tmp , off , ctx );
1021
1043
emit (A64_LDR32 (dst , src , tmp ), ctx );
1022
1044
}
1023
1045
break ;
1024
1046
case BPF_H :
1025
- if (is_lsi_offset (off , 1 )) {
1026
- emit (A64_LDRHI (dst , src , off ), ctx );
1047
+ if (is_lsi_offset (off_adj , 1 )) {
1048
+ emit (A64_LDRHI (dst , src_adj , off_adj ), ctx );
1027
1049
} else {
1028
1050
emit_a64_mov_i (1 , tmp , off , ctx );
1029
1051
emit (A64_LDRH (dst , src , tmp ), ctx );
1030
1052
}
1031
1053
break ;
1032
1054
case BPF_B :
1033
- if (is_lsi_offset (off , 0 )) {
1034
- emit (A64_LDRBI (dst , src , off ), ctx );
1055
+ if (is_lsi_offset (off_adj , 0 )) {
1056
+ emit (A64_LDRBI (dst , src_adj , off_adj ), ctx );
1035
1057
} else {
1036
1058
emit_a64_mov_i (1 , tmp , off , ctx );
1037
1059
emit (A64_LDRB (dst , src , tmp ), ctx );
1038
1060
}
1039
1061
break ;
1040
1062
case BPF_DW :
1041
- if (is_lsi_offset (off , 3 )) {
1042
- emit (A64_LDR64I (dst , src , off ), ctx );
1063
+ if (is_lsi_offset (off_adj , 3 )) {
1064
+ emit (A64_LDR64I (dst , src_adj , off_adj ), ctx );
1043
1065
} else {
1044
1066
emit_a64_mov_i (1 , tmp , off , ctx );
1045
1067
emit (A64_LDR64 (dst , src , tmp ), ctx );
@@ -1070,36 +1092,43 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1070
1092
case BPF_ST | BPF_MEM | BPF_H :
1071
1093
case BPF_ST | BPF_MEM | BPF_B :
1072
1094
case BPF_ST | BPF_MEM | BPF_DW :
1095
+ if (ctx -> fpb_offset > 0 && dst == fp ) {
1096
+ dst_adj = fpb ;
1097
+ off_adj = off + ctx -> fpb_offset ;
1098
+ } else {
1099
+ dst_adj = dst ;
1100
+ off_adj = off ;
1101
+ }
1073
1102
/* Load imm to a register then store it */
1074
1103
emit_a64_mov_i (1 , tmp , imm , ctx );
1075
1104
switch (BPF_SIZE (code )) {
1076
1105
case BPF_W :
1077
- if (is_lsi_offset (off , 2 )) {
1078
- emit (A64_STR32I (tmp , dst , off ), ctx );
1106
+ if (is_lsi_offset (off_adj , 2 )) {
1107
+ emit (A64_STR32I (tmp , dst_adj , off_adj ), ctx );
1079
1108
} else {
1080
1109
emit_a64_mov_i (1 , tmp2 , off , ctx );
1081
1110
emit (A64_STR32 (tmp , dst , tmp2 ), ctx );
1082
1111
}
1083
1112
break ;
1084
1113
case BPF_H :
1085
- if (is_lsi_offset (off , 1 )) {
1086
- emit (A64_STRHI (tmp , dst , off ), ctx );
1114
+ if (is_lsi_offset (off_adj , 1 )) {
1115
+ emit (A64_STRHI (tmp , dst_adj , off_adj ), ctx );
1087
1116
} else {
1088
1117
emit_a64_mov_i (1 , tmp2 , off , ctx );
1089
1118
emit (A64_STRH (tmp , dst , tmp2 ), ctx );
1090
1119
}
1091
1120
break ;
1092
1121
case BPF_B :
1093
- if (is_lsi_offset (off , 0 )) {
1094
- emit (A64_STRBI (tmp , dst , off ), ctx );
1122
+ if (is_lsi_offset (off_adj , 0 )) {
1123
+ emit (A64_STRBI (tmp , dst_adj , off_adj ), ctx );
1095
1124
} else {
1096
1125
emit_a64_mov_i (1 , tmp2 , off , ctx );
1097
1126
emit (A64_STRB (tmp , dst , tmp2 ), ctx );
1098
1127
}
1099
1128
break ;
1100
1129
case BPF_DW :
1101
- if (is_lsi_offset (off , 3 )) {
1102
- emit (A64_STR64I (tmp , dst , off ), ctx );
1130
+ if (is_lsi_offset (off_adj , 3 )) {
1131
+ emit (A64_STR64I (tmp , dst_adj , off_adj ), ctx );
1103
1132
} else {
1104
1133
emit_a64_mov_i (1 , tmp2 , off , ctx );
1105
1134
emit (A64_STR64 (tmp , dst , tmp2 ), ctx );
@@ -1113,34 +1142,41 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1113
1142
case BPF_STX | BPF_MEM | BPF_H :
1114
1143
case BPF_STX | BPF_MEM | BPF_B :
1115
1144
case BPF_STX | BPF_MEM | BPF_DW :
1145
+ if (ctx -> fpb_offset > 0 && dst == fp ) {
1146
+ dst_adj = fpb ;
1147
+ off_adj = off + ctx -> fpb_offset ;
1148
+ } else {
1149
+ dst_adj = dst ;
1150
+ off_adj = off ;
1151
+ }
1116
1152
switch (BPF_SIZE (code )) {
1117
1153
case BPF_W :
1118
- if (is_lsi_offset (off , 2 )) {
1119
- emit (A64_STR32I (src , dst , off ), ctx );
1154
+ if (is_lsi_offset (off_adj , 2 )) {
1155
+ emit (A64_STR32I (src , dst_adj , off_adj ), ctx );
1120
1156
} else {
1121
1157
emit_a64_mov_i (1 , tmp , off , ctx );
1122
1158
emit (A64_STR32 (src , dst , tmp ), ctx );
1123
1159
}
1124
1160
break ;
1125
1161
case BPF_H :
1126
- if (is_lsi_offset (off , 1 )) {
1127
- emit (A64_STRHI (src , dst , off ), ctx );
1162
+ if (is_lsi_offset (off_adj , 1 )) {
1163
+ emit (A64_STRHI (src , dst_adj , off_adj ), ctx );
1128
1164
} else {
1129
1165
emit_a64_mov_i (1 , tmp , off , ctx );
1130
1166
emit (A64_STRH (src , dst , tmp ), ctx );
1131
1167
}
1132
1168
break ;
1133
1169
case BPF_B :
1134
- if (is_lsi_offset (off , 0 )) {
1135
- emit (A64_STRBI (src , dst , off ), ctx );
1170
+ if (is_lsi_offset (off_adj , 0 )) {
1171
+ emit (A64_STRBI (src , dst_adj , off_adj ), ctx );
1136
1172
} else {
1137
1173
emit_a64_mov_i (1 , tmp , off , ctx );
1138
1174
emit (A64_STRB (src , dst , tmp ), ctx );
1139
1175
}
1140
1176
break ;
1141
1177
case BPF_DW :
1142
- if (is_lsi_offset (off , 3 )) {
1143
- emit (A64_STR64I (src , dst , off ), ctx );
1178
+ if (is_lsi_offset (off_adj , 3 )) {
1179
+ emit (A64_STR64I (src , dst_adj , off_adj ), ctx );
1144
1180
} else {
1145
1181
emit_a64_mov_i (1 , tmp , off , ctx );
1146
1182
emit (A64_STR64 (src , dst , tmp ), ctx );
@@ -1167,6 +1203,79 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1167
1203
return 0 ;
1168
1204
}
1169
1205
1206
+ /*
1207
+ * Return 0 if FP may change at runtime, otherwise find the minimum negative
1208
+ * offset to FP, converts it to positive number, and align down to 8 bytes.
1209
+ */
1210
+ static int find_fpb_offset (struct bpf_prog * prog )
1211
+ {
1212
+ int i ;
1213
+ int offset = 0 ;
1214
+
1215
+ for (i = 0 ; i < prog -> len ; i ++ ) {
1216
+ const struct bpf_insn * insn = & prog -> insnsi [i ];
1217
+ const u8 class = BPF_CLASS (insn -> code );
1218
+ const u8 mode = BPF_MODE (insn -> code );
1219
+ const u8 src = insn -> src_reg ;
1220
+ const u8 dst = insn -> dst_reg ;
1221
+ const s32 imm = insn -> imm ;
1222
+ const s16 off = insn -> off ;
1223
+
1224
+ switch (class ) {
1225
+ case BPF_STX :
1226
+ case BPF_ST :
1227
+ /* fp holds atomic operation result */
1228
+ if (class == BPF_STX && mode == BPF_ATOMIC &&
1229
+ ((imm == BPF_XCHG ||
1230
+ imm == (BPF_FETCH | BPF_ADD ) ||
1231
+ imm == (BPF_FETCH | BPF_AND ) ||
1232
+ imm == (BPF_FETCH | BPF_XOR ) ||
1233
+ imm == (BPF_FETCH | BPF_OR )) &&
1234
+ src == BPF_REG_FP ))
1235
+ return 0 ;
1236
+
1237
+ if (mode == BPF_MEM && dst == BPF_REG_FP &&
1238
+ off < offset )
1239
+ offset = insn -> off ;
1240
+ break ;
1241
+
1242
+ case BPF_JMP32 :
1243
+ case BPF_JMP :
1244
+ break ;
1245
+
1246
+ case BPF_LDX :
1247
+ case BPF_LD :
1248
+ /* fp holds load result */
1249
+ if (dst == BPF_REG_FP )
1250
+ return 0 ;
1251
+
1252
+ if (class == BPF_LDX && mode == BPF_MEM &&
1253
+ src == BPF_REG_FP && off < offset )
1254
+ offset = off ;
1255
+ break ;
1256
+
1257
+ case BPF_ALU :
1258
+ case BPF_ALU64 :
1259
+ default :
1260
+ /* fp holds ALU result */
1261
+ if (dst == BPF_REG_FP )
1262
+ return 0 ;
1263
+ }
1264
+ }
1265
+
1266
+ if (offset < 0 ) {
1267
+ /*
1268
+ * safely be converted to a positive 'int', since insn->off
1269
+ * is 's16'
1270
+ */
1271
+ offset = - offset ;
1272
+ /* align down to 8 bytes */
1273
+ offset = ALIGN_DOWN (offset , 8 );
1274
+ }
1275
+
1276
+ return offset ;
1277
+ }
1278
+
1170
1279
static int build_body (struct jit_ctx * ctx , bool extra_pass )
1171
1280
{
1172
1281
const struct bpf_prog * prog = ctx -> prog ;
@@ -1288,6 +1397,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
1288
1397
goto out_off ;
1289
1398
}
1290
1399
1400
+ ctx .fpb_offset = find_fpb_offset (prog );
1401
+
1291
1402
/*
1292
1403
* 1. Initial fake pass to compute ctx->idx and ctx->offset.
1293
1404
*
0 commit comments