Skip to content

Commit 70d1a3b

Browse files
Yonghong Songintel-lab-lkp
authored andcommitted
bpf, x86: Support private stack in jit
Private stack is allocated in function bpf_int_jit_compile() with alignment 16. The x86 register 9 (X86_REG_R9) is used to replace bpf frame register (BPF_REG_10). The private stack is used per subprog per cpu. The X86_REG_R9 is saved and restored around every func call (not including tailcall) to maintain correctness of X86_REG_R9. Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
1 parent 6ce848c commit 70d1a3b

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,22 @@ struct jit_context {
325325
/* Number of bytes that will be skipped on tailcall */
326326
#define X86_TAIL_CALL_OFFSET (12 + ENDBR_INSN_SIZE)
327327

328+
static void push_r9(u8 **pprog)
329+
{
330+
u8 *prog = *pprog;
331+
332+
EMIT2(0x41, 0x51); /* push r9 */
333+
*pprog = prog;
334+
}
335+
336+
static void pop_r9(u8 **pprog)
337+
{
338+
u8 *prog = *pprog;
339+
340+
EMIT2(0x41, 0x59); /* pop r9 */
341+
*pprog = prog;
342+
}
343+
328344
static void push_r12(u8 **pprog)
329345
{
330346
u8 *prog = *pprog;
@@ -1404,6 +1420,24 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op)
14041420
*pprog = prog;
14051421
}
14061422

1423+
static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
1424+
{
1425+
u8 *prog = *pprog;
1426+
1427+
/* movabs r9, priv_frame_ptr */
1428+
emit_mov_imm64(&prog, X86_REG_R9, (__force long) priv_frame_ptr >> 32,
1429+
(u32) (__force long) priv_frame_ptr);
1430+
1431+
#ifdef CONFIG_SMP
1432+
/* add <r9>, gs:[<off>] */
1433+
EMIT2(0x65, 0x4c);
1434+
EMIT3(0x03, 0x0c, 0x25);
1435+
EMIT((u32)(unsigned long)&this_cpu_off, 4);
1436+
#endif
1437+
1438+
*pprog = prog;
1439+
}
1440+
14071441
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
14081442

14091443
#define __LOAD_TCC_PTR(off) \
@@ -1421,6 +1455,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
14211455
int insn_cnt = bpf_prog->len;
14221456
bool seen_exit = false;
14231457
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
1458+
void __percpu *priv_frame_ptr = NULL;
14241459
u64 arena_vm_start, user_vm_start;
14251460
int i, excnt = 0;
14261461
int ilen, proglen = 0;
@@ -1429,6 +1464,10 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
14291464
int err;
14301465

14311466
stack_depth = bpf_prog->aux->stack_depth;
1467+
if (bpf_prog->aux->priv_stack_ptr) {
1468+
priv_frame_ptr = bpf_prog->aux->priv_stack_ptr + round_up(stack_depth, 16);
1469+
stack_depth = 0;
1470+
}
14321471

14331472
arena_vm_start = bpf_arena_get_kern_vm_start(bpf_prog->aux->arena);
14341473
user_vm_start = bpf_arena_get_user_vm_start(bpf_prog->aux->arena);
@@ -1457,6 +1496,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
14571496
emit_mov_imm64(&prog, X86_REG_R12,
14581497
arena_vm_start >> 32, (u32) arena_vm_start);
14591498

1499+
if (priv_frame_ptr)
1500+
emit_priv_frame_ptr(&prog, priv_frame_ptr);
1501+
14601502
ilen = prog - temp;
14611503
if (rw_image)
14621504
memcpy(rw_image + proglen, temp, ilen);
@@ -1476,6 +1518,14 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
14761518
u8 *func;
14771519
int nops;
14781520

1521+
if (priv_frame_ptr) {
1522+
if (src_reg == BPF_REG_FP)
1523+
src_reg = X86_REG_R9;
1524+
1525+
if (dst_reg == BPF_REG_FP)
1526+
dst_reg = X86_REG_R9;
1527+
}
1528+
14791529
switch (insn->code) {
14801530
/* ALU */
14811531
case BPF_ALU | BPF_ADD | BPF_X:
@@ -2136,9 +2186,15 @@ st: if (is_imm8(insn->off))
21362186
}
21372187
if (!imm32)
21382188
return -EINVAL;
2189+
if (priv_frame_ptr) {
2190+
push_r9(&prog);
2191+
ip += 2;
2192+
}
21392193
ip += x86_call_depth_emit_accounting(&prog, func, ip);
21402194
if (emit_call(&prog, func, ip))
21412195
return -EINVAL;
2196+
if (priv_frame_ptr)
2197+
pop_r9(&prog);
21422198
break;
21432199
}
21442200

@@ -3323,6 +3379,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
33233379
struct bpf_binary_header *rw_header = NULL;
33243380
struct bpf_binary_header *header = NULL;
33253381
struct bpf_prog *tmp, *orig_prog = prog;
3382+
void __percpu *priv_stack_ptr = NULL;
33263383
struct x64_jit_data *jit_data;
33273384
int proglen, oldproglen = 0;
33283385
struct jit_context ctx = {};
@@ -3359,6 +3416,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
33593416
}
33603417
prog->aux->jit_data = jit_data;
33613418
}
3419+
priv_stack_ptr = prog->aux->priv_stack_ptr;
3420+
if (!priv_stack_ptr && prog->aux->priv_stack_requested) {
3421+
priv_stack_ptr = __alloc_percpu_gfp(prog->aux->stack_depth, 16, GFP_KERNEL);
3422+
if (!priv_stack_ptr) {
3423+
prog = orig_prog;
3424+
goto out_priv_stack;
3425+
}
3426+
prog->aux->priv_stack_ptr = priv_stack_ptr;
3427+
}
33623428
addrs = jit_data->addrs;
33633429
if (addrs) {
33643430
ctx = jit_data->ctx;
@@ -3494,6 +3560,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
34943560
bpf_prog_fill_jited_linfo(prog, addrs + 1);
34953561
out_addrs:
34963562
kvfree(addrs);
3563+
if (!image && priv_stack_ptr) {
3564+
free_percpu(priv_stack_ptr);
3565+
prog->aux->priv_stack_ptr = NULL;
3566+
}
3567+
out_priv_stack:
34973568
kfree(jit_data);
34983569
prog->aux->jit_data = NULL;
34993570
}
@@ -3547,6 +3618,7 @@ void bpf_jit_free(struct bpf_prog *prog)
35473618
prog->bpf_func = (void *)prog->bpf_func - cfi_get_offset();
35483619
hdr = bpf_jit_binary_pack_hdr(prog);
35493620
bpf_jit_binary_pack_free(hdr, NULL);
3621+
free_percpu(prog->aux->priv_stack_ptr);
35503622
WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(prog));
35513623
}
35523624

@@ -3562,6 +3634,11 @@ bool bpf_jit_supports_exceptions(void)
35623634
return IS_ENABLED(CONFIG_UNWINDER_ORC);
35633635
}
35643636

3637+
bool bpf_jit_supports_private_stack(void)
3638+
{
3639+
return true;
3640+
}
3641+
35653642
void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
35663643
{
35673644
#if defined(CONFIG_UNWINDER_ORC)

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,7 @@ struct bpf_prog_aux {
15071507
u32 max_rdwr_access;
15081508
struct btf *attach_btf;
15091509
const struct bpf_ctx_arg_aux *ctx_arg_info;
1510+
void __percpu *priv_stack_ptr;
15101511
struct mutex dst_mutex; /* protects dst_* pointers below, *after* prog becomes visible */
15111512
struct bpf_prog *dst_prog;
15121513
struct bpf_trampoline *dst_trampoline;

0 commit comments

Comments
 (0)