@@ -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,134 @@ 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
+
2194
+ /* the rest arguments are passed through stack */
2195
+ for (a -> ostack_for_args = 0 , a -> bstack_for_args = 0 ;
2196
+ 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 - EOPNOTSUPP ;
2202
+ stack_slots = (m -> arg_size [i ] + 7 ) / 8 ;
2203
+ /* AAPCS 64 C.14: arguments passed on stack must be aligned to
2204
+ * max(8, arg_natural_alignment)
2205
+ */
2206
+ a -> bstack_for_args += stack_slots * 8 ;
2207
+ a -> ostack_for_args = round_up (a -> ostack_for_args + stack_slots * 8 , 8 );
2208
+ }
2161
2209
2162
- for (i = 0 ; i < nregs ; i ++ ) {
2163
- emit (A64_STR64I (i , A64_SP , args_off ), ctx );
2164
- args_off += 8 ;
2210
+ return 0 ;
2211
+ }
2212
+
2213
+ static void clear_garbage (struct jit_ctx * ctx , int reg , int effective_bytes )
2214
+ {
2215
+ if (effective_bytes ) {
2216
+ int garbage_bits = 64 - 8 * effective_bytes ;
2217
+ #ifdef CONFIG_CPU_BIG_ENDIAN
2218
+ /* garbage bits are at the right end */
2219
+ emit (A64_LSR (1 , reg , reg , garbage_bits ), ctx );
2220
+ emit (A64_LSL (1 , reg , reg , garbage_bits ), ctx );
2221
+ #else
2222
+ /* garbage bits are at the left end */
2223
+ emit (A64_LSL (1 , reg , reg , garbage_bits ), ctx );
2224
+ emit (A64_LSR (1 , reg , reg , garbage_bits ), ctx );
2225
+ #endif
2165
2226
}
2166
2227
}
2167
2228
2168
- static void restore_args (struct jit_ctx * ctx , int args_off , int nregs )
2229
+ static void save_args (struct jit_ctx * ctx , int bargs_off , int oargs_off ,
2230
+ const struct btf_func_model * m ,
2231
+ const struct arg_aux * a ,
2232
+ bool for_call_origin )
2169
2233
{
2170
2234
int i ;
2235
+ int reg ;
2236
+ int doff ;
2237
+ int soff ;
2238
+ int slots ;
2239
+ u8 tmp = bpf2a64 [TMP_REG_1 ];
2240
+
2241
+ /* store arguments to the stack for the bpf program, or restore
2242
+ * arguments from stack for the original function
2243
+ */
2244
+ for (reg = 0 ; reg < a -> regs_for_args ; reg ++ ) {
2245
+ emit (for_call_origin ?
2246
+ A64_LDR64I (reg , A64_SP , bargs_off ) :
2247
+ A64_STR64I (reg , A64_SP , bargs_off ),
2248
+ ctx );
2249
+ bargs_off += 8 ;
2250
+ }
2251
+
2252
+ soff = 32 ; /* on stack arguments start from FP + 32 */
2253
+ doff = (for_call_origin ? oargs_off : bargs_off );
2254
+
2255
+ /* save on stack arguments */
2256
+ for (i = a -> args_in_regs ; i < m -> nr_args ; i ++ ) {
2257
+ slots = (m -> arg_size [i ] + 7 ) / 8 ;
2258
+ /* AAPCS C.14: additional arguments on stack must be
2259
+ * aligned on max(8, arg_natural_alignment)
2260
+ */
2261
+ soff = round_up (soff , 8 );
2262
+ if (for_call_origin )
2263
+ doff = round_up (doff , 8 );
2264
+ /* verifier ensures arg_size <= 16, so slots equals 1 or 2 */
2265
+ while (slots -- > 0 ) {
2266
+ emit (A64_LDR64I (tmp , A64_FP , soff ), ctx );
2267
+ /* if there is unused space in the last slot, clear
2268
+ * the garbage contained in the space.
2269
+ */
2270
+ if (slots == 0 && !for_call_origin )
2271
+ clear_garbage (ctx , tmp , m -> arg_size [i ] % 8 );
2272
+ emit (A64_STR64I (tmp , A64_SP , doff ), ctx );
2273
+ soff += 8 ;
2274
+ doff += 8 ;
2275
+ }
2276
+ }
2277
+ }
2278
+
2279
+ static void restore_args (struct jit_ctx * ctx , int bargs_off , int nregs )
2280
+ {
2281
+ int reg ;
2171
2282
2172
- for (i = 0 ; i < nregs ; i ++ ) {
2173
- emit (A64_LDR64I (i , A64_SP , args_off ), ctx );
2174
- args_off += 8 ;
2283
+ for (reg = 0 ; reg < nregs ; reg ++ ) {
2284
+ emit (A64_LDR64I (reg , A64_SP , bargs_off ), ctx );
2285
+ bargs_off += 8 ;
2175
2286
}
2176
2287
}
2177
2288
@@ -2194,17 +2305,21 @@ static bool is_struct_ops_tramp(const struct bpf_tramp_links *fentry_links)
2194
2305
*/
2195
2306
static int prepare_trampoline (struct jit_ctx * ctx , struct bpf_tramp_image * im ,
2196
2307
struct bpf_tramp_links * tlinks , void * func_addr ,
2197
- int nregs , u32 flags )
2308
+ const struct btf_func_model * m ,
2309
+ const struct arg_aux * a ,
2310
+ u32 flags )
2198
2311
{
2199
2312
int i ;
2200
2313
int stack_size ;
2201
2314
int retaddr_off ;
2202
2315
int regs_off ;
2203
2316
int retval_off ;
2204
- int args_off ;
2205
- int nregs_off ;
2317
+ int bargs_off ;
2318
+ int nfuncargs_off ;
2206
2319
int ip_off ;
2207
2320
int run_ctx_off ;
2321
+ int oargs_off ;
2322
+ int nfuncargs ;
2208
2323
struct bpf_tramp_links * fentry = & tlinks [BPF_TRAMP_FENTRY ];
2209
2324
struct bpf_tramp_links * fexit = & tlinks [BPF_TRAMP_FEXIT ];
2210
2325
struct bpf_tramp_links * fmod_ret = & tlinks [BPF_TRAMP_MODIFY_RETURN ];
@@ -2213,31 +2328,38 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2213
2328
bool is_struct_ops = is_struct_ops_tramp (fentry );
2214
2329
2215
2330
/* trampoline stack layout:
2216
- * [ parent ip ]
2217
- * [ FP ]
2218
- * SP + retaddr_off [ self ip ]
2219
- * [ FP ]
2331
+ * [ parent ip ]
2332
+ * [ FP ]
2333
+ * SP + retaddr_off [ self ip ]
2334
+ * [ FP ]
2220
2335
*
2221
- * [ padding ] align SP to multiples of 16
2336
+ * [ padding ] align SP to multiples of 16
2222
2337
*
2223
- * [ x20 ] callee saved reg x20
2224
- * SP + regs_off [ x19 ] callee saved reg x19
2338
+ * [ x20 ] callee saved reg x20
2339
+ * SP + regs_off [ x19 ] callee saved reg x19
2225
2340
*
2226
- * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
2227
- * BPF_TRAMP_F_RET_FENTRY_RET
2341
+ * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
2342
+ * BPF_TRAMP_F_RET_FENTRY_RET
2343
+ * [ arg reg N ]
2344
+ * [ ... ]
2345
+ * SP + bargs_off [ arg reg 1 ] for bpf
2228
2346
*
2229
- * [ arg reg N ]
2230
- * [ ... ]
2231
- * SP + args_off [ arg reg 1 ]
2347
+ * SP + nfuncargs_off [ arg regs count ]
2232
2348
*
2233
- * SP + nregs_off [ arg regs count ]
2349
+ * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
2234
2350
*
2235
- * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
2351
+ * SP + run_ctx_off [ bpf_tramp_run_ctx ]
2236
2352
*
2237
- * SP + run_ctx_off [ bpf_tramp_run_ctx ]
2353
+ * [ stack arg N ]
2354
+ * [ ... ]
2355
+ * SP + oargs_off [ stack arg 1 ] for original func
2238
2356
*/
2239
2357
2240
2358
stack_size = 0 ;
2359
+ oargs_off = stack_size ;
2360
+ if (flags & BPF_TRAMP_F_CALL_ORIG )
2361
+ stack_size += a -> ostack_for_args ;
2362
+
2241
2363
run_ctx_off = stack_size ;
2242
2364
/* room for bpf_tramp_run_ctx */
2243
2365
stack_size += round_up (sizeof (struct bpf_tramp_run_ctx ), 8 );
@@ -2247,13 +2369,14 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2247
2369
if (flags & BPF_TRAMP_F_IP_ARG )
2248
2370
stack_size += 8 ;
2249
2371
2250
- nregs_off = stack_size ;
2372
+ nfuncargs_off = stack_size ;
2251
2373
/* room for args count */
2252
2374
stack_size += 8 ;
2253
2375
2254
- args_off = stack_size ;
2376
+ bargs_off = stack_size ;
2255
2377
/* room for args */
2256
- stack_size += nregs * 8 ;
2378
+ nfuncargs = a -> regs_for_args + a -> bstack_for_args / 8 ;
2379
+ stack_size += 8 * nfuncargs ;
2257
2380
2258
2381
/* room for return value */
2259
2382
retval_off = stack_size ;
@@ -2300,11 +2423,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2300
2423
}
2301
2424
2302
2425
/* 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 );
2426
+ emit (A64_MOVZ (1 , A64_R (10 ), nfuncargs , 0 ), ctx );
2427
+ emit (A64_STR64I (A64_R (10 ), A64_SP , nfuncargs_off ), ctx );
2305
2428
2306
- /* save arg regs */
2307
- save_args (ctx , args_off , nregs );
2429
+ /* save args for bpf */
2430
+ save_args (ctx , bargs_off , oargs_off , m , a , false );
2308
2431
2309
2432
/* save callee saved registers */
2310
2433
emit (A64_STR64I (A64_R (19 ), A64_SP , regs_off ), ctx );
@@ -2320,7 +2443,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2320
2443
}
2321
2444
2322
2445
for (i = 0 ; i < fentry -> nr_links ; i ++ )
2323
- invoke_bpf_prog (ctx , fentry -> links [i ], args_off ,
2446
+ invoke_bpf_prog (ctx , fentry -> links [i ], bargs_off ,
2324
2447
retval_off , run_ctx_off ,
2325
2448
flags & BPF_TRAMP_F_RET_FENTRY_RET );
2326
2449
@@ -2330,12 +2453,13 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2330
2453
if (!branches )
2331
2454
return - ENOMEM ;
2332
2455
2333
- invoke_bpf_mod_ret (ctx , fmod_ret , args_off , retval_off ,
2456
+ invoke_bpf_mod_ret (ctx , fmod_ret , bargs_off , retval_off ,
2334
2457
run_ctx_off , branches );
2335
2458
}
2336
2459
2337
2460
if (flags & BPF_TRAMP_F_CALL_ORIG ) {
2338
- restore_args (ctx , args_off , nregs );
2461
+ /* save args for original func */
2462
+ save_args (ctx , bargs_off , oargs_off , m , a , true);
2339
2463
/* call original func */
2340
2464
emit (A64_LDR64I (A64_R (10 ), A64_SP , retaddr_off ), ctx );
2341
2465
emit (A64_ADR (A64_LR , AARCH64_INSN_SIZE * 2 ), ctx );
@@ -2354,7 +2478,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2354
2478
}
2355
2479
2356
2480
for (i = 0 ; i < fexit -> nr_links ; i ++ )
2357
- invoke_bpf_prog (ctx , fexit -> links [i ], args_off , retval_off ,
2481
+ invoke_bpf_prog (ctx , fexit -> links [i ], bargs_off , retval_off ,
2358
2482
run_ctx_off , false);
2359
2483
2360
2484
if (flags & BPF_TRAMP_F_CALL_ORIG ) {
@@ -2368,7 +2492,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
2368
2492
}
2369
2493
2370
2494
if (flags & BPF_TRAMP_F_RESTORE_REGS )
2371
- restore_args (ctx , args_off , nregs );
2495
+ restore_args (ctx , bargs_off , a -> regs_for_args );
2372
2496
2373
2497
/* restore callee saved register x19 and x20 */
2374
2498
emit (A64_LDR64I (A64_R (19 ), A64_SP , regs_off ), ctx );
@@ -2428,14 +2552,16 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
2428
2552
.idx = 0 ,
2429
2553
};
2430
2554
struct bpf_tramp_image im ;
2555
+ struct arg_aux aaux ;
2431
2556
int nregs , ret ;
2432
2557
2433
2558
nregs = btf_func_model_nregs (m );
2434
- /* the first 8 registers are used for arguments */
2435
- if (nregs > 8 )
2436
- return - ENOTSUPP ;
2437
2559
2438
- ret = prepare_trampoline (& ctx , & im , tlinks , func_addr , nregs , flags );
2560
+ ret = calc_arg_aux (m , & aaux );
2561
+ if (ret < 0 )
2562
+ return ret ;
2563
+
2564
+ ret = prepare_trampoline (& ctx , & im , tlinks , func_addr , m , & aaux , flags );
2439
2565
if (ret < 0 )
2440
2566
return ret ;
2441
2567
@@ -2462,9 +2588,10 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
2462
2588
u32 flags , struct bpf_tramp_links * tlinks ,
2463
2589
void * func_addr )
2464
2590
{
2465
- int ret , nregs ;
2466
- void * image , * tmp ;
2467
2591
u32 size = ro_image_end - ro_image ;
2592
+ struct arg_aux aaux ;
2593
+ void * image , * tmp ;
2594
+ int ret ;
2468
2595
2469
2596
/* image doesn't need to be in module memory range, so we can
2470
2597
* use kvmalloc.
@@ -2480,13 +2607,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
2480
2607
.write = true,
2481
2608
};
2482
2609
2483
- nregs = btf_func_model_nregs (m );
2484
- /* the first 8 registers are used for arguments */
2485
- if (nregs > 8 )
2486
- return - ENOTSUPP ;
2487
2610
2488
2611
jit_fill_hole (image , (unsigned int )(ro_image_end - ro_image ));
2489
- ret = prepare_trampoline (& ctx , im , tlinks , func_addr , nregs , flags );
2612
+ ret = calc_arg_aux (m , & aaux );
2613
+ if (ret )
2614
+ goto out ;
2615
+ ret = prepare_trampoline (& ctx , im , tlinks , func_addr , m , & aaux , flags );
2490
2616
2491
2617
if (ret > 0 && validate_code (& ctx ) < 0 ) {
2492
2618
ret = - EINVAL ;
0 commit comments