@@ -191,6 +191,47 @@ static bool is_addsub_imm(u32 imm)
191
191
return !(imm & ~0xfff ) || !(imm & ~0xfff000 );
192
192
}
193
193
194
+ /*
195
+ * There are 3 types of AArch64 LDR/STR (immediate) instruction:
196
+ * Post-index, Pre-index, Unsigned offset.
197
+ *
198
+ * For BPF ldr/str, the "unsigned offset" type is sufficient.
199
+ *
200
+ * "Unsigned offset" type LDR(immediate) format:
201
+ *
202
+ * 3 2 1 0
203
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
204
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
205
+ * |x x|1 1 1 0 0 1 0 1| imm12 | Rn | Rt |
206
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
207
+ * scale
208
+ *
209
+ * "Unsigned offset" type STR(immediate) format:
210
+ * 3 2 1 0
211
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
212
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
213
+ * |x x|1 1 1 0 0 1 0 0| imm12 | Rn | Rt |
214
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
215
+ * scale
216
+ *
217
+ * The offset is calculated from imm12 and scale in the following way:
218
+ *
219
+ * offset = (u64)imm12 << scale
220
+ */
221
+ static bool is_lsi_offset (s16 offset , int scale )
222
+ {
223
+ if (offset < 0 )
224
+ return false;
225
+
226
+ if (offset > (0xFFF << scale ))
227
+ return false;
228
+
229
+ if (offset & ((1 << scale ) - 1 ))
230
+ return false;
231
+
232
+ return true;
233
+ }
234
+
194
235
/* Tail call offset to jump into */
195
236
#if IS_ENABLED (CONFIG_ARM64_BTI_KERNEL )
196
237
#define PROLOGUE_OFFSET 8
@@ -971,19 +1012,38 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
971
1012
case BPF_LDX | BPF_PROBE_MEM | BPF_W :
972
1013
case BPF_LDX | BPF_PROBE_MEM | BPF_H :
973
1014
case BPF_LDX | BPF_PROBE_MEM | BPF_B :
974
- emit_a64_mov_i (1 , tmp , off , ctx );
975
1015
switch (BPF_SIZE (code )) {
976
1016
case BPF_W :
977
- emit (A64_LDR32 (dst , src , tmp ), ctx );
1017
+ if (is_lsi_offset (off , 2 )) {
1018
+ emit (A64_LDR32I (dst , src , off ), ctx );
1019
+ } else {
1020
+ emit_a64_mov_i (1 , tmp , off , ctx );
1021
+ emit (A64_LDR32 (dst , src , tmp ), ctx );
1022
+ }
978
1023
break ;
979
1024
case BPF_H :
980
- emit (A64_LDRH (dst , src , tmp ), ctx );
1025
+ if (is_lsi_offset (off , 1 )) {
1026
+ emit (A64_LDRHI (dst , src , off ), ctx );
1027
+ } else {
1028
+ emit_a64_mov_i (1 , tmp , off , ctx );
1029
+ emit (A64_LDRH (dst , src , tmp ), ctx );
1030
+ }
981
1031
break ;
982
1032
case BPF_B :
983
- emit (A64_LDRB (dst , src , tmp ), ctx );
1033
+ if (is_lsi_offset (off , 0 )) {
1034
+ emit (A64_LDRBI (dst , src , off ), ctx );
1035
+ } else {
1036
+ emit_a64_mov_i (1 , tmp , off , ctx );
1037
+ emit (A64_LDRB (dst , src , tmp ), ctx );
1038
+ }
984
1039
break ;
985
1040
case BPF_DW :
986
- emit (A64_LDR64 (dst , src , tmp ), ctx );
1041
+ if (is_lsi_offset (off , 3 )) {
1042
+ emit (A64_LDR64I (dst , src , off ), ctx );
1043
+ } else {
1044
+ emit_a64_mov_i (1 , tmp , off , ctx );
1045
+ emit (A64_LDR64 (dst , src , tmp ), ctx );
1046
+ }
987
1047
break ;
988
1048
}
989
1049
@@ -1011,20 +1071,39 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1011
1071
case BPF_ST | BPF_MEM | BPF_B :
1012
1072
case BPF_ST | BPF_MEM | BPF_DW :
1013
1073
/* Load imm to a register then store it */
1014
- emit_a64_mov_i (1 , tmp2 , off , ctx );
1015
1074
emit_a64_mov_i (1 , tmp , imm , ctx );
1016
1075
switch (BPF_SIZE (code )) {
1017
1076
case BPF_W :
1018
- emit (A64_STR32 (tmp , dst , tmp2 ), ctx );
1077
+ if (is_lsi_offset (off , 2 )) {
1078
+ emit (A64_STR32I (tmp , dst , off ), ctx );
1079
+ } else {
1080
+ emit_a64_mov_i (1 , tmp2 , off , ctx );
1081
+ emit (A64_STR32 (tmp , dst , tmp2 ), ctx );
1082
+ }
1019
1083
break ;
1020
1084
case BPF_H :
1021
- emit (A64_STRH (tmp , dst , tmp2 ), ctx );
1085
+ if (is_lsi_offset (off , 1 )) {
1086
+ emit (A64_STRHI (tmp , dst , off ), ctx );
1087
+ } else {
1088
+ emit_a64_mov_i (1 , tmp2 , off , ctx );
1089
+ emit (A64_STRH (tmp , dst , tmp2 ), ctx );
1090
+ }
1022
1091
break ;
1023
1092
case BPF_B :
1024
- emit (A64_STRB (tmp , dst , tmp2 ), ctx );
1093
+ if (is_lsi_offset (off , 0 )) {
1094
+ emit (A64_STRBI (tmp , dst , off ), ctx );
1095
+ } else {
1096
+ emit_a64_mov_i (1 , tmp2 , off , ctx );
1097
+ emit (A64_STRB (tmp , dst , tmp2 ), ctx );
1098
+ }
1025
1099
break ;
1026
1100
case BPF_DW :
1027
- emit (A64_STR64 (tmp , dst , tmp2 ), ctx );
1101
+ if (is_lsi_offset (off , 3 )) {
1102
+ emit (A64_STR64I (tmp , dst , off ), ctx );
1103
+ } else {
1104
+ emit_a64_mov_i (1 , tmp2 , off , ctx );
1105
+ emit (A64_STR64 (tmp , dst , tmp2 ), ctx );
1106
+ }
1028
1107
break ;
1029
1108
}
1030
1109
break ;
@@ -1034,19 +1113,38 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
1034
1113
case BPF_STX | BPF_MEM | BPF_H :
1035
1114
case BPF_STX | BPF_MEM | BPF_B :
1036
1115
case BPF_STX | BPF_MEM | BPF_DW :
1037
- emit_a64_mov_i (1 , tmp , off , ctx );
1038
1116
switch (BPF_SIZE (code )) {
1039
1117
case BPF_W :
1040
- emit (A64_STR32 (src , dst , tmp ), ctx );
1118
+ if (is_lsi_offset (off , 2 )) {
1119
+ emit (A64_STR32I (src , dst , off ), ctx );
1120
+ } else {
1121
+ emit_a64_mov_i (1 , tmp , off , ctx );
1122
+ emit (A64_STR32 (src , dst , tmp ), ctx );
1123
+ }
1041
1124
break ;
1042
1125
case BPF_H :
1043
- emit (A64_STRH (src , dst , tmp ), ctx );
1126
+ if (is_lsi_offset (off , 1 )) {
1127
+ emit (A64_STRHI (src , dst , off ), ctx );
1128
+ } else {
1129
+ emit_a64_mov_i (1 , tmp , off , ctx );
1130
+ emit (A64_STRH (src , dst , tmp ), ctx );
1131
+ }
1044
1132
break ;
1045
1133
case BPF_B :
1046
- emit (A64_STRB (src , dst , tmp ), ctx );
1134
+ if (is_lsi_offset (off , 0 )) {
1135
+ emit (A64_STRBI (src , dst , off ), ctx );
1136
+ } else {
1137
+ emit_a64_mov_i (1 , tmp , off , ctx );
1138
+ emit (A64_STRB (src , dst , tmp ), ctx );
1139
+ }
1047
1140
break ;
1048
1141
case BPF_DW :
1049
- emit (A64_STR64 (src , dst , tmp ), ctx );
1142
+ if (is_lsi_offset (off , 3 )) {
1143
+ emit (A64_STR64I (src , dst , off ), ctx );
1144
+ } else {
1145
+ emit_a64_mov_i (1 , tmp , off , ctx );
1146
+ emit (A64_STR64 (src , dst , tmp ), ctx );
1147
+ }
1050
1148
break ;
1051
1149
}
1052
1150
break ;
0 commit comments