@@ -2064,7 +2064,7 @@ bool bpf_jit_supports_subprog_tailcalls(void)
2064
2064
}
2065
2065
2066
2066
static void invoke_bpf_prog (struct jit_ctx * ctx , struct bpf_tramp_link * l ,
2067
- int args_off , int retval_off , int run_ctx_off ,
2067
+ int bargs_off , int retval_off , int run_ctx_off ,
2068
2068
bool save_ret )
2069
2069
{
2070
2070
__le32 * branch ;
@@ -2106,7 +2106,7 @@ static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l,
2106
2106
branch = ctx -> image + ctx -> idx ;
2107
2107
emit (A64_NOP , ctx );
2108
2108
2109
- emit (A64_ADD_I (1 , A64_R (0 ), A64_SP , args_off ), ctx );
2109
+ emit (A64_ADD_I (1 , A64_R (0 ), A64_SP , bargs_off ), ctx );
2110
2110
if (!p -> jited )
2111
2111
emit_addr_mov_i64 (A64_R (1 ), (const u64 )p -> insnsi , ctx );
2112
2112
@@ -2131,7 +2131,7 @@ static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l,
2131
2131
}
2132
2132
2133
2133
static void invoke_bpf_mod_ret (struct jit_ctx * ctx , struct bpf_tramp_links * tl ,
2134
- int args_off , int retval_off , int run_ctx_off ,
2134
+ int bargs_off , int retval_off , int run_ctx_off ,
2135
2135
__le32 * * branches )
2136
2136
{
2137
2137
int i ;
@@ -2141,7 +2141,7 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
2141
2141
*/
2142
2142
emit (A64_STR64I (A64_ZR , A64_SP , retval_off ), ctx );
2143
2143
for (i = 0 ; i < tl -> nr_links ; i ++ ) {
2144
- invoke_bpf_prog (ctx , tl -> links [i ], args_off , retval_off ,
2144
+ invoke_bpf_prog (ctx , tl -> links [i ], bargs_off , retval_off ,
2145
2145
run_ctx_off , true);
2146
2146
/* if (*(u64 *)(sp + retval_off) != 0)
2147
2147
* goto do_fexit;
@@ -2155,23 +2155,125 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
2155
2155
}
2156
2156
}
2157
2157
2158
- static void save_args (struct jit_ctx * ctx , int args_off , int nregs )
2158
+ struct arg_aux {
2159
+ /* how many args are passed through registers, the rest of the args are
2160
+ * passed through stack
2161
+ */
2162
+ int args_in_regs ;
2163
+ /* how many registers are used to pass arguments */
2164
+ int regs_for_args ;
2165
+ /* how much stack is used for additional args passed to bpf program
2166
+ * that did not fit in original function registers
2167
+ */
2168
+ int bstack_for_args ;
2169
+ /* home much stack is used for additional args passed to the
2170
+ * original function when called from trampoline (this one needs
2171
+ * arguments to be properly aligned)
2172
+ */
2173
+ int ostack_for_args ;
2174
+ };
2175
+
2176
+ static int calc_arg_aux (const struct btf_func_model * m ,
2177
+ struct arg_aux * a )
2159
2178
{
2160
- int i ;
2179
+ int stack_slots , nregs , slots , i ;
2180
+
2181
+ /* verifier ensures m->nr_args <= MAX_BPF_FUNC_ARGS */
2182
+ for (i = 0 , nregs = 0 ; i < m -> nr_args ; i ++ ) {
2183
+ slots = (m -> arg_size [i ] + 7 ) / 8 ;
2184
+ if (nregs + slots <= 8 ) /* passed through register ? */
2185
+ nregs += slots ;
2186
+ else
2187
+ break ;
2188
+ }
2189
+
2190
+ a -> args_in_regs = i ;
2191
+ a -> regs_for_args = nregs ;
2192
+ a -> ostack_for_args = 0 ;
2193
+ a -> bstack_for_args = 0 ;
2161
2194
2162
- for (i = 0 ; i < nregs ; i ++ ) {
2163
- emit (A64_STR64I (i , A64_SP , args_off ), ctx );
2164
- args_off += 8 ;
2195
+ /* the rest arguments are passed through stack */
2196
+ for (; i < m -> nr_args ; i ++ ) {
2197
+ /* We can not know for sure about exact alignment needs for
2198
+ * struct passed on stack, so deny those
2199
+ */
2200
+ if (m -> arg_flags [i ] & BTF_FMODEL_STRUCT_ARG )
2201
+ return - ENOTSUPP ;
2202
+ stack_slots = (m -> arg_size [i ] + 7 ) / 8 ;
2203
+ a -> bstack_for_args += stack_slots * 8 ;
2204
+ a -> ostack_for_args = a -> ostack_for_args + stack_slots * 8 ;
2205
+ }
2206
+
2207
+ return 0 ;
2208
+ }
2209
+
2210
+ static void clear_garbage (struct jit_ctx * ctx , int reg , int effective_bytes )
2211
+ {
2212
+ if (effective_bytes ) {
2213
+ int garbage_bits = 64 - 8 * effective_bytes ;
2214
+ #ifdef CONFIG_CPU_BIG_ENDIAN
2215
+ /* garbage bits are at the right end */
2216
+ emit (A64_LSR (1 , reg , reg , garbage_bits ), ctx );
2217
+ emit (A64_LSL (1 , reg , reg , garbage_bits ), ctx );
2218
+ #else
2219
+ /* garbage bits are at the left end */
2220
+ emit (A64_LSL (1 , reg , reg , garbage_bits ), ctx );
2221
+ emit (A64_LSR (1 , reg , reg , garbage_bits ), ctx );
2222
+ #endif
2165
2223
}
2166
2224
}
2167
2225
2168
- static void restore_args (struct jit_ctx * ctx , int args_off , int nregs )
2226
+ static void save_args (struct jit_ctx * ctx , int bargs_off , int oargs_off ,
2227
+ const struct btf_func_model * m ,
2228
+ const struct arg_aux * a ,
2229
+ bool for_call_origin )
2169
2230
{
2170
2231
int i ;
2232
+ int reg ;
2233
+ int doff ;
2234
+ int soff ;
2235
+ int slots ;
2236
+ u8 tmp = bpf2a64 [TMP_REG_1 ];
2237
+
2238
+ /* store arguments to the stack for the bpf program, or restore
2239
+ * arguments from stack for the original function
2240
+ */
2241
+ for (reg = 0 ; reg < a -> regs_for_args ; reg ++ ) {
2242
+ emit (for_call_origin ?
2243
+ A64_LDR64I (reg , A64_SP , bargs_off ) :
2244
+ A64_STR64I (reg , A64_SP , bargs_off ),
2245
+ ctx );
2246
+ bargs_off += 8 ;
2247
+ }
2171
2248
2172
- for (i = 0 ; i < nregs ; i ++ ) {
2173
- emit (A64_LDR64I (i , A64_SP , args_off ), ctx );
2174
- args_off += 8 ;
2249
+ soff = 32 ; /* on stack arguments start from FP + 32 */
2250
+ doff = (for_call_origin ? oargs_off : bargs_off );
2251
+
2252
+ /* save on stack arguments */
2253
+ for (i = a -> args_in_regs ; i < m -> nr_args ; i ++ ) {
2254
+ slots = (m -> arg_size [i ] + 7 ) / 8 ;
2255
+ /* verifier ensures arg_size <= 16, so slots equals 1 or 2 */
2256
+ while (slots -- > 0 ) {
2257
+ emit (A64_LDR64I (tmp , A64_FP , soff ), ctx );
2258
+ /* if there is unused space in the last slot, clear
2259
+ * the garbage contained in the space.
2260
+ */
2261
+ if (slots == 0 && !for_call_origin )
2262
+ clear_garbage (ctx , tmp , m -> arg_size [i ] % 8 );
2263
+ emit (A64_STR64I (tmp , A64_SP , doff ), ctx );
2264
+ soff += 8 ;
2265
+ doff += 8 ;
2266
+ }
2267
+ }
2268
+ }
2269
+
2270
+ static void restore_args (struct jit_ctx * ctx , int bargs_off , int nregs )
2271
+ {
2272
+ int reg ;
2273
+
2274
+ for (reg = 0 ; reg < nregs ; reg ++ ) {
2275
+ emit (A64_LDR64I (reg , A64_SP , bargs_off ), ctx );
2276
+ bargs_off += 8 ;
2175
2277
}
2176
2278
}
2177
2279
@@ -2194,17 +2296,21 @@ static bool is_struct_ops_tramp(const struct bpf_tramp_links *fentry_links)
2194
2296
*/
2195
2297
static int prepare_trampoline (struct jit_ctx * ctx , struct bpf_tramp_image * im ,
2196
2298
struct bpf_tramp_links * tlinks , void * func_addr ,
2197
- int nregs , u32 flags )
2299
+ const struct btf_func_model * m ,
2300
+ const struct arg_aux * a ,
2301
+ u32 flags )
2198
2302
{
2199
2303
int i ;
2200
2304
int stack_size ;
2201
2305
int retaddr_off ;
2202
2306
int regs_off ;
2203
2307
int retval_off ;
2204
- int args_off ;
2205
- int nregs_off ;
2308
+ int bargs_off ;
2309
+ int nfuncargs_off ;
2206
2310
int ip_off ;
2207
2311
int run_ctx_off ;
2312
+ int oargs_off ;
2313
+ int nfuncargs ;
2208
2314
struct bpf_tramp_links * fentry = & tlinks [BPF_TRAMP_FENTRY ];
2209
2315
struct bpf_tramp_links * fexit = & tlinks [BPF_TRAMP_FEXIT ];
2210
2316
struct bpf_tramp_links * fmod_ret = & tlinks [BPF_TRAMP_MODIFY_RETURN ];
@@ -2213,31 +2319,38 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2213
2319
bool is_struct_ops = is_struct_ops_tramp (fentry );
2214
2320
2215
2321
/* trampoline stack layout:
2216
- * [ parent ip ]
2217
- * [ FP ]
2218
- * SP + retaddr_off [ self ip ]
2219
- * [ FP ]
2322
+ * [ parent ip ]
2323
+ * [ FP ]
2324
+ * SP + retaddr_off [ self ip ]
2325
+ * [ FP ]
2220
2326
*
2221
- * [ padding ] align SP to multiples of 16
2327
+ * [ padding ] align SP to multiples of 16
2222
2328
*
2223
- * [ x20 ] callee saved reg x20
2224
- * SP + regs_off [ x19 ] callee saved reg x19
2329
+ * [ x20 ] callee saved reg x20
2330
+ * SP + regs_off [ x19 ] callee saved reg x19
2225
2331
*
2226
- * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
2227
- * BPF_TRAMP_F_RET_FENTRY_RET
2332
+ * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
2333
+ * BPF_TRAMP_F_RET_FENTRY_RET
2334
+ * [ arg reg N ]
2335
+ * [ ... ]
2336
+ * SP + bargs_off [ arg reg 1 ] for bpf
2228
2337
*
2229
- * [ arg reg N ]
2230
- * [ ... ]
2231
- * SP + args_off [ arg reg 1 ]
2338
+ * SP + nfuncargs_off [ arg regs count ]
2232
2339
*
2233
- * SP + nregs_off [ arg regs count ]
2340
+ * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
2234
2341
*
2235
- * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
2342
+ * SP + run_ctx_off [ bpf_tramp_run_ctx ]
2236
2343
*
2237
- * SP + run_ctx_off [ bpf_tramp_run_ctx ]
2344
+ * [ stack arg N ]
2345
+ * [ ... ]
2346
+ * SP + oargs_off [ stack arg 1 ] for original func
2238
2347
*/
2239
2348
2240
2349
stack_size = 0 ;
2350
+ oargs_off = stack_size ;
2351
+ if (flags & BPF_TRAMP_F_CALL_ORIG )
2352
+ stack_size += a -> ostack_for_args ;
2353
+
2241
2354
run_ctx_off = stack_size ;
2242
2355
/* room for bpf_tramp_run_ctx */
2243
2356
stack_size += round_up (sizeof (struct bpf_tramp_run_ctx ), 8 );
@@ -2247,13 +2360,14 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2247
2360
if (flags & BPF_TRAMP_F_IP_ARG )
2248
2361
stack_size += 8 ;
2249
2362
2250
- nregs_off = stack_size ;
2363
+ nfuncargs_off = stack_size ;
2251
2364
/* room for args count */
2252
2365
stack_size += 8 ;
2253
2366
2254
- args_off = stack_size ;
2367
+ bargs_off = stack_size ;
2255
2368
/* room for args */
2256
- stack_size += nregs * 8 ;
2369
+ nfuncargs = a -> regs_for_args + a -> bstack_for_args / 8 ;
2370
+ stack_size += 8 * nfuncargs ;
2257
2371
2258
2372
/* room for return value */
2259
2373
retval_off = stack_size ;
@@ -2300,11 +2414,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2300
2414
}
2301
2415
2302
2416
/* save arg regs count*/
2303
- emit (A64_MOVZ (1 , A64_R (10 ), nregs , 0 ), ctx );
2304
- emit (A64_STR64I (A64_R (10 ), A64_SP , nregs_off ), ctx );
2417
+ emit (A64_MOVZ (1 , A64_R (10 ), nfuncargs , 0 ), ctx );
2418
+ emit (A64_STR64I (A64_R (10 ), A64_SP , nfuncargs_off ), ctx );
2305
2419
2306
- /* save arg regs */
2307
- save_args (ctx , args_off , nregs );
2420
+ /* save args for bpf */
2421
+ save_args (ctx , bargs_off , oargs_off , m , a , false );
2308
2422
2309
2423
/* save callee saved registers */
2310
2424
emit (A64_STR64I (A64_R (19 ), A64_SP , regs_off ), ctx );
@@ -2320,7 +2434,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2320
2434
}
2321
2435
2322
2436
for (i = 0 ; i < fentry -> nr_links ; i ++ )
2323
- invoke_bpf_prog (ctx , fentry -> links [i ], args_off ,
2437
+ invoke_bpf_prog (ctx , fentry -> links [i ], bargs_off ,
2324
2438
retval_off , run_ctx_off ,
2325
2439
flags & BPF_TRAMP_F_RET_FENTRY_RET );
2326
2440
@@ -2330,12 +2444,13 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2330
2444
if (!branches )
2331
2445
return - ENOMEM ;
2332
2446
2333
- invoke_bpf_mod_ret (ctx , fmod_ret , args_off , retval_off ,
2447
+ invoke_bpf_mod_ret (ctx , fmod_ret , bargs_off , retval_off ,
2334
2448
run_ctx_off , branches );
2335
2449
}
2336
2450
2337
2451
if (flags & BPF_TRAMP_F_CALL_ORIG ) {
2338
- restore_args (ctx , args_off , nregs );
2452
+ /* save args for original func */
2453
+ save_args (ctx , bargs_off , oargs_off , m , a , true);
2339
2454
/* call original func */
2340
2455
emit (A64_LDR64I (A64_R (10 ), A64_SP , retaddr_off ), ctx );
2341
2456
emit (A64_ADR (A64_LR , AARCH64_INSN_SIZE * 2 ), ctx );
@@ -2354,7 +2469,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2354
2469
}
2355
2470
2356
2471
for (i = 0 ; i < fexit -> nr_links ; i ++ )
2357
- invoke_bpf_prog (ctx , fexit -> links [i ], args_off , retval_off ,
2472
+ invoke_bpf_prog (ctx , fexit -> links [i ], bargs_off , retval_off ,
2358
2473
run_ctx_off , false);
2359
2474
2360
2475
if (flags & BPF_TRAMP_F_CALL_ORIG ) {
@@ -2368,7 +2483,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2368
2483
}
2369
2484
2370
2485
if (flags & BPF_TRAMP_F_RESTORE_REGS )
2371
- restore_args (ctx , args_off , nregs );
2486
+ restore_args (ctx , bargs_off , a -> regs_for_args );
2372
2487
2373
2488
/* restore callee saved register x19 and x20 */
2374
2489
emit (A64_LDR64I (A64_R (19 ), A64_SP , regs_off ), ctx );
@@ -2428,14 +2543,16 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
2428
2543
.idx = 0 ,
2429
2544
};
2430
2545
struct bpf_tramp_image im ;
2546
+ struct arg_aux aaux ;
2431
2547
int nregs , ret ;
2432
2548
2433
2549
nregs = btf_func_model_nregs (m );
2434
- /* the first 8 registers are used for arguments */
2435
- if (nregs > 8 )
2436
- return - ENOTSUPP ;
2437
2550
2438
- ret = prepare_trampoline (& ctx , & im , tlinks , func_addr , nregs , flags );
2551
+ ret = calc_arg_aux (m , & aaux );
2552
+ if (ret < 0 )
2553
+ return ret ;
2554
+
2555
+ ret = prepare_trampoline (& ctx , & im , tlinks , func_addr , m , & aaux , flags );
2439
2556
if (ret < 0 )
2440
2557
return ret ;
2441
2558
@@ -2462,9 +2579,10 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
2462
2579
u32 flags , struct bpf_tramp_links * tlinks ,
2463
2580
void * func_addr )
2464
2581
{
2465
- int ret , nregs ;
2466
- void * image , * tmp ;
2467
2582
u32 size = ro_image_end - ro_image ;
2583
+ struct arg_aux aaux ;
2584
+ void * image , * tmp ;
2585
+ int ret ;
2468
2586
2469
2587
/* image doesn't need to be in module memory range, so we can
2470
2588
* use kvmalloc.
@@ -2480,13 +2598,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
2480
2598
.write = true,
2481
2599
};
2482
2600
2483
- nregs = btf_func_model_nregs (m );
2484
- /* the first 8 registers are used for arguments */
2485
- if (nregs > 8 )
2486
- return - ENOTSUPP ;
2487
2601
2488
2602
jit_fill_hole (image , (unsigned int )(ro_image_end - ro_image ));
2489
- ret = prepare_trampoline (& ctx , im , tlinks , func_addr , nregs , flags );
2603
+ ret = calc_arg_aux (m , & aaux );
2604
+ if (ret )
2605
+ goto out ;
2606
+ ret = prepare_trampoline (& ctx , im , tlinks , func_addr , m , & aaux , flags );
2490
2607
2491
2608
if (ret > 0 && validate_code (& ctx ) < 0 ) {
2492
2609
ret = - EINVAL ;
0 commit comments