| @@ -221,14 +221,48 @@ struct jit_context { · 220 unmodified lines |
| 221 | 221 | |
| 222 | 222 | /* Number of bytes emit_patch() needs to generate instructions */ |
| 223 | 223 | #define X86_PATCH_SIZE 5 |
| 224 | +/* Number of bytes that will be skipped on tailcall */ |
| 225 | +#define X86_TAIL_CALL_OFFSET 11 |
| 224 | 226 | |
| 225 | | −#define PROLOGUE_SIZE 25 |
| 227 | +static void push_callee_regs(u8 **pprog, bool *callee_regs_used) |
| 228 | +{ |
| 229 | + u8 *prog = *pprog; |
| 230 | + int cnt = 0; |
| 231 | + |
| 232 | + if (callee_regs_used[0]) |
| 233 | + EMIT1(0x53); /* push rbx */ |
| 234 | + if (callee_regs_used[1]) |
| 235 | + EMIT2(0x41, 0x55); /* push r13 */ |
| 236 | + if (callee_regs_used[2]) |
| 237 | + EMIT2(0x41, 0x56); /* push r14 */ |
| 238 | + if (callee_regs_used[3]) |
| 239 | + EMIT2(0x41, 0x57); /* push r15 */ |
| 240 | + *pprog = prog; |
| 241 | +} |
| 242 | + |
| 243 | +static void pop_callee_regs(u8 **pprog, bool *callee_regs_used) |
| 244 | +{ |
| 245 | + u8 *prog = *pprog; |
| 246 | + int cnt = 0; |
| 247 | + |
| 248 | + if (callee_regs_used[3]) |
| 249 | + EMIT2(0x41, 0x5F); /* pop r15 */ |
| 250 | + if (callee_regs_used[2]) |
| 251 | + EMIT2(0x41, 0x5E); /* pop r14 */ |
| 252 | + if (callee_regs_used[1]) |
| 253 | + EMIT2(0x41, 0x5D); /* pop r13 */ |
| 254 | + if (callee_regs_used[0]) |
| 255 | + EMIT1(0x5B); /* pop rbx */ |
| 256 | + *pprog = prog; |
| 257 | +} |
| 226 | 258 | |
| 227 | 259 | /* |
| 228 | | − * Emit x86-64 prologue code for BPF program and check its size. |
| 229 | | − * bpf_tail_call helper will skip it while jumping into another program |
| 260 | + * Emit x86-64 prologue code for BPF program. |
| 261 | + * bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes |
| 262 | + * while jumping to another program |
| 230 | 263 | */ |
| 231 | | −static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf) |
| 264 | +static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf, |
| 265 | + bool tail_call_reachable, bool is_subprog) |
| 232 | 266 | { |
| 233 | 267 | u8 *prog = *pprog; |
| 234 | 268 | int cnt = X86_PATCH_SIZE; |
| @@ -238,19 +272,18 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf) · 3 unmodified lines |
| 238 | 272 | */ |
| 239 | 273 | memcpy(prog, ideal_nops[NOP_ATOMIC5], cnt); |
| 240 | 274 | prog += cnt; |
| 275 | + if (!ebpf_from_cbpf) { |
| 276 | + if (tail_call_reachable && !is_subprog) |
| 277 | + EMIT2(0x31, 0xC0); /* xor eax, eax */ |
| 278 | + else |
| 279 | + EMIT2(0x66, 0x90); /* nop2 */ |
| 280 | + } |
| 241 | 281 | EMIT1(0x55); /* push rbp */ |
| 242 | 282 | EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */ |
| 243 | 283 | /* sub rsp, rounded_stack_depth */ |
| 244 | 284 | EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8)); |
| 245 | | − EMIT1(0x53); /* push rbx */ |
| 246 | | − EMIT2(0x41, 0x55); /* push r13 */ |
| 247 | | − EMIT2(0x41, 0x56); /* push r14 */ |
| 248 | | − EMIT2(0x41, 0x57); /* push r15 */ |
| 249 | | − if (!ebpf_from_cbpf) { |
| 250 | | − /* zero init tail_call_cnt */ |
| 251 | | − EMIT2(0x6a, 0x00); |
| 252 | | − BUILD_BUG_ON(cnt != PROLOGUE_SIZE); |
| 253 | | − } |
| 285 | + if (tail_call_reachable) |
| 286 | + EMIT1(0x50); /* push rax */ |
| 254 | 287 | *pprog = prog; |
| 255 | 288 | } |
| 256 | 289 | |
| @@ -314,13 +347,14 @@ static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, · 57 unmodified lines |
| 314 | 347 | mutex_lock(&text_mutex); |
| 315 | 348 | if (memcmp(ip, old_insn, X86_PATCH_SIZE)) |
| 316 | 349 | goto out; |
| 350 | + ret = 1; |
| 317 | 351 | if (memcmp(ip, new_insn, X86_PATCH_SIZE)) { |
| 318 | 352 | if (text_live) |
| 319 | 353 | text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL); |
| 320 | 354 | else |
| 321 | 355 | memcpy(ip, new_insn, X86_PATCH_SIZE); |
| 356 | + ret = 0; |
| 322 | 357 | } |
| 323 | | − ret = 0; |
| 324 | 358 | out: |
| 325 | 359 | mutex_unlock(&text_mutex); |
| 326 | 360 | return ret; |
| @@ -337,6 +371,22 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, · 10 unmodified lines |
| 337 | 371 | return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true); |
| 338 | 372 | } |
| 339 | 373 | |
| 374 | +static int get_pop_bytes(bool *callee_regs_used) |
| 375 | +{ |
| 376 | + int bytes = 0; |
| 377 | + |
| 378 | + if (callee_regs_used[3]) |
| 379 | + bytes += 2; |
| 380 | + if (callee_regs_used[2]) |
| 381 | + bytes += 2; |
| 382 | + if (callee_regs_used[1]) |
| 383 | + bytes += 2; |
| 384 | + if (callee_regs_used[0]) |
| 385 | + bytes += 1; |
| 386 | + |
| 387 | + return bytes; |
| 388 | +} |
| 389 | + |
| 340 | 390 | /* |
| 341 | 391 | * Generate the following code: |
| 342 | 392 | * |
| @@ -351,12 +401,26 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, · 8 unmodified lines |
| 351 | 401 | * goto *(prog->bpf_func + prologue_size); |
| 352 | 402 | * out: |
| 353 | 403 | */ |
| 354 | | −static void emit_bpf_tail_call_indirect(u8 **pprog) |
| 404 | +static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used, |
| 405 | + u32 stack_depth) |
| 355 | 406 | { |
| 407 | + int tcc_off = -4 - round_up(stack_depth, 8); |
| 356 | 408 | u8 *prog = *pprog; |
| 357 | | − int label1, label2, label3; |
| 409 | + int pop_bytes = 0; |
| 410 | + int off1 = 49; |
| 411 | + int off2 = 38; |
| 412 | + int off3 = 16; |
| 358 | 413 | int cnt = 0; |
| 359 | 414 | |
| 415 | + /* count the additional bytes used for popping callee regs from stack |
| 416 | + * that need to be taken into account for each of the offsets that |
| 417 | + * are used for bailing out of the tail call |
| 418 | + */ |
| 419 | + pop_bytes = get_pop_bytes(callee_regs_used); |
| 420 | + off1 += pop_bytes; |
| 421 | + off2 += pop_bytes; |
| 422 | + off3 += pop_bytes; |
| 423 | + |
| 360 | 424 | /* |
| 361 | 425 | * rdi - pointer to ctx |
| 362 | 426 | * rsi - pointer to bpf_array |
| @@ -370,21 +434,19 @@ static void emit_bpf_tail_call_indirect(u8 **pprog) · 7 unmodified lines |
| 370 | 434 | EMIT2(0x89, 0xD2); /* mov edx, edx */ |
| 371 | 435 | EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */ |
| 372 | 436 | offsetof(struct bpf_array, map.max_entries)); |
| 373 | | −#define OFFSET1 (41 + RETPOLINE_RCX_BPF_JIT_SIZE) /* Number of bytes to jump */ |
| 437 | +#define OFFSET1 (off1 + RETPOLINE_RCX_BPF_JIT_SIZE) /* Number of bytes to jump */ |
| 374 | 438 | EMIT2(X86_JBE, OFFSET1); /* jbe out */ |
| 375 | | − label1 = cnt; |
| 376 | 439 | |
| 377 | 440 | /* |
| 378 | 441 | * if (tail_call_cnt > MAX_TAIL_CALL_CNT) |
| 379 | 442 | * goto out; |
| 380 | 443 | */ |
| 381 | | − EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */ |
| 444 | + EMIT2_off32(0x8B, 0x85, tcc_off); /* mov eax, dword ptr [rbp - tcc_off] */ |
| 382 | 445 | EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */ |
| 383 | | −#define OFFSET2 (30 + RETPOLINE_RCX_BPF_JIT_SIZE) |
| 446 | +#define OFFSET2 (off2 + RETPOLINE_RCX_BPF_JIT_SIZE) |
| 384 | 447 | EMIT2(X86_JA, OFFSET2); /* ja out */ |
| 385 | | − label2 = cnt; |
| 386 | 448 | EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ |
| 387 | | − EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */ |
| 449 | + EMIT2_off32(0x89, 0x85, tcc_off); /* mov dword ptr [rbp - tcc_off], eax */ |
| 388 | 450 | |
| 389 | 451 | /* prog = array->ptrs[index]; */ |
| 390 | 452 | EMIT4_off32(0x48, 0x8B, 0x8C, 0xD6, /* mov rcx, [rsi + rdx * 8 + offsetof(...)] */ |
| @@ -394,48 +456,84 @@ static void emit_bpf_tail_call_indirect(u8 **pprog) · 3 unmodified lines |
| 394 | 456 | * if (prog == NULL) |
| 395 | 457 | * goto out; |
| 396 | 458 | */ |
| 397 | | − EMIT3(0x48, 0x85, 0xC9); /* test rcx,rcx */ |
| 398 | | −#define OFFSET3 (8 + RETPOLINE_RCX_BPF_JIT_SIZE) |
| 459 | + EMIT3(0x48, 0x85, 0xC9); /* test rcx,rcx */ |
| 460 | +#define OFFSET3 (off3 + RETPOLINE_RCX_BPF_JIT_SIZE) |
| 399 | 461 | EMIT2(X86_JE, OFFSET3); /* je out */ |
| 400 | | − label3 = cnt; |
| 401 | 462 | |
| 402 | | − /* goto *(prog->bpf_func + prologue_size); */ |
| 463 | + *pprog = prog; |
| 464 | + pop_callee_regs(pprog, callee_regs_used); |
| 465 | + prog = *pprog; |
| 466 | + |
| 467 | + EMIT1(0x58); /* pop rax */ |
| 468 | + EMIT3_off32(0x48, 0x81, 0xC4, /* add rsp, sd */ |
| 469 | + round_up(stack_depth, 8)); |
| 470 | + |
| 471 | + /* goto *(prog->bpf_func + X86_TAIL_CALL_OFFSET); */ |
| 403 | 472 | EMIT4(0x48, 0x8B, 0x49, /* mov rcx, qword ptr [rcx + 32] */ |
| 404 | 473 | offsetof(struct bpf_prog, bpf_func)); |
| 405 | | − EMIT4(0x48, 0x83, 0xC1, PROLOGUE_SIZE); /* add rcx, prologue_size */ |
| 406 | | − |
| 474 | + EMIT4(0x48, 0x83, 0xC1, /* add rcx, X86_TAIL_CALL_OFFSET */ |
| 475 | + X86_TAIL_CALL_OFFSET); |
| 407 | 476 | /* |
| 408 | 477 | * Now we're ready to jump into next BPF program |
| 409 | 478 | * rdi == ctx (1st arg) |
| 410 | | − * rcx == prog->bpf_func + prologue_size |
| 479 | + * rcx == prog->bpf_func + X86_TAIL_CALL_OFFSET |
| 411 | 480 | */ |
| 412 | 481 | RETPOLINE_RCX_BPF_JIT(); |
| 413 | 482 | |
| 414 | 483 | /* out: */ |
| 415 | | − BUILD_BUG_ON(cnt - label1 != OFFSET1); |
| 416 | | − BUILD_BUG_ON(cnt - label2 != OFFSET2); |
| 417 | | − BUILD_BUG_ON(cnt - label3 != OFFSET3); |
| 418 | 484 | *pprog = prog; |
| 419 | 485 | } |
| 420 | 486 | |
| 421 | 487 | static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke, |
| 422 | | − u8 **pprog, int addr, u8 *image) |
| 488 | + u8 **pprog, int addr, u8 *image, |
| 489 | + bool *callee_regs_used, u32 stack_depth) |
| 423 | 490 | { |
| 491 | + int tcc_off = -4 - round_up(stack_depth, 8); |
| 424 | 492 | u8 *prog = *pprog; |
| 493 | + int pop_bytes = 0; |
| 494 | + int off1 = 27; |
| 495 | + int poke_off; |
| 425 | 496 | int cnt = 0; |
| 426 | 497 | |
| 498 | + /* count the additional bytes used for popping callee regs to stack |
| 499 | + * that need to be taken into account for jump offset that is used for |
| 500 | + * bailing out from of the tail call when limit is reached |
| 501 | + */ |
| 502 | + pop_bytes = get_pop_bytes(callee_regs_used); |
| 503 | + off1 += pop_bytes; |
| 504 | + |
| 505 | + /* |
| 506 | + * total bytes for: |
| 507 | + * - nop5/ jmpq $off |
| 508 | + * - pop callee regs |
| 509 | + * - sub rsp, $val |
| 510 | + * - pop rax |
| 511 | + */ |
| 512 | + poke_off = X86_PATCH_SIZE + pop_bytes + 7 + 1; |
| 513 | + |
| 427 | 514 | /* |
| 428 | 515 | * if (tail_call_cnt > MAX_TAIL_CALL_CNT) |
| 429 | 516 | * goto out; |
| 430 | 517 | */ |
| 431 | | − EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */ |
| 518 | + EMIT2_off32(0x8B, 0x85, tcc_off); /* mov eax, dword ptr [rbp - tcc_off] */ |
| 432 | 519 | EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */ |
| 433 | | − EMIT2(X86_JA, 14); /* ja out */ |
| 520 | + EMIT2(X86_JA, off1); /* ja out */ |
| 434 | 521 | EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ |
| 435 | | − EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */ |
| 522 | + EMIT2_off32(0x89, 0x85, tcc_off); /* mov dword ptr [rbp - tcc_off], eax */ |
| 436 | 523 | |
| 524 | + poke->tailcall_bypass = image + (addr - poke_off - X86_PATCH_SIZE); |
| 525 | + poke->adj_off = X86_TAIL_CALL_OFFSET; |
| 437 | 526 | poke->tailcall_target = image + (addr - X86_PATCH_SIZE); |
| 438 | | − poke->adj_off = PROLOGUE_SIZE; |
| 527 | + poke->bypass_addr = (u8 *)poke->tailcall_target + X86_PATCH_SIZE; |
| 528 | + |
| 529 | + emit_jump(&prog, (u8 *)poke->tailcall_target + X86_PATCH_SIZE, |
| 530 | + poke->tailcall_bypass); |
| 531 | + |
| 532 | + *pprog = prog; |
| 533 | + pop_callee_regs(pprog, callee_regs_used); |
| 534 | + prog = *pprog; |
| 535 | + EMIT1(0x58); /* pop rax */ |
| 536 | + EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8)); |
| 439 | 537 | |
| 440 | 538 | memcpy(prog, ideal_nops[NOP_ATOMIC5], X86_PATCH_SIZE); |
| 441 | 539 | prog += X86_PATCH_SIZE; |
| @@ -476,6 +574,11 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog) · 34 unmodified lines |
| 476 | 574 | (u8 *)target->bpf_func + |
| 477 | 575 | poke->adj_off, false); |
| 478 | 576 | BUG_ON(ret < 0); |
| 577 | + ret = __bpf_arch_text_poke(poke->tailcall_bypass, |
| 578 | + BPF_MOD_JUMP, |
| 579 | + (u8 *)poke->tailcall_target + |
| 580 | + X86_PATCH_SIZE, NULL, false); |
| 581 | + BUG_ON(ret < 0); |
| 479 | 582 | } |
| 480 | 583 | WRITE_ONCE(poke->tailcall_target_stable, true); |
| 481 | 584 | mutex_unlock(&array->aux->poke_mutex); |
| @@ -654,19 +757,49 @@ static bool ex_handler_bpf(const struct exception_table_entry *x, · 172 unmodified lines |
| 654 | 757 | return true; |
| 655 | 758 | } |
| 656 | 759 | |
| 760 | +static void detect_reg_usage(struct bpf_insn *insn, int insn_cnt, |
| 761 | + bool *regs_used, bool *tail_call_seen) |
| 762 | +{ |
| 763 | + int i; |
| 764 | + |
| 765 | + for (i = 1; i <= insn_cnt; i++, insn++) { |
| 766 | + if (insn->code == (BPF_JMP | BPF_TAIL_CALL)) |
| 767 | + *tail_call_seen = true; |
| 768 | + if (insn->dst_reg == BPF_REG_6 || insn->src_reg == BPF_REG_6) |
| 769 | + regs_used[0] = true; |
| 770 | + if (insn->dst_reg == BPF_REG_7 || insn->src_reg == BPF_REG_7) |
| 771 | + regs_used[1] = true; |
| 772 | + if (insn->dst_reg == BPF_REG_8 || insn->src_reg == BPF_REG_8) |
| 773 | + regs_used[2] = true; |
| 774 | + if (insn->dst_reg == BPF_REG_9 || insn->src_reg == BPF_REG_9) |
| 775 | + regs_used[3] = true; |
| 776 | + } |
| 777 | +} |
| 778 | + |
| 657 | 779 | static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, |
| 658 | 780 | int oldproglen, struct jit_context *ctx) |
| 659 | 781 | { |
| 782 | + bool tail_call_reachable = bpf_prog->aux->tail_call_reachable; |
| 660 | 783 | struct bpf_insn *insn = bpf_prog->insnsi; |
| 784 | + bool callee_regs_used[4] = {}; |
| 661 | 785 | int insn_cnt = bpf_prog->len; |
| 786 | + bool tail_call_seen = false; |
| 662 | 787 | bool seen_exit = false; |
| 663 | 788 | u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY]; |
| 664 | 789 | int i, cnt = 0, excnt = 0; |
| 665 | 790 | int proglen = 0; |
| 666 | 791 | u8 *prog = temp; |
| 667 | 792 | |
| 793 | + detect_reg_usage(insn, insn_cnt, callee_regs_used, |
| 794 | + &tail_call_seen); |
| 795 | + |
| 796 | + /* tail call's presence in current prog implies it is reachable */ |
| 797 | + tail_call_reachable |= tail_call_seen; |
| 798 | + |
| 668 | 799 | emit_prologue(&prog, bpf_prog->aux->stack_depth, |
| 669 | | − bpf_prog_was_classic(bpf_prog)); |
| 800 | + bpf_prog_was_classic(bpf_prog), tail_call_reachable, |
| 801 | + bpf_prog->aux->func_idx != 0); |
| 802 | + push_callee_regs(&prog, callee_regs_used); |
| 670 | 803 | addrs[0] = prog - temp; |
| 671 | 804 | |
| 672 | 805 | for (i = 1; i <= insn_cnt; i++, insn++) { |
| @@ -1104,16 +1237,27 @@ xadd: if (is_imm8(insn->off)) · 431 unmodified lines |
| 1104 | 1237 | /* call */ |
| 1105 | 1238 | case BPF_JMP | BPF_CALL: |
| 1106 | 1239 | func = (u8 *) __bpf_call_base + imm32; |
| 1107 | | − if (!imm32 || emit_call(&prog, func, image + addrs[i - 1])) |
| 1108 | | − return -EINVAL; |
| 1240 | + if (tail_call_reachable) { |
| 1241 | + EMIT3_off32(0x48, 0x8B, 0x85, |
| 1242 | + -(bpf_prog->aux->stack_depth + 8)); |
| 1243 | + if (!imm32 || emit_call(&prog, func, image + addrs[i - 1] + 7)) |
| 1244 | + return -EINVAL; |
| 1245 | + } else { |
| 1246 | + if (!imm32 || emit_call(&prog, func, image + addrs[i - 1])) |
| 1247 | + return -EINVAL; |
| 1248 | + } |
| 1109 | 1249 | break; |
| 1110 | 1250 | |
| 1111 | 1251 | case BPF_JMP | BPF_TAIL_CALL: |
| 1112 | 1252 | if (imm32) |
| 1113 | 1253 | emit_bpf_tail_call_direct(&bpf_prog->aux->poke_tab[imm32 - 1], |
| 1114 | | − &prog, addrs[i], image); |
| 1254 | + &prog, addrs[i], image, |
| 1255 | + callee_regs_used, |
| 1256 | + bpf_prog->aux->stack_depth); |
| 1115 | 1257 | else |
| 1116 | | − emit_bpf_tail_call_indirect(&prog); |
| 1258 | + emit_bpf_tail_call_indirect(&prog, |
| 1259 | + callee_regs_used, |
| 1260 | + bpf_prog->aux->stack_depth); |
| 1117 | 1261 | break; |
| 1118 | 1262 | |
| 1119 | 1263 | /* cond jump */ |
| @@ -1296,12 +1440,9 @@ emit_jmp: · 176 unmodified lines |
| 1296 | 1440 | seen_exit = true; |
| 1297 | 1441 | /* Update cleanup_addr */ |
| 1298 | 1442 | ctx->cleanup_addr = proglen; |
| 1299 | | − if (!bpf_prog_was_classic(bpf_prog)) |
| 1300 | | − EMIT1(0x5B); /* get rid of tail_call_cnt */ |
| 1301 | | − EMIT2(0x41, 0x5F); /* pop r15 */ |
| 1302 | | − EMIT2(0x41, 0x5E); /* pop r14 */ |
| 1303 | | − EMIT2(0x41, 0x5D); /* pop r13 */ |
| 1304 | | − EMIT1(0x5B); /* pop rbx */ |
| 1443 | + pop_callee_regs(&prog, callee_regs_used); |
| 1444 | + if (tail_call_reachable) |
| 1445 | + EMIT1(0x59); /* pop rcx, get rid of tail_call_cnt */ |
| 1305 | 1446 | EMIT1(0xC9); /* leave */ |
| 1306 | 1447 | EMIT1(0xC3); /* ret */ |
| 1307 | 1448 | break; |