Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/x86/net/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 106 kB image not shown  

Quelle  bpf_jit_comp.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * BPF JIT compiler
 *
 * Copyright (C) 2011-2013 Eric Dumazet (eric.dumazet@gmail.com)
 * Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
 */

#include <linux/netdevice.h>
#include <linux/filter.h>
#include <linux/if_vlan.h>
#include <linux/bpf.h>
#include <linux/memory.h>
#include <linux/sort.h>
#include <asm/extable.h>
#include <asm/ftrace.h>
#include <asm/set_memory.h>
#include <asm/nospec-branch.h>
#include <asm/text-patching.h>
#include <asm/unwind.h>
#include <asm/cfi.h>

static bool all_callee_regs_used[4] = {truetruetruetrue};

static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
{
 if (len == 1)
  *ptr = bytes;
 else if (len == 2)
  *(u16 *)ptr = bytes;
 else {
  *(u32 *)ptr = bytes;
  barrier();
 }
 return ptr + len;
}

#define EMIT(bytes, len) \
 do { prog = emit_code(prog, bytes, len); } while (0)

#define EMIT1(b1)  EMIT(b1, 1)
#define EMIT2(b1, b2)  EMIT((b1) + ((b2) << 8), 2)
#define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3)
#define EMIT4(b1, b2, b3, b4)   EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4)
#define EMIT5(b1, b2, b3, b4, b5) \
 do { EMIT1(b1); EMIT4(b2, b3, b4, b5); } while (0)

#define EMIT1_off32(b1, off) \
 do { EMIT1(b1); EMIT(off, 4); } while (0)
#define EMIT2_off32(b1, b2, off) \
 do { EMIT2(b1, b2); EMIT(off, 4); } while (0)
#define EMIT3_off32(b1, b2, b3, off) \
 do { EMIT3(b1, b2, b3); EMIT(off, 4); } while (0)
#define EMIT4_off32(b1, b2, b3, b4, off) \
 do { EMIT4(b1, b2, b3, b4); EMIT(off, 4); } while (0)

#ifdef CONFIG_X86_KERNEL_IBT
#define EMIT_ENDBR()  EMIT(gen_endbr(), 4)
#define EMIT_ENDBR_POISON() EMIT(gen_endbr_poison(), 4)
#else
#define EMIT_ENDBR()
#define EMIT_ENDBR_POISON()
#endif

static bool is_imm8(int value)
{
 return value <= 127 && value >= -128;
}

/*
 * Let us limit the positive offset to be <= 123.
 * This is to ensure eventual jit convergence For the following patterns:
 * ...
 * pass4, final_proglen=4391:
 *   ...
 *   20e:    48 85 ff                test   rdi,rdi
 *   211:    74 7d                   je     0x290
 *   213:    48 8b 77 00             mov    rsi,QWORD PTR [rdi+0x0]
 *   ...
 *   289:    48 85 ff                test   rdi,rdi
 *   28c:    74 17                   je     0x2a5
 *   28e:    e9 7f ff ff ff          jmp    0x212
 *   293:    bf 03 00 00 00          mov    edi,0x3
 * Note that insn at 0x211 is 2-byte cond jump insn for offset 0x7d (-125)
 * and insn at 0x28e is 5-byte jmp insn with offset -129.
 *
 * pass5, final_proglen=4392:
 *   ...
 *   20e:    48 85 ff                test   rdi,rdi
 *   211:    0f 84 80 00 00 00       je     0x297
 *   217:    48 8b 77 00             mov    rsi,QWORD PTR [rdi+0x0]
 *   ...
 *   28d:    48 85 ff                test   rdi,rdi
 *   290:    74 1a                   je     0x2ac
 *   292:    eb 84                   jmp    0x218
 *   294:    bf 03 00 00 00          mov    edi,0x3
 * Note that insn at 0x211 is 6-byte cond jump insn now since its offset
 * becomes 0x80 based on previous round (0x293 - 0x213 = 0x80).
 * At the same time, insn at 0x292 is a 2-byte insn since its offset is
 * -124.
 *
 * pass6 will repeat the same code as in pass4 and this will prevent
 * eventual convergence.
 *
 * To fix this issue, we need to break je (2->6 bytes) <-> jmp (5->2 bytes)
 * cycle in the above. In the above example je offset <= 0x7c should work.
 *
 * For other cases, je <-> je needs offset <= 0x7b to avoid no convergence
 * issue. For jmp <-> je and jmp <-> jmp cases, jmp offset <= 0x7c should
 * avoid no convergence issue.
 *
 * Overall, let us limit the positive offset for 8bit cond/uncond jmp insn
 * to maximum 123 (0x7b). This way, the jit pass can eventually converge.
 */

static bool is_imm8_jmp_offset(int value)
{
 return value <= 123 && value >= -128;
}

static bool is_simm32(s64 value)
{
 return value == (s64)(s32)value;
}

static bool is_uimm32(u64 value)
{
 return value == (u64)(u32)value;
}

/* mov dst, src */
#define EMIT_mov(DST, SRC)         \
 do {           \
  if (DST != SRC)         \
   EMIT3(add_2mod(0x48, DST, SRC), 0x89, add_2reg(0xC0, DST, SRC)); \
 } while (0)

static int bpf_size_to_x86_bytes(int bpf_size)
{
 if (bpf_size == BPF_W)
  return 4;
 else if (bpf_size == BPF_H)
  return 2;
 else if (bpf_size == BPF_B)
  return 1;
 else if (bpf_size == BPF_DW)
  return 4; /* imm32 */
 else
  return 0;
}

/*
 * List of x86 cond jumps opcodes (. + s8)
 * Add 0x10 (and an extra 0x0f) to generate far jumps (. + s32)
 */

#define X86_JB  0x72
#define X86_JAE 0x73
#define X86_JE  0x74
#define X86_JNE 0x75
#define X86_JBE 0x76
#define X86_JA  0x77
#define X86_JL  0x7C
#define X86_JGE 0x7D
#define X86_JLE 0x7E
#define X86_JG  0x7F

/* Pick a register outside of BPF range for JIT internal work */
#define AUX_REG (MAX_BPF_JIT_REG + 1)
#define X86_REG_R9 (MAX_BPF_JIT_REG + 2)
#define X86_REG_R12 (MAX_BPF_JIT_REG + 3)

/*
 * The following table maps BPF registers to x86-64 registers.
 *
 * x86-64 register R12 is unused, since if used as base address
 * register in load/store instructions, it always needs an
 * extra byte of encoding and is callee saved.
 *
 * x86-64 register R9 is not used by BPF programs, but can be used by BPF
 * trampoline. x86-64 register R10 is used for blinding (if enabled).
 */

static const int reg2hex[] = {
 [BPF_REG_0] = 0,  /* RAX */
 [BPF_REG_1] = 7,  /* RDI */
 [BPF_REG_2] = 6,  /* RSI */
 [BPF_REG_3] = 2,  /* RDX */
 [BPF_REG_4] = 1,  /* RCX */
 [BPF_REG_5] = 0,  /* R8  */
 [BPF_REG_6] = 3,  /* RBX callee saved */
 [BPF_REG_7] = 5,  /* R13 callee saved */
 [BPF_REG_8] = 6,  /* R14 callee saved */
 [BPF_REG_9] = 7,  /* R15 callee saved */
 [BPF_REG_FP] = 5, /* RBP readonly */
 [BPF_REG_AX] = 2, /* R10 temp register */
 [AUX_REG] = 3,    /* R11 temp register */
 [X86_REG_R9] = 1, /* R9 register, 6th function argument */
 [X86_REG_R12] = 4, /* R12 callee saved */
};

static const int reg2pt_regs[] = {
 [BPF_REG_0] = offsetof(struct pt_regs, ax),
 [BPF_REG_1] = offsetof(struct pt_regs, di),
 [BPF_REG_2] = offsetof(struct pt_regs, si),
 [BPF_REG_3] = offsetof(struct pt_regs, dx),
 [BPF_REG_4] = offsetof(struct pt_regs, cx),
 [BPF_REG_5] = offsetof(struct pt_regs, r8),
 [BPF_REG_6] = offsetof(struct pt_regs, bx),
 [BPF_REG_7] = offsetof(struct pt_regs, r13),
 [BPF_REG_8] = offsetof(struct pt_regs, r14),
 [BPF_REG_9] = offsetof(struct pt_regs, r15),
};

/*
 * is_ereg() == true if BPF register 'reg' maps to x86-64 r8..r15
 * which need extra byte of encoding.
 * rax,rcx,...,rbp have simpler encoding
 */

static bool is_ereg(u32 reg)
{
 return (1 << reg) & (BIT(BPF_REG_5) |
        BIT(AUX_REG) |
        BIT(BPF_REG_7) |
        BIT(BPF_REG_8) |
        BIT(BPF_REG_9) |
        BIT(X86_REG_R9) |
        BIT(X86_REG_R12) |
        BIT(BPF_REG_AX));
}

/*
 * is_ereg_8l() == true if BPF register 'reg' is mapped to access x86-64
 * lower 8-bit registers dil,sil,bpl,spl,r8b..r15b, which need extra byte
 * of encoding. al,cl,dl,bl have simpler encoding.
 */

static bool is_ereg_8l(u32 reg)
{
 return is_ereg(reg) ||
     (1 << reg) & (BIT(BPF_REG_1) |
     BIT(BPF_REG_2) |
     BIT(BPF_REG_FP));
}

static bool is_axreg(u32 reg)
{
 return reg == BPF_REG_0;
}

/* Add modifiers if 'reg' maps to x86-64 registers R8..R15 */
static u8 add_1mod(u8 byte, u32 reg)
{
 if (is_ereg(reg))
  byte |= 1;
 return byte;
}

static u8 add_2mod(u8 byte, u32 r1, u32 r2)
{
 if (is_ereg(r1))
  byte |= 1;
 if (is_ereg(r2))
  byte |= 4;
 return byte;
}

static u8 add_3mod(u8 byte, u32 r1, u32 r2, u32 index)
{
 if (is_ereg(r1))
  byte |= 1;
 if (is_ereg(index))
  byte |= 2;
 if (is_ereg(r2))
  byte |= 4;
 return byte;
}

/* Encode 'dst_reg' register into x86-64 opcode 'byte' */
static u8 add_1reg(u8 byte, u32 dst_reg)
{
 return byte + reg2hex[dst_reg];
}

/* Encode 'dst_reg' and 'src_reg' registers into x86-64 opcode 'byte' */
static u8 add_2reg(u8 byte, u32 dst_reg, u32 src_reg)
{
 return byte + reg2hex[dst_reg] + (reg2hex[src_reg] << 3);
}

/* Some 1-byte opcodes for binary ALU operations */
static u8 simple_alu_opcodes[] = {
 [BPF_ADD] = 0x01,
 [BPF_SUB] = 0x29,
 [BPF_AND] = 0x21,
 [BPF_OR] = 0x09,
 [BPF_XOR] = 0x31,
 [BPF_LSH] = 0xE0,
 [BPF_RSH] = 0xE8,
 [BPF_ARSH] = 0xF8,
};

static void jit_fill_hole(void *area, unsigned int size)
{
 /* Fill whole space with INT3 instructions */
 memset(area, 0xcc, size);
}

int bpf_arch_text_invalidate(void *dst, size_t len)
{
 return IS_ERR_OR_NULL(text_poke_set(dst, 0xcc, len));
}

struct jit_context {
 int cleanup_addr; /* Epilogue code offset */

 /*
 * Program specific offsets of labels in the code; these rely on the
 * JIT doing at least 2 passes, recording the position on the first
 * pass, only to generate the correct offset on the second pass.
 */

 int tail_call_direct_label;
 int tail_call_indirect_label;
};

/* Maximum number of bytes emitted while JITing one eBPF insn */
#define BPF_MAX_INSN_SIZE 128
#define BPF_INSN_SAFETY  64

/* Number of bytes emit_patch() needs to generate instructions */
#define X86_PATCH_SIZE  5
/* Number of bytes that will be skipped on tailcall */
#define X86_TAIL_CALL_OFFSET (12 + ENDBR_INSN_SIZE)

static void push_r9(u8 **pprog)
{
 u8 *prog = *pprog;

 EMIT2(0x41, 0x51);   /* push r9 */
 *pprog = prog;
}

static void pop_r9(u8 **pprog)
{
 u8 *prog = *pprog;

 EMIT2(0x41, 0x59);   /* pop r9 */
 *pprog = prog;
}

static void push_r12(u8 **pprog)
{
 u8 *prog = *pprog;

 EMIT2(0x41, 0x54);   /* push r12 */
 *pprog = prog;
}

static void push_callee_regs(u8 **pprog, bool *callee_regs_used)
{
 u8 *prog = *pprog;

 if (callee_regs_used[0])
  EMIT1(0x53);         /* push rbx */
 if (callee_regs_used[1])
  EMIT2(0x41, 0x55);   /* push r13 */
 if (callee_regs_used[2])
  EMIT2(0x41, 0x56);   /* push r14 */
 if (callee_regs_used[3])
  EMIT2(0x41, 0x57);   /* push r15 */
 *pprog = prog;
}

static void pop_r12(u8 **pprog)
{
 u8 *prog = *pprog;

 EMIT2(0x41, 0x5C);   /* pop r12 */
 *pprog = prog;
}

static void pop_callee_regs(u8 **pprog, bool *callee_regs_used)
{
 u8 *prog = *pprog;

 if (callee_regs_used[3])
  EMIT2(0x41, 0x5F);   /* pop r15 */
 if (callee_regs_used[2])
  EMIT2(0x41, 0x5E);   /* pop r14 */
 if (callee_regs_used[1])
  EMIT2(0x41, 0x5D);   /* pop r13 */
 if (callee_regs_used[0])
  EMIT1(0x5B);         /* pop rbx */
 *pprog = prog;
}

static void emit_nops(u8 **pprog, int len)
{
 u8 *prog = *pprog;
 int i, noplen;

 while (len > 0) {
  noplen = len;

  if (noplen > ASM_NOP_MAX)
   noplen = ASM_NOP_MAX;

  for (i = 0; i < noplen; i++)
   EMIT1(x86_nops[noplen][i]);
  len -= noplen;
 }

 *pprog = prog;
}

/*
 * Emit the various CFI preambles, see asm/cfi.h and the comments about FineIBT
 * in arch/x86/kernel/alternative.c
 */

static int emit_call(u8 **prog, void *func, void *ip);

static void emit_fineibt(u8 **pprog, u8 *ip, u32 hash, int arity)
{
 u8 *prog = *pprog;

 EMIT_ENDBR();
 EMIT3_off32(0x41, 0x81, 0xea, hash);  /* subl $hash, %r10d */
 if (cfi_bhi) {
  emit_call(&prog, __bhi_args[arity], ip + 11);
 } else {
  EMIT2(0x75, 0xf9);   /* jne.d8 .-7 */
  EMIT3(0x0f, 0x1f, 0x00);  /* nop3 */
 }
 EMIT_ENDBR_POISON();

 *pprog = prog;
}

static void emit_kcfi(u8 **pprog, u32 hash)
{
 u8 *prog = *pprog;

 EMIT1_off32(0xb8, hash);   /* movl $hash, %eax */
#ifdef CONFIG_CALL_PADDING
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
 EMIT1(0x90);
#endif
 EMIT_ENDBR();

 *pprog = prog;
}

static void emit_cfi(u8 **pprog, u8 *ip, u32 hash, int arity)
{
 u8 *prog = *pprog;

 switch (cfi_mode) {
 case CFI_FINEIBT:
  emit_fineibt(&prog, ip, hash, arity);
  break;

 case CFI_KCFI:
  emit_kcfi(&prog, hash);
  break;

 default:
  EMIT_ENDBR();
  break;
 }

 *pprog = prog;
}

static void emit_prologue_tail_call(u8 **pprog, bool is_subprog)
{
 u8 *prog = *pprog;

 if (!is_subprog) {
  /* cmp rax, MAX_TAIL_CALL_CNT */
  EMIT4(0x48, 0x83, 0xF8, MAX_TAIL_CALL_CNT);
  EMIT2(X86_JA, 6);        /* ja 6 */
  /* rax is tail_call_cnt if <= MAX_TAIL_CALL_CNT.
 * case1: entry of main prog.
 * case2: tail callee of main prog.
 */

  EMIT1(0x50);             /* push rax */
  /* Make rax as tail_call_cnt_ptr. */
  EMIT3(0x48, 0x89, 0xE0); /* mov rax, rsp */
  EMIT2(0xEB, 1);          /* jmp 1 */
  /* rax is tail_call_cnt_ptr if > MAX_TAIL_CALL_CNT.
 * case: tail callee of subprog.
 */

  EMIT1(0x50);             /* push rax */
  /* push tail_call_cnt_ptr */
  EMIT1(0x50);             /* push rax */
 } else { /* is_subprog */
  /* rax is tail_call_cnt_ptr. */
  EMIT1(0x50);             /* push rax */
  EMIT1(0x50);             /* push rax */
 }

 *pprog = prog;
}

/*
 * Emit x86-64 prologue code for BPF program.
 * bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes
 * while jumping to another program
 */

static void emit_prologue(u8 **pprog, u8 *ip, u32 stack_depth, bool ebpf_from_cbpf,
     bool tail_call_reachable, bool is_subprog,
     bool is_exception_cb)
{
 u8 *prog = *pprog;

 if (is_subprog) {
  emit_cfi(&prog, ip, cfi_bpf_subprog_hash, 5);
 } else {
  emit_cfi(&prog, ip, cfi_bpf_hash, 1);
 }
 /* BPF trampoline can be made to work without these nops,
 * but let's waste 5 bytes for now and optimize later
 */

 emit_nops(&prog, X86_PATCH_SIZE);
 if (!ebpf_from_cbpf) {
  if (tail_call_reachable && !is_subprog)
   /* When it's the entry of the whole tailcall context,
 * zeroing rax means initialising tail_call_cnt.
 */

   EMIT3(0x48, 0x31, 0xC0); /* xor rax, rax */
  else
   /* Keep the same instruction layout. */
   emit_nops(&prog, 3);     /* nop3 */
 }
 /* Exception callback receives FP as third parameter */
 if (is_exception_cb) {
  EMIT3(0x48, 0x89, 0xF4); /* mov rsp, rsi */
  EMIT3(0x48, 0x89, 0xD5); /* mov rbp, rdx */
  /* The main frame must have exception_boundary as true, so we
 * first restore those callee-saved regs from stack, before
 * reusing the stack frame.
 */

  pop_callee_regs(&prog, all_callee_regs_used);
  pop_r12(&prog);
  /* Reset the stack frame. */
  EMIT3(0x48, 0x89, 0xEC); /* mov rsp, rbp */
 } else {
  EMIT1(0x55);             /* push rbp */
  EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
 }

 /* X86_TAIL_CALL_OFFSET is here */
 EMIT_ENDBR();

 /* sub rsp, rounded_stack_depth */
 if (stack_depth)
  EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8));
 if (tail_call_reachable)
  emit_prologue_tail_call(&prog, is_subprog);
 *pprog = prog;
}

static int emit_patch(u8 **pprog, void *func, void *ip, u8 opcode)
{
 u8 *prog = *pprog;
 s64 offset;

 offset = func - (ip + X86_PATCH_SIZE);
 if (!is_simm32(offset)) {
  pr_err("Target call %p is out of range\n", func);
  return -ERANGE;
 }
 EMIT1_off32(opcode, offset);
 *pprog = prog;
 return 0;
}

static int emit_call(u8 **pprog, void *func, void *ip)
{
 return emit_patch(pprog, func, ip, 0xE8);
}

static int emit_rsb_call(u8 **pprog, void *func, void *ip)
{
 OPTIMIZER_HIDE_VAR(func);
 ip += x86_call_depth_emit_accounting(pprog, func, ip);
 return emit_patch(pprog, func, ip, 0xE8);
}

static int emit_jump(u8 **pprog, void *func, void *ip)
{
 return emit_patch(pprog, func, ip, 0xE9);
}

static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
    void *old_addr, void *new_addr)
{
 const u8 *nop_insn = x86_nops[5];
 u8 old_insn[X86_PATCH_SIZE];
 u8 new_insn[X86_PATCH_SIZE];
 u8 *prog;
 int ret;

 memcpy(old_insn, nop_insn, X86_PATCH_SIZE);
 if (old_addr) {
  prog = old_insn;
  ret = t == BPF_MOD_CALL ?
        emit_call(&prog, old_addr, ip) :
        emit_jump(&prog, old_addr, ip);
  if (ret)
   return ret;
 }

 memcpy(new_insn, nop_insn, X86_PATCH_SIZE);
 if (new_addr) {
  prog = new_insn;
  ret = t == BPF_MOD_CALL ?
        emit_call(&prog, new_addr, ip) :
        emit_jump(&prog, new_addr, ip);
  if (ret)
   return ret;
 }

 ret = -EBUSY;
 mutex_lock(&text_mutex);
 if (memcmp(ip, old_insn, X86_PATCH_SIZE))
  goto out;
 ret = 1;
 if (memcmp(ip, new_insn, X86_PATCH_SIZE)) {
  smp_text_poke_single(ip, new_insn, X86_PATCH_SIZE, NULL);
  ret = 0;
 }
out:
 mutex_unlock(&text_mutex);
 return ret;
}

int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
         void *old_addr, void *new_addr)
{
 if (!is_kernel_text((long)ip) &&
     !is_bpf_text_address((long)ip))
  /* BPF poking in modules is not supported */
  return -EINVAL;

 /*
 * See emit_prologue(), for IBT builds the trampoline hook is preceded
 * with an ENDBR instruction.
 */

 if (is_endbr(ip))
  ip += ENDBR_INSN_SIZE;

 return __bpf_arch_text_poke(ip, t, old_addr, new_addr);
}

#define EMIT_LFENCE() EMIT3(0x0F, 0xAE, 0xE8)

static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
{
 u8 *prog = *pprog;

 if (cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) {
  OPTIMIZER_HIDE_VAR(reg);
  emit_jump(&prog, its_static_thunk(reg), ip);
 } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
  EMIT_LFENCE();
  EMIT2(0xFF, 0xE0 + reg);
 } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
  OPTIMIZER_HIDE_VAR(reg);
  if (cpu_feature_enabled(X86_FEATURE_CALL_DEPTH))
   emit_jump(&prog, &__x86_indirect_jump_thunk_array[reg], ip);
  else
   emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
 } else {
  EMIT2(0xFF, 0xE0 + reg); /* jmp *%\reg */
  if (IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) || IS_ENABLED(CONFIG_MITIGATION_SLS))
   EMIT1(0xCC);  /* int3 */
 }

 *pprog = prog;
}

static void emit_return(u8 **pprog, u8 *ip)
{
 u8 *prog = *pprog;

 if (cpu_wants_rethunk()) {
  emit_jump(&prog, x86_return_thunk, ip);
 } else {
  EMIT1(0xC3);  /* ret */
  if (IS_ENABLED(CONFIG_MITIGATION_SLS))
   EMIT1(0xCC); /* int3 */
 }

 *pprog = prog;
}

#define BPF_TAIL_CALL_CNT_PTR_STACK_OFF(stack) (-16 - round_up(stack, 8))

/*
 * Generate the following code:
 *
 * ... bpf_tail_call(void *ctx, struct bpf_array *array, u64 index) ...
 *   if (index >= array->map.max_entries)
 *     goto out;
 *   if ((*tcc_ptr)++ >= MAX_TAIL_CALL_CNT)
 *     goto out;
 *   prog = array->ptrs[index];
 *   if (prog == NULL)
 *     goto out;
 *   goto *(prog->bpf_func + prologue_size);
 * out:
 */

static void emit_bpf_tail_call_indirect(struct bpf_prog *bpf_prog,
     u8 **pprog, bool *callee_regs_used,
     u32 stack_depth, u8 *ip,
     struct jit_context *ctx)
{
 int tcc_ptr_off = BPF_TAIL_CALL_CNT_PTR_STACK_OFF(stack_depth);
 u8 *prog = *pprog, *start = *pprog;
 int offset;

 /*
 * rdi - pointer to ctx
 * rsi - pointer to bpf_array
 * rdx - index in bpf_array
 */


 /*
 * if (index >= array->map.max_entries)
 * goto out;
 */

 EMIT2(0x89, 0xD2);                        /* mov edx, edx */
 EMIT3(0x39, 0x56,                         /* cmp dword ptr [rsi + 16], edx */
       offsetof(struct bpf_array, map.max_entries));

 offset = ctx->tail_call_indirect_label - (prog + 2 - start);
 EMIT2(X86_JBE, offset);                   /* jbe out */

 /*
 * if ((*tcc_ptr)++ >= MAX_TAIL_CALL_CNT)
 * goto out;
 */

 EMIT3_off32(0x48, 0x8B, 0x85, tcc_ptr_off); /* mov rax, qword ptr [rbp - tcc_ptr_off] */
 EMIT4(0x48, 0x83, 0x38, MAX_TAIL_CALL_CNT); /* cmp qword ptr [rax], MAX_TAIL_CALL_CNT */

 offset = ctx->tail_call_indirect_label - (prog + 2 - start);
 EMIT2(X86_JAE, offset);                   /* jae out */

 /* prog = array->ptrs[index]; */
 EMIT4_off32(0x48, 0x8B, 0x8C, 0xD6,       /* mov rcx, [rsi + rdx * 8 + offsetof(...)] */
      offsetof(struct bpf_array, ptrs));

 /*
 * if (prog == NULL)
 * goto out;
 */

 EMIT3(0x48, 0x85, 0xC9);                  /* test rcx,rcx */

 offset = ctx->tail_call_indirect_label - (prog + 2 - start);
 EMIT2(X86_JE, offset);                    /* je out */

 /* Inc tail_call_cnt if the slot is populated. */
 EMIT4(0x48, 0x83, 0x00, 0x01);            /* add qword ptr [rax], 1 */

 if (bpf_prog->aux->exception_boundary) {
  pop_callee_regs(&prog, all_callee_regs_used);
  pop_r12(&prog);
 } else {
  pop_callee_regs(&prog, callee_regs_used);
  if (bpf_arena_get_kern_vm_start(bpf_prog->aux->arena))
   pop_r12(&prog);
 }

 /* Pop tail_call_cnt_ptr. */
 EMIT1(0x58);                              /* pop rax */
 /* Pop tail_call_cnt, if it's main prog.
 * Pop tail_call_cnt_ptr, if it's subprog.
 */

 EMIT1(0x58);                              /* pop rax */
 if (stack_depth)
  EMIT3_off32(0x48, 0x81, 0xC4,     /* add rsp, sd */
       round_up(stack_depth, 8));

 /* goto *(prog->bpf_func + X86_TAIL_CALL_OFFSET); */
 EMIT4(0x48, 0x8B, 0x49,                   /* mov rcx, qword ptr [rcx + 32] */
       offsetof(struct bpf_prog, bpf_func));
 EMIT4(0x48, 0x83, 0xC1,                   /* add rcx, X86_TAIL_CALL_OFFSET */
       X86_TAIL_CALL_OFFSET);
 /*
 * Now we're ready to jump into next BPF program
 * rdi == ctx (1st arg)
 * rcx == prog->bpf_func + X86_TAIL_CALL_OFFSET
 */

 emit_indirect_jump(&prog, 1 /* rcx */, ip + (prog - start));

 /* out: */
 ctx->tail_call_indirect_label = prog - start;
 *pprog = prog;
}

static void emit_bpf_tail_call_direct(struct bpf_prog *bpf_prog,
          struct bpf_jit_poke_descriptor *poke,
          u8 **pprog, u8 *ip,
          bool *callee_regs_used, u32 stack_depth,
          struct jit_context *ctx)
{
 int tcc_ptr_off = BPF_TAIL_CALL_CNT_PTR_STACK_OFF(stack_depth);
 u8 *prog = *pprog, *start = *pprog;
 int offset;

 /*
 * if ((*tcc_ptr)++ >= MAX_TAIL_CALL_CNT)
 * goto out;
 */

 EMIT3_off32(0x48, 0x8B, 0x85, tcc_ptr_off);   /* mov rax, qword ptr [rbp - tcc_ptr_off] */
 EMIT4(0x48, 0x83, 0x38, MAX_TAIL_CALL_CNT);   /* cmp qword ptr [rax], MAX_TAIL_CALL_CNT */

 offset = ctx->tail_call_direct_label - (prog + 2 - start);
 EMIT2(X86_JAE, offset);                       /* jae out */

 poke->tailcall_bypass = ip + (prog - start);
 poke->adj_off = X86_TAIL_CALL_OFFSET;
 poke->tailcall_target = ip + ctx->tail_call_direct_label - X86_PATCH_SIZE;
 poke->bypass_addr = (u8 *)poke->tailcall_target + X86_PATCH_SIZE;

 emit_jump(&prog, (u8 *)poke->tailcall_target + X86_PATCH_SIZE,
    poke->tailcall_bypass);

 /* Inc tail_call_cnt if the slot is populated. */
 EMIT4(0x48, 0x83, 0x00, 0x01);                /* add qword ptr [rax], 1 */

 if (bpf_prog->aux->exception_boundary) {
  pop_callee_regs(&prog, all_callee_regs_used);
  pop_r12(&prog);
 } else {
  pop_callee_regs(&prog, callee_regs_used);
  if (bpf_arena_get_kern_vm_start(bpf_prog->aux->arena))
   pop_r12(&prog);
 }

 /* Pop tail_call_cnt_ptr. */
 EMIT1(0x58);                                  /* pop rax */
 /* Pop tail_call_cnt, if it's main prog.
 * Pop tail_call_cnt_ptr, if it's subprog.
 */

 EMIT1(0x58);                                  /* pop rax */
 if (stack_depth)
  EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8));

 emit_nops(&prog, X86_PATCH_SIZE);

 /* out: */
 ctx->tail_call_direct_label = prog - start;

 *pprog = prog;
}

static void bpf_tail_call_direct_fixup(struct bpf_prog *prog)
{
 struct bpf_jit_poke_descriptor *poke;
 struct bpf_array *array;
 struct bpf_prog *target;
 int i, ret;

 for (i = 0; i < prog->aux->size_poke_tab; i++) {
  poke = &prog->aux->poke_tab[i];
  if (poke->aux && poke->aux != prog->aux)
   continue;

  WARN_ON_ONCE(READ_ONCE(poke->tailcall_target_stable));

  if (poke->reason != BPF_POKE_REASON_TAIL_CALL)
   continue;

  array = container_of(poke->tail_call.map, struct bpf_array, map);
  mutex_lock(&array->aux->poke_mutex);
  target = array->ptrs[poke->tail_call.key];
  if (target) {
   ret = __bpf_arch_text_poke(poke->tailcall_target,
         BPF_MOD_JUMP, NULL,
         (u8 *)target->bpf_func +
         poke->adj_off);
   BUG_ON(ret < 0);
   ret = __bpf_arch_text_poke(poke->tailcall_bypass,
         BPF_MOD_JUMP,
         (u8 *)poke->tailcall_target +
         X86_PATCH_SIZE, NULL);
   BUG_ON(ret < 0);
  }
  WRITE_ONCE(poke->tailcall_target_stable, true);
  mutex_unlock(&array->aux->poke_mutex);
 }
}

static void emit_mov_imm32(u8 **pprog, bool sign_propagate,
      u32 dst_reg, const u32 imm32)
{
 u8 *prog = *pprog;
 u8 b1, b2, b3;

 /*
 * Optimization: if imm32 is positive, use 'mov %eax, imm32'
 * (which zero-extends imm32) to save 2 bytes.
 */

 if (sign_propagate && (s32)imm32 < 0) {
  /* 'mov %rax, imm32' sign extends imm32 */
  b1 = add_1mod(0x48, dst_reg);
  b2 = 0xC7;
  b3 = 0xC0;
  EMIT3_off32(b1, b2, add_1reg(b3, dst_reg), imm32);
  goto done;
 }

 /*
 * Optimization: if imm32 is zero, use 'xor %eax, %eax'
 * to save 3 bytes.
 */

 if (imm32 == 0) {
  if (is_ereg(dst_reg))
   EMIT1(add_2mod(0x40, dst_reg, dst_reg));
  b2 = 0x31; /* xor */
  b3 = 0xC0;
  EMIT2(b2, add_2reg(b3, dst_reg, dst_reg));
  goto done;
 }

 /* mov %eax, imm32 */
 if (is_ereg(dst_reg))
  EMIT1(add_1mod(0x40, dst_reg));
 EMIT1_off32(add_1reg(0xB8, dst_reg), imm32);
done:
 *pprog = prog;
}

static void emit_mov_imm64(u8 **pprog, u32 dst_reg,
      const u32 imm32_hi, const u32 imm32_lo)
{
 u64 imm64 = ((u64)imm32_hi << 32) | (u32)imm32_lo;
 u8 *prog = *pprog;

 if (is_uimm32(imm64)) {
  /*
 * For emitting plain u32, where sign bit must not be
 * propagated LLVM tends to load imm64 over mov32
 * directly, so save couple of bytes by just doing
 * 'mov %eax, imm32' instead.
 */

  emit_mov_imm32(&prog, false, dst_reg, imm32_lo);
 } else if (is_simm32(imm64)) {
  emit_mov_imm32(&prog, true, dst_reg, imm32_lo);
 } else {
  /* movabsq rax, imm64 */
  EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
  EMIT(imm32_lo, 4);
  EMIT(imm32_hi, 4);
 }

 *pprog = prog;
}

static void emit_mov_reg(u8 **pprog, bool is64, u32 dst_reg, u32 src_reg)
{
 u8 *prog = *pprog;

 if (is64) {
  /* mov dst, src */
  EMIT_mov(dst_reg, src_reg);
 } else {
  /* mov32 dst, src */
  if (is_ereg(dst_reg) || is_ereg(src_reg))
   EMIT1(add_2mod(0x40, dst_reg, src_reg));
  EMIT2(0x89, add_2reg(0xC0, dst_reg, src_reg));
 }

 *pprog = prog;
}

static void emit_movsx_reg(u8 **pprog, int num_bits, bool is64, u32 dst_reg,
      u32 src_reg)
{
 u8 *prog = *pprog;

 if (is64) {
  /* movs[b,w,l]q dst, src */
  if (num_bits == 8)
   EMIT4(add_2mod(0x48, src_reg, dst_reg), 0x0f, 0xbe,
         add_2reg(0xC0, src_reg, dst_reg));
  else if (num_bits == 16)
   EMIT4(add_2mod(0x48, src_reg, dst_reg), 0x0f, 0xbf,
         add_2reg(0xC0, src_reg, dst_reg));
  else if (num_bits == 32)
   EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x63,
         add_2reg(0xC0, src_reg, dst_reg));
 } else {
  /* movs[b,w]l dst, src */
  if (num_bits == 8) {
   EMIT4(add_2mod(0x40, src_reg, dst_reg), 0x0f, 0xbe,
         add_2reg(0xC0, src_reg, dst_reg));
  } else if (num_bits == 16) {
   if (is_ereg(dst_reg) || is_ereg(src_reg))
    EMIT1(add_2mod(0x40, src_reg, dst_reg));
   EMIT3(add_2mod(0x0f, src_reg, dst_reg), 0xbf,
         add_2reg(0xC0, src_reg, dst_reg));
  }
 }

 *pprog = prog;
}

/* Emit the suffix (ModR/M etc) for addressing *(ptr_reg + off) and val_reg */
static void emit_insn_suffix(u8 **pprog, u32 ptr_reg, u32 val_reg, int off)
{
 u8 *prog = *pprog;

 if (is_imm8(off)) {
  /* 1-byte signed displacement.
 *
 * If off == 0 we could skip this and save one extra byte, but
 * special case of x86 R13 which always needs an offset is not
 * worth the hassle
 */

  EMIT2(add_2reg(0x40, ptr_reg, val_reg), off);
 } else {
  /* 4-byte signed displacement */
  EMIT1_off32(add_2reg(0x80, ptr_reg, val_reg), off);
 }
 *pprog = prog;
}

static void emit_insn_suffix_SIB(u8 **pprog, u32 ptr_reg, u32 val_reg, u32 index_reg, int off)
{
 u8 *prog = *pprog;

 if (is_imm8(off)) {
  EMIT3(add_2reg(0x44, BPF_REG_0, val_reg), add_2reg(0, ptr_reg, index_reg) /* SIB */, off);
 } else {
  EMIT2_off32(add_2reg(0x84, BPF_REG_0, val_reg), add_2reg(0, ptr_reg, index_reg) /* SIB */, off);
 }
 *pprog = prog;
}

/*
 * Emit a REX byte if it will be necessary to address these registers
 */

static void maybe_emit_mod(u8 **pprog, u32 dst_reg, u32 src_reg, bool is64)
{
 u8 *prog = *pprog;

 if (is64)
  EMIT1(add_2mod(0x48, dst_reg, src_reg));
 else if (is_ereg(dst_reg) || is_ereg(src_reg))
  EMIT1(add_2mod(0x40, dst_reg, src_reg));
 *pprog = prog;
}

/*
 * Similar version of maybe_emit_mod() for a single register
 */

static void maybe_emit_1mod(u8 **pprog, u32 reg, bool is64)
{
 u8 *prog = *pprog;

 if (is64)
  EMIT1(add_1mod(0x48, reg));
 else if (is_ereg(reg))
  EMIT1(add_1mod(0x40, reg));
 *pprog = prog;
}

/* LDX: dst_reg = *(u8*)(src_reg + off) */
static void emit_ldx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
{
 u8 *prog = *pprog;

 switch (size) {
 case BPF_B:
  /* Emit 'movzx rax, byte ptr [rax + off]' */
  EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x0F, 0xB6);
  break;
 case BPF_H:
  /* Emit 'movzx rax, word ptr [rax + off]' */
  EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x0F, 0xB7);
  break;
 case BPF_W:
  /* Emit 'mov eax, dword ptr [rax+0x14]' */
  if (is_ereg(dst_reg) || is_ereg(src_reg))
   EMIT2(add_2mod(0x40, src_reg, dst_reg), 0x8B);
  else
   EMIT1(0x8B);
  break;
 case BPF_DW:
  /* Emit 'mov rax, qword ptr [rax+0x14]' */
  EMIT2(add_2mod(0x48, src_reg, dst_reg), 0x8B);
  break;
 }
 emit_insn_suffix(&prog, src_reg, dst_reg, off);
 *pprog = prog;
}

/* LDSX: dst_reg = *(s8*)(src_reg + off) */
static void emit_ldsx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
{
 u8 *prog = *pprog;

 switch (size) {
 case BPF_B:
  /* Emit 'movsx rax, byte ptr [rax + off]' */
  EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x0F, 0xBE);
  break;
 case BPF_H:
  /* Emit 'movsx rax, word ptr [rax + off]' */
  EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x0F, 0xBF);
  break;
 case BPF_W:
  /* Emit 'movsx rax, dword ptr [rax+0x14]' */
  EMIT2(add_2mod(0x48, src_reg, dst_reg), 0x63);
  break;
 }
 emit_insn_suffix(&prog, src_reg, dst_reg, off);
 *pprog = prog;
}

static void emit_ldx_index(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, u32 index_reg, int off)
{
 u8 *prog = *pprog;

 switch (size) {
 case BPF_B:
  /* movzx rax, byte ptr [rax + r12 + off] */
  EMIT3(add_3mod(0x40, src_reg, dst_reg, index_reg), 0x0F, 0xB6);
  break;
 case BPF_H:
  /* movzx rax, word ptr [rax + r12 + off] */
  EMIT3(add_3mod(0x40, src_reg, dst_reg, index_reg), 0x0F, 0xB7);
  break;
 case BPF_W:
  /* mov eax, dword ptr [rax + r12 + off] */
  EMIT2(add_3mod(0x40, src_reg, dst_reg, index_reg), 0x8B);
  break;
 case BPF_DW:
  /* mov rax, qword ptr [rax + r12 + off] */
  EMIT2(add_3mod(0x48, src_reg, dst_reg, index_reg), 0x8B);
  break;
 }
 emit_insn_suffix_SIB(&prog, src_reg, dst_reg, index_reg, off);
 *pprog = prog;
}

static void emit_ldx_r12(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
{
 emit_ldx_index(pprog, size, dst_reg, src_reg, X86_REG_R12, off);
}

/* STX: *(u8*)(dst_reg + off) = src_reg */
static void emit_stx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
{
 u8 *prog = *pprog;

 switch (size) {
 case BPF_B:
  /* Emit 'mov byte ptr [rax + off], al' */
  if (is_ereg(dst_reg) || is_ereg_8l(src_reg))
   /* Add extra byte for eregs or SIL,DIL,BPL in src_reg */
   EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88);
  else
   EMIT1(0x88);
  break;
 case BPF_H:
  if (is_ereg(dst_reg) || is_ereg(src_reg))
   EMIT3(0x66, add_2mod(0x40, dst_reg, src_reg), 0x89);
  else
   EMIT2(0x66, 0x89);
  break;
 case BPF_W:
  if (is_ereg(dst_reg) || is_ereg(src_reg))
   EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x89);
  else
   EMIT1(0x89);
  break;
 case BPF_DW:
  EMIT2(add_2mod(0x48, dst_reg, src_reg), 0x89);
  break;
 }
 emit_insn_suffix(&prog, dst_reg, src_reg, off);
 *pprog = prog;
}

/* STX: *(u8*)(dst_reg + index_reg + off) = src_reg */
static void emit_stx_index(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, u32 index_reg, int off)
{
 u8 *prog = *pprog;

 switch (size) {
 case BPF_B:
  /* mov byte ptr [rax + r12 + off], al */
  EMIT2(add_3mod(0x40, dst_reg, src_reg, index_reg), 0x88);
  break;
 case BPF_H:
  /* mov word ptr [rax + r12 + off], ax */
  EMIT3(0x66, add_3mod(0x40, dst_reg, src_reg, index_reg), 0x89);
  break;
 case BPF_W:
  /* mov dword ptr [rax + r12 + 1], eax */
  EMIT2(add_3mod(0x40, dst_reg, src_reg, index_reg), 0x89);
  break;
 case BPF_DW:
  /* mov qword ptr [rax + r12 + 1], rax */
  EMIT2(add_3mod(0x48, dst_reg, src_reg, index_reg), 0x89);
  break;
 }
 emit_insn_suffix_SIB(&prog, dst_reg, src_reg, index_reg, off);
 *pprog = prog;
}

static void emit_stx_r12(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
{
 emit_stx_index(pprog, size, dst_reg, src_reg, X86_REG_R12, off);
}

/* ST: *(u8*)(dst_reg + index_reg + off) = imm32 */
static void emit_st_index(u8 **pprog, u32 size, u32 dst_reg, u32 index_reg, int off, int imm)
{
 u8 *prog = *pprog;

 switch (size) {
 case BPF_B:
  /* mov byte ptr [rax + r12 + off], imm8 */
  EMIT2(add_3mod(0x40, dst_reg, 0, index_reg), 0xC6);
  break;
 case BPF_H:
  /* mov word ptr [rax + r12 + off], imm16 */
  EMIT3(0x66, add_3mod(0x40, dst_reg, 0, index_reg), 0xC7);
  break;
 case BPF_W:
  /* mov dword ptr [rax + r12 + 1], imm32 */
  EMIT2(add_3mod(0x40, dst_reg, 0, index_reg), 0xC7);
  break;
 case BPF_DW:
  /* mov qword ptr [rax + r12 + 1], imm32 */
  EMIT2(add_3mod(0x48, dst_reg, 0, index_reg), 0xC7);
  break;
 }
 emit_insn_suffix_SIB(&prog, dst_reg, 0, index_reg, off);
 EMIT(imm, bpf_size_to_x86_bytes(size));
 *pprog = prog;
}

static void emit_st_r12(u8 **pprog, u32 size, u32 dst_reg, int off, int imm)
{
 emit_st_index(pprog, size, dst_reg, X86_REG_R12, off, imm);
}

static int emit_atomic_rmw(u8 **pprog, u32 atomic_op,
      u32 dst_reg, u32 src_reg, s16 off, u8 bpf_size)
{
 u8 *prog = *pprog;

 EMIT1(0xF0); /* lock prefix */

 maybe_emit_mod(&prog, dst_reg, src_reg, bpf_size == BPF_DW);

 /* emit opcode */
 switch (atomic_op) {
 case BPF_ADD:
 case BPF_AND:
 case BPF_OR:
 case BPF_XOR:
  /* lock *(u32/u64*)(dst_reg + off) <op>= src_reg */
  EMIT1(simple_alu_opcodes[atomic_op]);
  break;
 case BPF_ADD | BPF_FETCH:
  /* src_reg = atomic_fetch_add(dst_reg + off, src_reg); */
  EMIT2(0x0F, 0xC1);
  break;
 case BPF_XCHG:
  /* src_reg = atomic_xchg(dst_reg + off, src_reg); */
  EMIT1(0x87);
  break;
 case BPF_CMPXCHG:
  /* r0 = atomic_cmpxchg(dst_reg + off, r0, src_reg); */
  EMIT2(0x0F, 0xB1);
  break;
 default:
  pr_err("bpf_jit: unknown atomic opcode %02x\n", atomic_op);
  return -EFAULT;
 }

 emit_insn_suffix(&prog, dst_reg, src_reg, off);

 *pprog = prog;
 return 0;
}

static int emit_atomic_rmw_index(u8 **pprog, u32 atomic_op, u32 size,
     u32 dst_reg, u32 src_reg, u32 index_reg,
     int off)
{
 u8 *prog = *pprog;

 EMIT1(0xF0); /* lock prefix */
 switch (size) {
 case BPF_W:
  EMIT1(add_3mod(0x40, dst_reg, src_reg, index_reg));
  break;
 case BPF_DW:
  EMIT1(add_3mod(0x48, dst_reg, src_reg, index_reg));
  break;
 default:
  pr_err("bpf_jit: 1- and 2-byte RMW atomics are not supported\n");
  return -EFAULT;
 }

 /* emit opcode */
 switch (atomic_op) {
 case BPF_ADD:
 case BPF_AND:
 case BPF_OR:
 case BPF_XOR:
  /* lock *(u32/u64*)(dst_reg + idx_reg + off) <op>= src_reg */
  EMIT1(simple_alu_opcodes[atomic_op]);
  break;
 case BPF_ADD | BPF_FETCH:
  /* src_reg = atomic_fetch_add(dst_reg + idx_reg + off, src_reg); */
  EMIT2(0x0F, 0xC1);
  break;
 case BPF_XCHG:
  /* src_reg = atomic_xchg(dst_reg + idx_reg + off, src_reg); */
  EMIT1(0x87);
  break;
 case BPF_CMPXCHG:
  /* r0 = atomic_cmpxchg(dst_reg + idx_reg + off, r0, src_reg); */
  EMIT2(0x0F, 0xB1);
  break;
 default:
  pr_err("bpf_jit: unknown atomic opcode %02x\n", atomic_op);
  return -EFAULT;
 }
 emit_insn_suffix_SIB(&prog, dst_reg, src_reg, index_reg, off);
 *pprog = prog;
 return 0;
}

static int emit_atomic_ld_st(u8 **pprog, u32 atomic_op, u32 dst_reg,
        u32 src_reg, s16 off, u8 bpf_size)
{
 switch (atomic_op) {
 case BPF_LOAD_ACQ:
  /* dst_reg = smp_load_acquire(src_reg + off16) */
  emit_ldx(pprog, bpf_size, dst_reg, src_reg, off);
  break;
 case BPF_STORE_REL:
  /* smp_store_release(dst_reg + off16, src_reg) */
  emit_stx(pprog, bpf_size, dst_reg, src_reg, off);
  break;
 default:
  pr_err("bpf_jit: unknown atomic load/store opcode %02x\n",
         atomic_op);
  return -EFAULT;
 }

 return 0;
}

static int emit_atomic_ld_st_index(u8 **pprog, u32 atomic_op, u32 size,
       u32 dst_reg, u32 src_reg, u32 index_reg,
       int off)
{
 switch (atomic_op) {
 case BPF_LOAD_ACQ:
  /* dst_reg = smp_load_acquire(src_reg + idx_reg + off16) */
  emit_ldx_index(pprog, size, dst_reg, src_reg, index_reg, off);
  break;
 case BPF_STORE_REL:
  /* smp_store_release(dst_reg + idx_reg + off16, src_reg) */
  emit_stx_index(pprog, size, dst_reg, src_reg, index_reg, off);
  break;
 default:
  pr_err("bpf_jit: unknown atomic load/store opcode %02x\n",
         atomic_op);
  return -EFAULT;
 }

 return 0;
}

#define DONT_CLEAR 1

bool ex_handler_bpf(const struct exception_table_entry *x, struct pt_regs *regs)
{
 u32 reg = x->fixup >> 8;

 /* jump over faulting load and clear dest register */
 if (reg != DONT_CLEAR)
  *(unsigned long *)((void *)regs + reg) = 0;
 regs->ip += x->fixup & 0xff;
 return true;
}

static void detect_reg_usage(struct bpf_insn *insn, int insn_cnt,
        bool *regs_used)
{
 int i;

 for (i = 1; i <= insn_cnt; i++, insn++) {
  if (insn->dst_reg == BPF_REG_6 || insn->src_reg == BPF_REG_6)
   regs_used[0] = true;
  if (insn->dst_reg == BPF_REG_7 || insn->src_reg == BPF_REG_7)
   regs_used[1] = true;
  if (insn->dst_reg == BPF_REG_8 || insn->src_reg == BPF_REG_8)
   regs_used[2] = true;
  if (insn->dst_reg == BPF_REG_9 || insn->src_reg == BPF_REG_9)
   regs_used[3] = true;
 }
}

/* emit the 3-byte VEX prefix
 *
 * r: same as rex.r, extra bit for ModRM reg field
 * x: same as rex.x, extra bit for SIB index field
 * b: same as rex.b, extra bit for ModRM r/m, or SIB base
 * m: opcode map select, encoding escape bytes e.g. 0x0f38
 * w: same as rex.w (32 bit or 64 bit) or opcode specific
 * src_reg2: additional source reg (encoded as BPF reg)
 * l: vector length (128 bit or 256 bit) or reserved
 * pp: opcode prefix (none, 0x66, 0xf2 or 0xf3)
 */

static void emit_3vex(u8 **pprog, bool r, bool x, bool b, u8 m,
        bool w, u8 src_reg2, bool l, u8 pp)
{
 u8 *prog = *pprog;
 const u8 b0 = 0xc4; /* first byte of 3-byte VEX prefix */
 u8 b1, b2;
 u8 vvvv = reg2hex[src_reg2];

 /* reg2hex gives only the lower 3 bit of vvvv */
 if (is_ereg(src_reg2))
  vvvv |= 1 << 3;

 /*
 * 2nd byte of 3-byte VEX prefix
 * ~ means bit inverted encoding
 *
 *    7                           0
 *  +---+---+---+---+---+---+---+---+
 *  |~R |~X |~B |         m         |
 *  +---+---+---+---+---+---+---+---+
 */

 b1 = (!r << 7) | (!x << 6) | (!b << 5) | (m & 0x1f);
 /*
 * 3rd byte of 3-byte VEX prefix
 *
 *    7                           0
 *  +---+---+---+---+---+---+---+---+
 *  | W |     ~vvvv     | L |   pp  |
 *  +---+---+---+---+---+---+---+---+
 */

 b2 = (w << 7) | ((~vvvv & 0xf) << 3) | (l << 2) | (pp & 3);

 EMIT3(b0, b1, b2);
 *pprog = prog;
}

/* emit BMI2 shift instruction */
static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op)
{
 u8 *prog = *pprog;
 bool r = is_ereg(dst_reg);
 u8 m = 2; /* escape code 0f38 */

 emit_3vex(&prog, r, false, r, m, is64, src_reg, false, op);
 EMIT2(0xf7, add_2reg(0xC0, dst_reg, dst_reg));
 *pprog = prog;
}

static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
{
 u8 *prog = *pprog;

 /* movabs r9, priv_frame_ptr */
 emit_mov_imm64(&prog, X86_REG_R9, (__force long) priv_frame_ptr >> 32,
         (u32) (__force long) priv_frame_ptr);

#ifdef CONFIG_SMP
 /* add <r9>, gs:[<off>] */
 EMIT2(0x65, 0x4c);
 EMIT3(0x03, 0x0c, 0x25);
 EMIT((u32)(unsigned long)&this_cpu_off, 4);
#endif

 *pprog = prog;
}

#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))

#define __LOAD_TCC_PTR(off)   \
 EMIT3_off32(0x48, 0x8B, 0x85, off)
/* mov rax, qword ptr [rbp - rounded_stack_depth - 16] */
#define LOAD_TAIL_CALL_CNT_PTR(stack)    \
 __LOAD_TCC_PTR(BPF_TAIL_CALL_CNT_PTR_STACK_OFF(stack))

/* Memory size/value to protect private stack overflow/underflow */
#define PRIV_STACK_GUARD_SZ    8
#define PRIV_STACK_GUARD_VAL   0xEB9F12345678eb9fULL

static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
        struct bpf_prog *bpf_prog)
{
 u8 *prog = *pprog;
 u8 *func;

 if (cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP)) {
  /* The clearing sequence clobbers eax and ecx. */
  EMIT1(0x50); /* push rax */
  EMIT1(0x51); /* push rcx */
  ip += 2;

  func = (u8 *)clear_bhb_loop;
  ip += x86_call_depth_emit_accounting(&prog, func, ip);

  if (emit_call(&prog, func, ip))
   return -EINVAL;
  EMIT1(0x59); /* pop rcx */
  EMIT1(0x58); /* pop rax */
 }
 /* Insert IBHF instruction */
 if ((cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP) &&
      cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) ||
     cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_HW)) {
  /*
 * Add an Indirect Branch History Fence (IBHF). IBHF acts as a
 * fence preventing branch history from before the fence from
 * affecting indirect branches after the fence. This is
 * specifically used in cBPF jitted code to prevent Intra-mode
 * BHI attacks. The IBHF instruction is designed to be a NOP on
 * hardware that doesn't need or support it.  The REP and REX.W
 * prefixes are required by the microcode, and they also ensure
 * that the NOP is unlikely to be used in existing code.
 *
 * IBHF is not a valid instruction in 32-bit mode.
 */

  EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */
 }
 *pprog = prog;
 return 0;
}

static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
    int oldproglen, struct jit_context *ctx, bool jmp_padding)
{
 bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
 struct bpf_insn *insn = bpf_prog->insnsi;
 bool callee_regs_used[4] = {};
 int insn_cnt = bpf_prog->len;
 bool seen_exit = false;
 u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
 void __percpu *priv_frame_ptr = NULL;
 u64 arena_vm_start, user_vm_start;
 void __percpu *priv_stack_ptr;
 int i, excnt = 0;
 int ilen, proglen = 0;
 u8 *prog = temp;
 u32 stack_depth;
 int err;

 stack_depth = bpf_prog->aux->stack_depth;
 priv_stack_ptr = bpf_prog->aux->priv_stack_ptr;
 if (priv_stack_ptr) {
  priv_frame_ptr = priv_stack_ptr + PRIV_STACK_GUARD_SZ + round_up(stack_depth, 8);
  stack_depth = 0;
 }

 arena_vm_start = bpf_arena_get_kern_vm_start(bpf_prog->aux->arena);
 user_vm_start = bpf_arena_get_user_vm_start(bpf_prog->aux->arena);

 detect_reg_usage(insn, insn_cnt, callee_regs_used);

 emit_prologue(&prog, image, stack_depth,
        bpf_prog_was_classic(bpf_prog), tail_call_reachable,
        bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
 /* Exception callback will clobber callee regs for its own use, and
 * restore the original callee regs from main prog's stack frame.
 */

 if (bpf_prog->aux->exception_boundary) {
  /* We also need to save r12, which is not mapped to any BPF
 * register, as we throw after entry into the kernel, which may
 * overwrite r12.
 */

  push_r12(&prog);
  push_callee_regs(&prog, all_callee_regs_used);
 } else {
  if (arena_vm_start)
   push_r12(&prog);
  push_callee_regs(&prog, callee_regs_used);
 }
 if (arena_vm_start)
  emit_mov_imm64(&prog, X86_REG_R12,
          arena_vm_start >> 32, (u32) arena_vm_start);

 if (priv_frame_ptr)
  emit_priv_frame_ptr(&prog, priv_frame_ptr);

 ilen = prog - temp;
 if (rw_image)
  memcpy(rw_image + proglen, temp, ilen);
 proglen += ilen;
 addrs[0] = proglen;
 prog = temp;

 for (i = 1; i <= insn_cnt; i++, insn++) {
  const s32 imm32 = insn->imm;
  u32 dst_reg = insn->dst_reg;
  u32 src_reg = insn->src_reg;
  u8 b2 = 0, b3 = 0;
  u8 *start_of_ldx;
  s64 jmp_offset;
  s16 insn_off;
  u8 jmp_cond;
  u8 *func;
  int nops;

  if (priv_frame_ptr) {
   if (src_reg == BPF_REG_FP)
    src_reg = X86_REG_R9;

   if (dst_reg == BPF_REG_FP)
    dst_reg = X86_REG_R9;
  }

  switch (insn->code) {
   /* ALU */
  case BPF_ALU | BPF_ADD | BPF_X:
  case BPF_ALU | BPF_SUB | BPF_X:
  case BPF_ALU | BPF_AND | BPF_X:
  case BPF_ALU | BPF_OR | BPF_X:
  case BPF_ALU | BPF_XOR | BPF_X:
  case BPF_ALU64 | BPF_ADD | BPF_X:
  case BPF_ALU64 | BPF_SUB | BPF_X:
  case BPF_ALU64 | BPF_AND | BPF_X:
  case BPF_ALU64 | BPF_OR | BPF_X:
  case BPF_ALU64 | BPF_XOR | BPF_X:
   maybe_emit_mod(&prog, dst_reg, src_reg,
           BPF_CLASS(insn->code) == BPF_ALU64);
   b2 = simple_alu_opcodes[BPF_OP(insn->code)];
   EMIT2(b2, add_2reg(0xC0, dst_reg, src_reg));
   break;

  case BPF_ALU64 | BPF_MOV | BPF_X:
   if (insn_is_cast_user(insn)) {
    if (dst_reg != src_reg)
     /* 32-bit mov */
     emit_mov_reg(&prog, false, dst_reg, src_reg);
    /* shl dst_reg, 32 */
    maybe_emit_1mod(&prog, dst_reg, true);
    EMIT3(0xC1, add_1reg(0xE0, dst_reg), 32);

    /* or dst_reg, user_vm_start */
    maybe_emit_1mod(&prog, dst_reg, true);
    if (is_axreg(dst_reg))
     EMIT1_off32(0x0D,  user_vm_start >> 32);
    else
     EMIT2_off32(0x81, add_1reg(0xC8, dst_reg),  user_vm_start >> 32);

    /* rol dst_reg, 32 */
    maybe_emit_1mod(&prog, dst_reg, true);
    EMIT3(0xC1, add_1reg(0xC0, dst_reg), 32);

    /* xor r11, r11 */
    EMIT3(0x4D, 0x31, 0xDB);

    /* test dst_reg32, dst_reg32; check if lower 32-bit are zero */
    maybe_emit_mod(&prog, dst_reg, dst_reg, false);
    EMIT2(0x85, add_2reg(0xC0, dst_reg, dst_reg));

    /* cmove r11, dst_reg; if so, set dst_reg to zero */
    /* WARNING: Intel swapped src/dst register encoding in CMOVcc !!! */
    maybe_emit_mod(&prog, AUX_REG, dst_reg, true);
    EMIT3(0x0F, 0x44, add_2reg(0xC0, AUX_REG, dst_reg));
    break;
   } else if (insn_is_mov_percpu_addr(insn)) {
    /* mov <dst>, <src> (if necessary) */
    EMIT_mov(dst_reg, src_reg);
#ifdef CONFIG_SMP
    /* add <dst>, gs:[<off>] */
    EMIT2(0x65, add_1mod(0x48, dst_reg));
    EMIT3(0x03, add_2reg(0x04, 0, dst_reg), 0x25);
    EMIT((u32)(unsigned long)&this_cpu_off, 4);
#endif
    break;
   }
   fallthrough;
  case BPF_ALU | BPF_MOV | BPF_X:
   if (insn->off == 0)
    emit_mov_reg(&prog,
          BPF_CLASS(insn->code) == BPF_ALU64,
          dst_reg, src_reg);
   else
    emit_movsx_reg(&prog, insn->off,
            BPF_CLASS(insn->code) == BPF_ALU64,
            dst_reg, src_reg);
   break;

   /* neg dst */
  case BPF_ALU | BPF_NEG:
  case BPF_ALU64 | BPF_NEG:
   maybe_emit_1mod(&prog, dst_reg,
     BPF_CLASS(insn->code) == BPF_ALU64);
   EMIT2(0xF7, add_1reg(0xD8, dst_reg));
   break;

  case BPF_ALU | BPF_ADD | BPF_K:
  case BPF_ALU | BPF_SUB | BPF_K:
  case BPF_ALU | BPF_AND | BPF_K:
  case BPF_ALU | BPF_OR | BPF_K:
  case BPF_ALU | BPF_XOR | BPF_K:
  case BPF_ALU64 | BPF_ADD | BPF_K:
  case BPF_ALU64 | BPF_SUB | BPF_K:
  case BPF_ALU64 | BPF_AND | BPF_K:
  case BPF_ALU64 | BPF_OR | BPF_K:
  case BPF_ALU64 | BPF_XOR | BPF_K:
   maybe_emit_1mod(&prog, dst_reg,
     BPF_CLASS(insn->code) == BPF_ALU64);

   /*
 * b3 holds 'normal' opcode, b2 short form only valid
 * in case dst is eax/rax.
 */

   switch (BPF_OP(insn->code)) {
   case BPF_ADD:
    b3 = 0xC0;
    b2 = 0x05;
    break;
   case BPF_SUB:
    b3 = 0xE8;
    b2 = 0x2D;
    break;
   case BPF_AND:
    b3 = 0xE0;
    b2 = 0x25;
    break;
   case BPF_OR:
    b3 = 0xC8;
    b2 = 0x0D;
    break;
   case BPF_XOR:
    b3 = 0xF0;
    b2 = 0x35;
    break;
   }

   if (is_imm8(imm32))
    EMIT3(0x83, add_1reg(b3, dst_reg), imm32);
   else if (is_axreg(dst_reg))
    EMIT1_off32(b2, imm32);
   else
    EMIT2_off32(0x81, add_1reg(b3, dst_reg), imm32);
   break;

  case BPF_ALU64 | BPF_MOV | BPF_K:
  case BPF_ALU | BPF_MOV | BPF_K:
   emit_mov_imm32(&prog, BPF_CLASS(insn->code) == BPF_ALU64,
           dst_reg, imm32);
   break;

  case BPF_LD | BPF_IMM | BPF_DW:
   emit_mov_imm64(&prog, dst_reg, insn[1].imm, insn[0].imm);
   insn++;
   i++;
   break;

   /* dst %= src, dst /= src, dst %= imm32, dst /= imm32 */
  case BPF_ALU | BPF_MOD | BPF_X:
  case BPF_ALU | BPF_DIV | BPF_X:
  case BPF_ALU | BPF_MOD | BPF_K:
  case BPF_ALU | BPF_DIV | BPF_K:
  case BPF_ALU64 | BPF_MOD | BPF_X:
  case BPF_ALU64 | BPF_DIV | BPF_X:
  case BPF_ALU64 | BPF_MOD | BPF_K:
  case BPF_ALU64 | BPF_DIV | BPF_K: {
   bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;

   if (dst_reg != BPF_REG_0)
    EMIT1(0x50); /* push rax */
   if (dst_reg != BPF_REG_3)
    EMIT1(0x52); /* push rdx */

   if (BPF_SRC(insn->code) == BPF_X) {
    if (src_reg == BPF_REG_0 ||
        src_reg == BPF_REG_3) {
     /* mov r11, src_reg */
     EMIT_mov(AUX_REG, src_reg);
     src_reg = AUX_REG;
    }
   } else {
    /* mov r11, imm32 */
    EMIT3_off32(0x49, 0xC7, 0xC3, imm32);
    src_reg = AUX_REG;
   }

   if (dst_reg != BPF_REG_0)
    /* mov rax, dst_reg */
    emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);

   if (insn->off == 0) {
    /*
 * xor edx, edx
 * equivalent to 'xor rdx, rdx', but one byte less
 */

    EMIT2(0x31, 0xd2);

    /* div src_reg */
    maybe_emit_1mod(&prog, src_reg, is64);
    EMIT2(0xF7, add_1reg(0xF0, src_reg));
   } else {
    if (BPF_CLASS(insn->code) == BPF_ALU)
     EMIT1(0x99); /* cdq */
    else
     EMIT2(0x48, 0x99); /* cqo */

    /* idiv src_reg */
    maybe_emit_1mod(&prog, src_reg, is64);
    EMIT2(0xF7, add_1reg(0xF8, src_reg));
   }

   if (BPF_OP(insn->code) == BPF_MOD &&
       dst_reg != BPF_REG_3)
    /* mov dst_reg, rdx */
    emit_mov_reg(&prog, is64, dst_reg, BPF_REG_3);
   else if (BPF_OP(insn->code) == BPF_DIV &&
     dst_reg != BPF_REG_0)
    /* mov dst_reg, rax */
    emit_mov_reg(&prog, is64, dst_reg, BPF_REG_0);

   if (dst_reg != BPF_REG_3)
    EMIT1(0x5A); /* pop rdx */
   if (dst_reg != BPF_REG_0)
    EMIT1(0x58); /* pop rax */
   break;
  }

  case BPF_ALU | BPF_MUL | BPF_K:
  case BPF_ALU64 | BPF_MUL | BPF_K:
   maybe_emit_mod(&prog, dst_reg, dst_reg,
           BPF_CLASS(insn->code) == BPF_ALU64);

   if (is_imm8(imm32))
    /* imul dst_reg, dst_reg, imm8 */
    EMIT3(0x6B, add_2reg(0xC0, dst_reg, dst_reg),
          imm32);
   else
    /* imul dst_reg, dst_reg, imm32 */
    EMIT2_off32(0x69,
         add_2reg(0xC0, dst_reg, dst_reg),
         imm32);
   break;

  case BPF_ALU | BPF_MUL | BPF_X:
  case BPF_ALU64 | BPF_MUL | BPF_X:
   maybe_emit_mod(&prog, src_reg, dst_reg,
           BPF_CLASS(insn->code) == BPF_ALU64);

   /* imul dst_reg, src_reg */
   EMIT3(0x0F, 0xAF, add_2reg(0xC0, src_reg, dst_reg));
   break;

   /* Shifts */
  case BPF_ALU | BPF_LSH | BPF_K:
  case BPF_ALU | BPF_RSH | BPF_K:
  case BPF_ALU | BPF_ARSH | BPF_K:
  case BPF_ALU64 | BPF_LSH | BPF_K:
  case BPF_ALU64 | BPF_RSH | BPF_K:
  case BPF_ALU64 | BPF_ARSH | BPF_K:
   maybe_emit_1mod(&prog, dst_reg,
     BPF_CLASS(insn->code) == BPF_ALU64);

   b3 = simple_alu_opcodes[BPF_OP(insn->code)];
   if (imm32 == 1)
    EMIT2(0xD1, add_1reg(b3, dst_reg));
   else
    EMIT3(0xC1, add_1reg(b3, dst_reg), imm32);
   break;

  case BPF_ALU | BPF_LSH | BPF_X:
  case BPF_ALU | BPF_RSH | BPF_X:
  case BPF_ALU | BPF_ARSH | BPF_X:
  case BPF_ALU64 | BPF_LSH | BPF_X:
  case BPF_ALU64 | BPF_RSH | BPF_X:
  case BPF_ALU64 | BPF_ARSH | BPF_X:
   /* BMI2 shifts aren't better when shift count is already in rcx */
   if (boot_cpu_has(X86_FEATURE_BMI2) && src_reg != BPF_REG_4) {
    /* shrx/sarx/shlx dst_reg, dst_reg, src_reg */
    bool w = (BPF_CLASS(insn->code) == BPF_ALU64);
    u8 op;

    switch (BPF_OP(insn->code)) {
    case BPF_LSH:
     op = 1; /* prefix 0x66 */
     break;
    case BPF_RSH:
     op = 3; /* prefix 0xf2 */
     break;
    case BPF_ARSH:
     op = 2; /* prefix 0xf3 */
     break;
    }

    emit_shiftx(&prog, dst_reg, src_reg, w, op);

    break;
   }

   if (src_reg != BPF_REG_4) { /* common case */
    /* Check for bad case when dst_reg == rcx */
    if (dst_reg == BPF_REG_4) {
     /* mov r11, dst_reg */
     EMIT_mov(AUX_REG, dst_reg);
     dst_reg = AUX_REG;
    } else {
     EMIT1(0x51); /* push rcx */
    }
    /* mov rcx, src_reg */
    EMIT_mov(BPF_REG_4, src_reg);
   }

   /* shl %rax, %cl | shr %rax, %cl | sar %rax, %cl */
   maybe_emit_1mod(&prog, dst_reg,
     BPF_CLASS(insn->code) == BPF_ALU64);

   b3 = simple_alu_opcodes[BPF_OP(insn->code)];
   EMIT2(0xD3, add_1reg(b3, dst_reg));

   if (src_reg != BPF_REG_4) {
    if (insn->dst_reg == BPF_REG_4)
     /* mov dst_reg, r11 */
     EMIT_mov(insn->dst_reg, AUX_REG);
    else
     EMIT1(0x59); /* pop rcx */
   }

   break;

  case BPF_ALU | BPF_END | BPF_FROM_BE:
  case BPF_ALU64 | BPF_END | BPF_FROM_LE:
   switch (imm32) {
   case 16:
    /* Emit 'ror %ax, 8' to swap lower 2 bytes */
    EMIT1(0x66);
    if (is_ereg(dst_reg))
     EMIT1(0x41);
    EMIT3(0xC1, add_1reg(0xC8, dst_reg), 8);

    /* Emit 'movzwl eax, ax' */
    if (is_ereg(dst_reg))
     EMIT3(0x45, 0x0F, 0xB7);
    else
     EMIT2(0x0F, 0xB7);
    EMIT1(add_2reg(0xC0, dst_reg, dst_reg));
    break;
   case 32:
    /* Emit 'bswap eax' to swap lower 4 bytes */
    if (is_ereg(dst_reg))
     EMIT2(0x41, 0x0F);
    else
     EMIT1(0x0F);
    EMIT1(add_1reg(0xC8, dst_reg));
    break;
   case 64:
    /* Emit 'bswap rax' to swap 8 bytes */
    EMIT3(add_1mod(0x48, dst_reg), 0x0F,
          add_1reg(0xC8, dst_reg));
    break;
   }
   break;

  case BPF_ALU | BPF_END | BPF_FROM_LE:
   switch (imm32) {
   case 16:
    /*
 * Emit 'movzwl eax, ax' to zero extend 16-bit
 * into 64 bit
 */

    if (is_ereg(dst_reg))
     EMIT3(0x45, 0x0F, 0xB7);
    else
     EMIT2(0x0F, 0xB7);
    EMIT1(add_2reg(0xC0, dst_reg, dst_reg));
    break;
   case 32:
    /* Emit 'mov eax, eax' to clear upper 32-bits */
    if (is_ereg(dst_reg))
     EMIT1(0x45);
    EMIT2(0x89, add_2reg(0xC0, dst_reg, dst_reg));
    break;
   case 64:
    /* nop */
    break;
   }
   break;

   /* speculation barrier */
  case BPF_ST | BPF_NOSPEC:
   EMIT_LFENCE();
   break;

   /* ST: *(u8*)(dst_reg + off) = imm */
  case BPF_ST | BPF_MEM | BPF_B:
   if (is_ereg(dst_reg))
    EMIT2(0x41, 0xC6);
   else
    EMIT1(0xC6);
   goto st;
  case BPF_ST | BPF_MEM | BPF_H:
   if (is_ereg(dst_reg))
    EMIT3(0x66, 0x41, 0xC7);
   else
    EMIT2(0x66, 0xC7);
   goto st;
  case BPF_ST | BPF_MEM | BPF_W:
   if (is_ereg(dst_reg))
    EMIT2(0x41, 0xC7);
   else
    EMIT1(0xC7);
   goto st;
  case BPF_ST | BPF_MEM | BPF_DW:
   EMIT2(add_1mod(0x48, dst_reg), 0xC7);

st:   if (is_imm8(insn->off))
    EMIT2(add_1reg(0x40, dst_reg), insn->off);
   else
    EMIT1_off32(add_1reg(0x80, dst_reg), insn->off);

   EMIT(imm32, bpf_size_to_x86_bytes(BPF_SIZE(insn->code)));
   break;

   /* STX: *(u8*)(dst_reg + off) = src_reg */
  case BPF_STX | BPF_MEM | BPF_B:
  case BPF_STX | BPF_MEM | BPF_H:
  case BPF_STX | BPF_MEM | BPF_W:
  case BPF_STX | BPF_MEM | BPF_DW:
   emit_stx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
   break;

  case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
  case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
  case BPF_ST | BPF_PROBE_MEM32 | BPF_W:
  case BPF_ST | BPF_PROBE_MEM32 | BPF_DW:
   start_of_ldx = prog;
   emit_st_r12(&prog, BPF_SIZE(insn->code), dst_reg, insn->off, insn->imm);
   goto populate_extable;

   /* LDX: dst_reg = *(u8*)(src_reg + r12 + off) */
  case BPF_LDX | BPF_PROBE_MEM32 | BPF_B:
  case BPF_LDX | BPF_PROBE_MEM32 | BPF_H:
  case BPF_LDX | BPF_PROBE_MEM32 | BPF_W:
  case BPF_LDX | BPF_PROBE_MEM32 | BPF_DW:
  case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
  case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
  case BPF_STX | BPF_PROBE_MEM32 | BPF_W:
  case BPF_STX | BPF_PROBE_MEM32 | BPF_DW:
   start_of_ldx = prog;
   if (BPF_CLASS(insn->code) == BPF_LDX)
    emit_ldx_r12(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
   else
    emit_stx_r12(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
populate_extable:
   {
    struct exception_table_entry *ex;
    u8 *_insn = image + proglen + (start_of_ldx - temp);
    s64 delta;

    if (!bpf_prog->aux->extable)
     break;

    if (excnt >= bpf_prog->aux->num_exentries) {
     pr_err("mem32 extable bug\n");
     return -EFAULT;
    }
    ex = &bpf_prog->aux->extable[excnt++];

    delta = _insn - (u8 *)&ex->insn;
    /* switch ex to rw buffer for writes */
    ex = (void *)rw_image + ((void *)ex - (void *)image);

    ex->insn = delta;

    ex->data = EX_TYPE_BPF;

    ex->fixup = (prog - start_of_ldx) |
     ((BPF_CLASS(insn->code) == BPF_LDX ? reg2pt_regs[dst_reg] : DONT_CLEAR) << 8);
   }
   break;

   /* LDX: dst_reg = *(u8*)(src_reg + off) */
  case BPF_LDX | BPF_MEM | BPF_B:
  case BPF_LDX | BPF_PROBE_MEM | BPF_B:
  case BPF_LDX | BPF_MEM | BPF_H:
  case BPF_LDX | BPF_PROBE_MEM | BPF_H:
  case BPF_LDX | BPF_MEM | BPF_W:
  case BPF_LDX | BPF_PROBE_MEM | BPF_W:
  case BPF_LDX | BPF_MEM | BPF_DW:
  case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
   /* LDXS: dst_reg = *(s8*)(src_reg + off) */
  case BPF_LDX | BPF_MEMSX | BPF_B:
  case BPF_LDX | BPF_MEMSX | BPF_H:
  case BPF_LDX | BPF_MEMSX | BPF_W:
  case BPF_LDX | BPF_PROBE_MEMSX | BPF_B:
  case BPF_LDX | BPF_PROBE_MEMSX | BPF_H:
  case BPF_LDX | BPF_PROBE_MEMSX | BPF_W:
   insn_off = insn->off;

   if (BPF_MODE(insn->code) == BPF_PROBE_MEM ||
       BPF_MODE(insn->code) == BPF_PROBE_MEMSX) {
    /* Conservatively check that src_reg + insn->off is a kernel address:
 *   src_reg + insn->off > TASK_SIZE_MAX + PAGE_SIZE
 *   and
 *   src_reg + insn->off < VSYSCALL_ADDR
 */


    u64 limit = TASK_SIZE_MAX + PAGE_SIZE - VSYSCALL_ADDR;
    u8 *end_of_jmp;

    /* movabsq r10, VSYSCALL_ADDR */
    emit_mov_imm64(&prog, BPF_REG_AX, (long)VSYSCALL_ADDR >> 32,
            (u32)(long)VSYSCALL_ADDR);

    /* mov src_reg, r11 */
    EMIT_mov(AUX_REG, src_reg);

    if (insn->off) {
     /* add r11, insn->off */
     maybe_emit_1mod(&prog, AUX_REG, true);
     EMIT2_off32(0x81, add_1reg(0xC0, AUX_REG), insn->off);
    }

    /* sub r11, r10 */
    maybe_emit_mod(&prog, AUX_REG, BPF_REG_AX, true);
    EMIT2(0x29, add_2reg(0xC0, AUX_REG, BPF_REG_AX));

    /* movabsq r10, limit */
    emit_mov_imm64(&prog, BPF_REG_AX, (long)limit >> 32,
            (u32)(long)limit);

    /* cmp r10, r11 */
    maybe_emit_mod(&prog, AUX_REG, BPF_REG_AX, true);
    EMIT2(0x39, add_2reg(0xC0, AUX_REG, BPF_REG_AX));

    /* if unsigned '>', goto load */
    EMIT2(X86_JA, 0);
    end_of_jmp = prog;

    /* xor dst_reg, dst_reg */
    emit_mov_imm32(&prog, false, dst_reg, 0);
    /* jmp byte_after_ldx */
    EMIT2(0xEB, 0);

    /* populate jmp_offset for JAE above to jump to start_of_ldx */
    start_of_ldx = prog;
    end_of_jmp[-1] = start_of_ldx - end_of_jmp;
   }
   if (BPF_MODE(insn->code) == BPF_PROBE_MEMSX ||
       BPF_MODE(insn->code) == BPF_MEMSX)
    emit_ldsx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn_off);
   else
    emit_ldx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn_off);
   if (BPF_MODE(insn->code) == BPF_PROBE_MEM ||
       BPF_MODE(insn->code) == BPF_PROBE_MEMSX) {
    struct exception_table_entry *ex;
    u8 *_insn = image + proglen + (start_of_ldx - temp);
    s64 delta;

    /* populate jmp_offset for JMP above */
    start_of_ldx[-1] = prog - start_of_ldx;

    if (!bpf_prog->aux->extable)
     break;

    if (excnt >= bpf_prog->aux->num_exentries) {
     pr_err("ex gen bug\n");
     return -EFAULT;
    }
    ex = &bpf_prog->aux->extable[excnt++];

    delta = _insn - (u8 *)&ex->insn;
    if (!is_simm32(delta)) {
     pr_err("extable->insn doesn't fit into 32-bit\n");
     return -EFAULT;
    }
    /* switch ex to rw buffer for writes */
    ex = (void *)rw_image + ((void *)ex - (void *)image);

    ex->insn = delta;

    ex->data = EX_TYPE_BPF;

    if (dst_reg > BPF_REG_9) {
     pr_err("verifier error\n");
     return -EFAULT;
    }
    /*
 * Compute size of x86 insn and its target dest x86 register.
 * ex_handler_bpf() will use lower 8 bits to adjust
 * pt_regs->ip to jump over this x86 instruction
 * and upper bits to figure out which pt_regs to zero out.
 * End result: x86 insn "mov rbx, qword ptr [rax+0x14]"
 * of 4 bytes will be ignored and rbx will be zero inited.
 */

    ex->fixup = (prog - start_of_ldx) | (reg2pt_regs[dst_reg] << 8);
   }
   break;

  case BPF_STX | BPF_ATOMIC | BPF_B:
  case BPF_STX | BPF_ATOMIC | BPF_H:
   if (!bpf_atomic_is_load_store(insn)) {
    pr_err("bpf_jit: 1- and 2-byte RMW atomics are not supported\n");
    return -EFAULT;
   }
   fallthrough;
  case BPF_STX | BPF_ATOMIC | BPF_W:
  case BPF_STX | BPF_ATOMIC | BPF_DW:
   if (insn->imm == (BPF_AND | BPF_FETCH) ||
       insn->imm == (BPF_OR | BPF_FETCH) ||
       insn->imm == (BPF_XOR | BPF_FETCH)) {
    bool is64 = BPF_SIZE(insn->code) == BPF_DW;
    u32 real_src_reg = src_reg;
    u32 real_dst_reg = dst_reg;
    u8 *branch_target;

    /*
 * Can't be implemented with a single x86 insn.
 * Need to do a CMPXCHG loop.
 */


    /* Will need RAX as a CMPXCHG operand so save R0 */
    emit_mov_reg(&prog, true, BPF_REG_AX, BPF_REG_0);
    if (src_reg == BPF_REG_0)
     real_src_reg = BPF_REG_AX;
    if (dst_reg == BPF_REG_0)
     real_dst_reg = BPF_REG_AX;

    branch_target = prog;
    /* Load old value */
    emit_ldx(&prog, BPF_SIZE(insn->code),
      BPF_REG_0, real_dst_reg, insn->off);
    /*
 * Perform the (commutative) operation locally,
 * put the result in the AUX_REG.
 */

    emit_mov_reg(&prog, is64, AUX_REG, BPF_REG_0);
    maybe_emit_mod(&prog, AUX_REG, real_src_reg, is64);
    EMIT2(simple_alu_opcodes[BPF_OP(insn->imm)],
          add_2reg(0xC0, AUX_REG, real_src_reg));
    /* Attempt to swap in new value */
    err = emit_atomic_rmw(&prog, BPF_CMPXCHG,
            real_dst_reg, AUX_REG,
            insn->off,
            BPF_SIZE(insn->code));
    if (WARN_ON(err))
     return err;
    /*
 * ZF tells us whether we won the race. If it's
 * cleared we need to try again.
 */

    EMIT2(X86_JNE, -(prog - branch_target) - 2);
    /* Return the pre-modification value */
    emit_mov_reg(&prog, is64, real_src_reg, BPF_REG_0);
    /* Restore R0 after clobbering RAX */
    emit_mov_reg(&prog, true, BPF_REG_0, BPF_REG_AX);
    break;
   }

   if (bpf_atomic_is_load_store(insn))
    err = emit_atomic_ld_st(&prog, insn->imm, dst_reg, src_reg,
       insn->off, BPF_SIZE(insn->code));
   else
    err = emit_atomic_rmw(&prog, insn->imm, dst_reg, src_reg,
            insn->off, BPF_SIZE(insn->code));
   if (err)
    return err;
   break;

  case BPF_STX | BPF_PROBE_ATOMIC | BPF_B:
  case BPF_STX | BPF_PROBE_ATOMIC | BPF_H:
   if (!bpf_atomic_is_load_store(insn)) {
    pr_err("bpf_jit: 1- and 2-byte RMW atomics are not supported\n");
    return -EFAULT;
   }
   fallthrough;
  case BPF_STX | BPF_PROBE_ATOMIC | BPF_W:
  case BPF_STX | BPF_PROBE_ATOMIC | BPF_DW:
   start_of_ldx = prog;

   if (bpf_atomic_is_load_store(insn))
    err = emit_atomic_ld_st_index(&prog, insn->imm,
             BPF_SIZE(insn->code), dst_reg,
             src_reg, X86_REG_R12, insn->off);
   else
    err = emit_atomic_rmw_index(&prog, insn->imm, BPF_SIZE(insn->code),
           dst_reg, src_reg, X86_REG_R12,
           insn->off);
   if (err)
    return err;
   goto populate_extable;

   /* call */
  case BPF_JMP | BPF_CALL: {
   u8 *ip = image + addrs[i - 1];

   func = (u8 *) __bpf_call_base + imm32;
   if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
    LOAD_TAIL_CALL_CNT_PTR(stack_depth);
    ip += 7;
   }
   if (!imm32)
    return -EINVAL;
   if (priv_frame_ptr) {
    push_r9(&prog);
    ip += 2;
   }
   ip += x86_call_depth_emit_accounting(&prog, func, ip);
   if (emit_call(&prog, func, ip))
    return -EINVAL;
   if (priv_frame_ptr)
    pop_r9(&prog);
   break;
  }

  case BPF_JMP | BPF_TAIL_CALL:
   if (imm32)
    emit_bpf_tail_call_direct(bpf_prog,
         &bpf_prog->aux->poke_tab[imm32 - 1],
         &prog, image + addrs[i - 1],
         callee_regs_used,
         stack_depth,
         ctx);
   else
    emit_bpf_tail_call_indirect(bpf_prog,
           &prog,
           callee_regs_used,
           stack_depth,
           image + addrs[i - 1],
           ctx);
   break;

   /* cond jump */
  case BPF_JMP | BPF_JEQ | BPF_X:
  case BPF_JMP | BPF_JNE | BPF_X:
  case BPF_JMP | BPF_JGT | BPF_X:
  case BPF_JMP | BPF_JLT | BPF_X:
  case BPF_JMP | BPF_JGE | BPF_X:
  case BPF_JMP | BPF_JLE | BPF_X:
  case BPF_JMP | BPF_JSGT | BPF_X:
  case BPF_JMP | BPF_JSLT | BPF_X:
  case BPF_JMP | BPF_JSGE | BPF_X:
  case BPF_JMP | BPF_JSLE | BPF_X:
  case BPF_JMP32 | BPF_JEQ | BPF_X:
  case BPF_JMP32 | BPF_JNE | BPF_X:
  case BPF_JMP32 | BPF_JGT | BPF_X:
  case BPF_JMP32 | BPF_JLT | BPF_X:
  case BPF_JMP32 | BPF_JGE | BPF_X:
  case BPF_JMP32 | BPF_JLE | BPF_X:
  case BPF_JMP32 | BPF_JSGT | BPF_X:
  case BPF_JMP32 | BPF_JSLT | BPF_X:
  case BPF_JMP32 | BPF_JSGE | BPF_X:
  case BPF_JMP32 | BPF_JSLE | BPF_X:
   /* cmp dst_reg, src_reg */
   maybe_emit_mod(&prog, dst_reg, src_reg,
           BPF_CLASS(insn->code) == BPF_JMP);
   EMIT2(0x39, add_2reg(0xC0, dst_reg, src_reg));
   goto emit_cond_jmp;

  case BPF_JMP | BPF_JSET | BPF_X:
  case BPF_JMP32 | BPF_JSET | BPF_X:
   /* test dst_reg, src_reg */
   maybe_emit_mod(&prog, dst_reg, src_reg,
           BPF_CLASS(insn->code) == BPF_JMP);
   EMIT2(0x85, add_2reg(0xC0, dst_reg, src_reg));
   goto emit_cond_jmp;

  case BPF_JMP | BPF_JSET | BPF_K:
  case BPF_JMP32 | BPF_JSET | BPF_K:
   /* test dst_reg, imm32 */
   maybe_emit_1mod(&prog, dst_reg,
     BPF_CLASS(insn->code) == BPF_JMP);
   EMIT2_off32(0xF7, add_1reg(0xC0, dst_reg), imm32);
   goto emit_cond_jmp;

  case BPF_JMP | BPF_JEQ | BPF_K:
  case BPF_JMP | BPF_JNE | BPF_K:
  case BPF_JMP | BPF_JGT | BPF_K:
  case BPF_JMP | BPF_JLT | BPF_K:
  case BPF_JMP | BPF_JGE | BPF_K:
  case BPF_JMP | BPF_JLE | BPF_K:
  case BPF_JMP | BPF_JSGT | BPF_K:
  case BPF_JMP | BPF_JSLT | BPF_K:
  case BPF_JMP | BPF_JSGE | BPF_K:
  case BPF_JMP | BPF_JSLE | BPF_K:
  case BPF_JMP32 | BPF_JEQ | BPF_K:
  case BPF_JMP32 | BPF_JNE | BPF_K:
  case BPF_JMP32 | BPF_JGT | BPF_K:
  case BPF_JMP32 | BPF_JLT | BPF_K:
  case BPF_JMP32 | BPF_JGE | BPF_K:
  case BPF_JMP32 | BPF_JLE | BPF_K:
  case BPF_JMP32 | BPF_JSGT | BPF_K:
  case BPF_JMP32 | BPF_JSLT | BPF_K:
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=90 G=91

¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.