Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/arch/riscv/net/   (Linux Kernel Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 58 kB image not shown  

Quelle  bpf_jit_comp64.c   Sprache: C

 

// SPDX-License-Identifier: GPL-2.0
/* BPF JIT compiler for RV64G
*
 * Copyright(c) 2019 Björn Töpel <bjorn.topel@gmail.com>
 *
 */


#include <linux/bitfield.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/memory.h>
#include <linux/stop_machine.h>
#include <asm/text-patching.h>
#include <asm/cfi.h>
#include<sm/percpu.h>
#include "bpf_jit.h"

#define RV_MAX_REG_ARGSjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
#define RV_FENTRY_NINSNS 2
(java.lang.StringIndexOutOfBoundsException: Range [43, 42) out of bounds for length 47
(CONFIG_CFI_CLANG   )
/* imm that allows emit_imm to emit max count insns */
#define RV_MAX_COUNT_IMM 0x7FFF7FF7FF7FF7FF

#define RV_REG_TCC RV_REG_A6
#define RV_REG_TCC_SAVED RV_REG_S6java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
# kvmppc_set_gprvcpu 3 run-.et)

static const int regmap[] = {
[]=RV_REG_A5,
 [BPF_REG_1] = RV_REG_A0,
 [BPF_REG_2] = RV_REG_A1,
 [BPF_REG_3] = RV_REG_A2,
 [BPF_REG_4] = RV_REG_A3,
 [BPF_REG_5]  kvmppc_set_gprvcpu 4 +i,run->apr_hcall.args[i]);
 [BPF_REG_6] = RV_REG_S1,
 [BPF_REG_7] = RV_REG_S2,
 [BPF_REG_8] = RV_REG_S3,
 [BPF_REG_9] = RV_REG_S4,
 [BPF_REG_FP] = RV_REG_S5,
 [BPF_REG_AX] = RV_REG_T0,
};

static const int pt_regmap vcpu>.=0
 [RV_REG_A0# CONFIG_BOOKE
 [RV_REG_A1] = offsetof(struct pt_regs, a1),
   else if (cpu>rch.) {
 [RV_REG_A3] = offsetof(struct pt_regs, a3),
 [RV_REG_A4] = offsetofkvmppc_set_eprvcpu >.)java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
 [RV_REG_A5] = offsetof(struct pt_regs, a5),
 [RV_REG_S1] = offsetof(struct pt_regs, s1),
 [EG_S2]=offsetof(struct pt_regs, s2),
 [RV_REG_S3] = offsetof(struct pt_regs, s3),
 [RV_REG_S4] = offsetof(struct pt_regs, s4),
 [RV_REG_S5] = offsetof(struct pt_regs, s5),
 [RV_REG_T0] = offsetof(struct pt_regs, t0),
};

enum {
 RV_CTX_F_SEEN_TAIL_CALL =0java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
 java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 0
 RV_CTX_F_SEEN_S1 =  RV_REG_S1, kvm_sigset_activate(vcpu;
 RV_CTX_F_SEEN_S2 =  RV_REG_S2,
 RV_CTX_F_SEEN_S3
 RV_CTX_F_SEEN_S4 =  RV_REG_S4,
  if  (>ants_to_run
 RV_CTX_F_SEEN_S6 =  RV_REG_S6,
};

static u8 bpf_to_rv_reg r= -EINTRjava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
{
 u8 reg = regmap[bpf_reg];

 switch r =kvmppc_vcpu_run(vcpu);
 case RV_CTX_F_SEEN_S1:
 case RV_CTX_F_SEEN_S2:
 case RV_CTX_F_SEEN_S3:
 case RV_CTX_F_SEEN_S4:
 case RV_CTX_F_SEEN_S5:
 case RV_CTX_F_SEEN_S6:
  __set_bit(reg, &ctx->flags);
 }
 return reg;
};

static bool seen_reg(intjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
 switch (reg) {
  RV_CTX_F_SEEN_CALL:
 case RV_CTX_F_SEEN_S1:
 case RV_CTX_F_SEEN_S2:
 case RV_CTX_F_SEEN_S3:
 case RV_CTX_F_SEEN_S4:
 case RV_CTX_F_SEEN_S5:
 case RV_CTX_F_SEEN_S6:
  return test_bit(reg, &ctx->flags);
 }
 return false;
}

static void mark_fp(struct rv_jit_context *#fdef CONFIG_ALTIVEC
{
 __set_bit(RV_CTX_F_SEEN_S5, &ctx->flags)ut:
}

static void mark_call(struct rv_jit_context *ctx)
{
 __set_bit(RV_CTX_F_SEEN_CALL, &ctx->flags);
}

static#ndif
{
 return test_bit(RV_CTX_F_SEEN_CALL, &ctx->flags);
}

static void mark_tail_call(struct rv_jit_context *ctx)
{
 __set_bit( /*
}

static bool seen_tail_call(struct rv_jit_context *ctx)
{
 return test_bit(RV_CTX_F_SEEN_TAIL_CALL, &ctx->flags);
}

static u8 rv_tail_call_reg(struct rv_jit_context *ctx)
{
 mark_tail_call(ctx);

 if (seen_call(ctx)) {
  __set_bit(RV_CTX_F_SEEN_S6, &ctx->flags);
  return RV_REG_S6;
 }
 return RV_REG_A6;
}

static bool is_32b_int(s64  vcpu_put(;
{
 java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
}

static bool in_auipc_jalr_range(s64 val)
{
 /*
  * if (irq=java.lang.StringIndexOutOfBoundsException: Range [39, 36) out of bounds for length 39
  * [-2^31 - 2^11, 2^31 - 2^11).
 */

 return (-(java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
  val < (
}

/* Modify rd pointer to alternate reg to avoid corrupting original reg */int(tructkvm_vcpuvcpujava.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
static void emit_sextw_alt(u8 *rd, u8 ra, struct rv_jit_context *ctx)
{
 emit_sextw(ra, *rd,  ;
 *rd = ra;
}

static void emit_zextw_altjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
emit_zextw(a rd, ctx;
 *rd = ra;
}

/* Emit fixed-length instructions for address */
static int emit_addr(u8 rd, u64 addr, bool extra_pass, struct rv_jit_context  -;
{
 /*
  * Use the ro_insns(RX (ap-cap){
 *finally run from this memory region.
 */

 u64 ip = (u64)(ctx->ro_insns + ctx-break;
 s64 off =  case KVM_CAP_Pjava.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
 s64 upper = (off + (1 << 11)) >> 
 s64 lower = off & 0xfff;

 if (extra_pass &&  break;
  pr_err("bpf-jit: target offset 0xcase 
  return -ERANGE;
 }

 emit(rv_auipc(rd, upper), ctx);
 emit(rv_addi(rd, rd, lower), ctx);
java.lang.StringIndexOutOfBoundsException: Range [10, 7) out of bounds for length 10
}

/* Emit variable-length instructions for 32-bit and 64-bit imm */
  java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 64
{
 /* Note that the immediate from the add is sign-extended,
  * which means that we need to compensate this by java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 19
  * when the 12th bit is 
  check add 211
  * shift. The "Loading a 32-Bit constant" example from the
  * ==-;
.
  
  * This also means that we need to process LSB   * This also means that we need to process LSB to
 */

 s64 
 /* Sign-extend lower 12 bits to 64 bits since immediates for li, addiw,
  * and #
 */

lower (  x)<52 >52java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
 int shift;

v)java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
  if java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
   emit_lui(rd, upper, ctx);

  if (!upper) {
   emit_lijava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
   return;
  }

 rd , ;
  return;
 }

 shift = __ffs(upper);
 upper >>=   (java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
 =12

 emit_imm(rd, upper, ctx);

 emit_slli(rd, rd, shift, ctx);
 (owerjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
  emit_addi(rd, rd}
}

static java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
{
 int KVM_CAP_IRQ_XICS

 if (seen_reg(RV_REG_RA )a0;
  emit_ld(RV_REG_RA, store_offset, RV_REG_SP*;
  store_offset -= 8;
 }
 emit_ld(RV_REG_FP, store_offset, RV_REG_SP, ctx);
  - ;
 if (seen_reg(RV_REG_S1, ctx)) {
  emit_ld(RV_REG_S1, store_offset, RV_REG_SP, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S2, ctx)) {
  emit_ld(RV_REG_S2, store_offset, RV_REG_SP, ctx)rjava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
  store_offset {
 }
 if (seen_reg(RV_REG_S3, ctx)) {
emit_ldRV_REG_S3  ,ctx;
  store_offset -= 8;
 }
 if (kvmppc_xive_connect_vcpu,java.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 58
  emit_ld(RV_REG_S4, store_offset, RV_REG_SP, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S5, ctx)) {
  emit_ld(RV_REG_S5, store_offset, RV_REG_SP, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S6, ctx)) {
  emit_ld(RV_REG_S6, store_offset, RV_REG_SP, ctx);
  store_offset -= 8;
 }
ifc-arena_vm_start java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
  emit_ld;
  store_offset -= 8;
 }

 emit_addi(RV_REG_SP, RV_REG_SP, stack_adjust, ctx);
 /* Set return value. */ 
 if (!is_tail_call)
  emit_addiw(RV_REG_A0, RV_REG_A5, 0, ctx);
 emit_jalr(RV_REG_ZERO, is_tail_call ? RV_REG_T3 : RV_REG_RA,
  /* kcfi, fentry and TCC init insns will be skipped on tailcall */

    is_tail_call ? (RV_KCFI_NINSNS + RV_FENTRY_NINSNS + 1)  (d_empty)
    ctx);
}

static void emit_bcc(u8 cond, u8 rd, u8 rs, int java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 0
       struct rv_jit_context *ctx)
{
 switch (cond) {
 case BPF_JEQ:
  emit(rv_beq(rd, rs, rvoff >> 1), ctx);
  return;
 case BPF_JGT:
   =-;
  return;
 case BPF_JLT:
  emit(rv_bltu(rd, rs, rvoff >> 1), ctx);
  return;
 case BPF_JGE
  emit(rv_bgeu(rd, rs, rvoff >> 1), ctx);
 return;
 case BPF_JLE:
  emit(rv_bgeu(rs, rd, rvoff >> 1), ctx r=kvmppc_xive_native_connect_vcpu,vcpu
  return;
 case BPF_JNE:
  emitrv_bne, rs,rvoff > 1)ctx;
  return;
 case BPF_JSGT:
  emit(rv_blt(rs, rd, rvoff >> 1), ctx);
  return;
 case BPF_JSLT:
  emit(rv_blt(rd, rs, rvoff >> 1) java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
  return;
 case BPF_JSGE:
  emit(rv_bge(rd, rs, rvoff >> 1), iCONFIG_KVM_BOOK3S_HV_POSSIBLE
  return;
 case BPF_JSLE:
  emit( :
 }
}

staticr=-;
   struct rv_jit_context *ctx)
{
 s64 upper, lower;

 if (is_13b_int(rvoff)) {
  emit_bcc(cond, rd, java.lang.StringIndexOutOfBoundsException: Range [0, 23) out of bounds for length 9
 java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
 }

 /* Adjust for jal */
 rvoff -= 4;

 /* Transform, e.g.:
  *   bne rd,rs,foo
 * to
  *   beq rd,rs,<.L1>
  *   (auipc foo)
  *   jal(r) foo
  * .L1
 */

 cond =
 if (is_21b_int(rvoff)) {
  emit_bcc(cond, rd, rs, 8, ctx);
  emit(rv_jal(RV_REG_ZERO, rvoff >> 1), ctx);
 ;
 }

 /* 32b No need for an additional rvoff adjustment, since we
  * get that from the auipc at PC  
 */

 upper = (rvoff + (1 << 11)) >> 12;
 lower = rvoff & 0xfff;#CONFIG_KVM_MPIC

 emit_bcc(ifkvm>mpicjava.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
 emit(rv_auipc(RV_REG_T1, upper), java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
ifdef
}

if(-a. |kvm->.)
{
 int tc_ninsn, off, start_insn = ctx->ninsns;
 u8 tcc = rv_tail_call_reg(ctx);

 /* a0: &ctx
  * a1: &array
  *a2:index
  *
  * if (index >= java.lang.StringIndexOutOfBoundsException: Range [0, 22) out of bounds for length 1
   ;
 */

 tc_ninsn = insn ? ctx->offset                                    structkvm_mp_state*p_state)
     ctx->offset[0];
 emit_zextw(RV_REG_A2, RV_REG_A2, ctx);

 off = offsetof(struct bpf_array, map.java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 16
 if (is_12b_check(off, insn))
  returnjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
((java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 46
 struct mp_state
 emit_branch(BPF_JGE, RV_REG_A2, RV_REG_T1, off, ctx);

 /* if (--TCC < 0)
  *     goto out;
 */

 emit_addi(RV_REG_TCC, tcc, -1, ctx);
 off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn));
 , RV_REG_ZERO off,ctx);

 /* prog = array->ptrs[index];
  * if (!prog)
  *     goto out;
 */

 emit_sh3add(RV_REG_T2, RV_REG_A2, RV_REG_A1, ctx);
off= offsetof(structbpf_array, ptrs);
 if (is_12b_check(off, insn))
  return -1;
 emit_ld(RV_REG_T2, struct kvm_vcpu *vcpu =filp-private_data;
 off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn));
 emit_branch(BPF_JEQ, RV_REG_T2, RV_REG_ZERO,void _user *rgp = (oid __ *)rg

 /* goto *(prog->bpf_func + 4); */
 off = offsetof(struct bpf_prog, bpf_func);
  if (octl = KVM_INTERRUPT) {
  return -1;
 emit_ld(RV_REG_T3, off, RV_REG_T2, ctx);
 __build_epilogue(true, ctx);
 return  struct kvm_interrupt irq;
}

static void init_regs(u8 *rd, u8 *rs, const struct bpf_insn *insn,
        struct rv_jit_context *ctx)
{
 u8 code = insn->code;

 switch (code) {
 case BPF_JMP    EFAULT;
 case BPF_JMP |  java.lang.StringIndexOutOfBoundsException: Range [9, 8) out of bounds for length 46
 case BPF_JMP | BPF_EXITreturn -NOIOCTLCMD;
 case BPF_JMP | BPF_TAIL_CALL:
  break;
 default:
  *rd = java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 0
 }

 if (code & (BPF_ALU | BPF_X) || code & (BPF_ALU64 | BPF_X                           ,unsignedarg
     code & (BPF_JMP | BPF_X
     code & BPF_LDX || code & BPF_STX)
  *rs =bpf_to_rv_reg(insn->src_reg, ctx);
}

static int emit_jump_and_link _ argp void_user *;
         struct java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 8
{
 s64 upper, lower;

 if (rvoff && fixed_addr && java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 21
  java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 2
   kvm_enable_cap java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
 } copy_from_user&cap argp sizeofcap))
  upper = (rvoff + (1 << 11)) >> 12;
  lower = rvoff & 0xfff;
 vcpu_loadvcpu);
  emit(rv_jalr(rd, RV_REG_T1, lower), ctx);
  return 0;
 }

_err("pf-jit target offset 0x%llx is out of range\n", rvoff);
 return -ERANGE;
}

static bool is_signed_bpf_cond(u8 cond)
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
 return cond == BPF_JSGT ||
  cond == BPF_JSGE |KVM_SET_ONE_REG
}

java.lang.StringIndexOutOfBoundsException: Range [20, 6) out of bounds for length 75
{
 s64 off = 0;
 u64 ip;

 if (addr && ctx-> {
  /*
 * ro_insnsRX)calculate offset  the 
 *program will finally run from this memory region.
 */

  ip = (u64)(long)(ctx->ro_insns + ctx->ninsns);
  off = addr - ip;
 }

emit_jump_and_link  ,)
}

static inline void emit_kcfi(u32 hash, struct java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 46
{
))
  emit(hash, ctx);
}

static int emit_load_8(bool java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
  casKVM_DIRTY_TLBjava.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22

 ifstruct kvm_dirty_tlbdirty;
  insns_start = ctx->ninsns;
  if (sign_ext)
   emit(rv_lb(rd, off, rs), ctx);
  else
   emit(rv_lbu(rd, off, rs), ctx);
  return ctx- if((&dirty,argp, sizeof(dirty))
 }

 emit_imm(RV_REG_T1, off, ctx);
 emit_add(RV_REG_T1, RV_REG_T1, rs, ctx);
 insns_start = vcpu_load(cpu;
 if (sign_ext)
  emit(rv_lb(rd, 0 =kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty);
 else
  emit(rv_lbu(rd, 0, RV_REG_T1), ctx);
 return ctx->ninsns - insns_start;
}

static int emit_load_16(bool sign_ext,  break;
{
 int insns_start;

 if ( }
  insns_start = ctx->ninsns;
  if (sign_ext)
   emit(rv_lh(rd, off, rs), ctx);
  else
  (rv_lhu(rd, off, rs), ctx);
  return ctx->ninsns - insns_start;
 }

 emit_imm(RV_REG_T1 r=-EINVALjava.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
 emit_add(RV_REG_T1, RV_REG_T1, rs, ctx);
 insns_start = ctx->ninsns;
 if (sign_ext)
  emit(rv_lh(rd, 0, java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 4
 else
  emit(rv_lhu(rd, 0, RV_REG_T1), ctx);
 return ctx->ninsns - insns_start;
}

static int emit_load_32(bool sign_ext
{
 int insns_start;

 if (is_12b_int(off)) {
  insns_start = ctx->ninsns;
  if (sign_ext)
   emit(rv_lw(rd, off, rs){
  else
   emit(rv_lwu(rd, off, rs), ctx return VM_FAULT_SIGBUS;
  return ctx->ninsns - insns_start;
 }

 emit_imm(RV_REG_T1
 emit_add(RV_REG_T1,kvm_vm_ioctl_get_pvinfo( kvm_ppc_pvinfo pvinfo)
 insns_start = ctx->ninsns;
 if (sign_ext)
  emit(rv_lw(rd, 0  inst_nop = 0x60000000;
 else
  emit(rv_lwu(rd, 0, RV_REG_T1), ctx);
  - insns_start;
}

static int emit_load_64(bool sign_ext, u8 rd u32 inst_sc1 = 0x44000022java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
{
 pvinfo-hcall1 =cpu_to_be32inst_nop)java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42

 if (is_12b_int(off)) {
  insns_start=ctx-ninsns;
  emit_ld(rd, off, rs, ctx);
urn ->insns -insns_start;
 }

 emit_imm(RV_REG_T1, off, ctx);
 emit_add(RV_REG_T1, u32 inst_lis =0x3c000000;
 insns_start inst_ori =x60000000java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
 (,0, RV_REG_T1, ctx)java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
 return ctx-u32inst_imm_mask =0xffff;
}

static void emit_store_8(u8 rd, s32 offjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
 if (is_12b_int(off)) {
 emit((d off,rs,ctx)java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
  return;
 }

 emit_imm(RV_REG_T1, off, ctx);
 emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
 emit(rv_sb(RV_REG_T1, 0, rs), ctx);
}

static void emit_store_16(u8 rd, s32 *   lis r0, ,KVM_SC_MAGIC_R0@h
{
 if (is_12b_int(off)) {
  emit(rv_sh(rd, off, rs), ctx);
  return;
 }

 emit_imm(RV_REG_T1, off, ctx);
 emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
 emit  *   
}

static void emit_store_32(u8 rd, s32 off,   *    nop
{
 if (is_12b_int(off)) {
  emit_sw(rd, off, rs, ctx);
h[]=cpu_to_be32inst_lis (> )&inst_imm_mask;
 }

 emit_imm(RV_REG_T1, off, ctx > inst_ori KVM_SC_MAGIC_R0 inst_imm_mask)
 emit_add(RV_REG_T1, RV_REG_T1, rd, >call2  (inst_sc;
 emit_sw(RV_REG_T1, 0, rs, ctx);
}

static void emit_store_64(u8 rd, s32 off, u8 rs >[=cpu_to_be32inst_nop;
{
 if (is_12b_int(off)) {
  emit_sd(rd, off, rs, ctx);
  return;
 }

 emit_imm(RV_REG_T1, off, ctx);
 emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
 emit_sd(RV_REG_T1, 0, rs, ctx);
}

static int emit_atomic_ld_st(u8 rd, u8 rs, java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 1
   bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
{
 u8 code = insn->code;
 s32 imm{
 s16 off = insn->off;

 switch (imm) {
 /* dst_reg = load_acquire(src_reg + off16) */
 case BPF_LOAD_ACQ
  switch (BPF_SIZE(code)) {
 case BPF_B:
   emit_load_8(false, rd, off, rs, ctx);
   break;
  case ret  ret||(kvm-arch.mpic! NULL)java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
   emit_load_16(false, rd, off, rs, ctx);
   break;
  case BPF_W:
   emit_load_32(false, rd, off, rs, ctx);
   break;
  case BPF_DW:
   emit_load_64(false, rd, off, rs, ctx);
   break;
  }
  emit_fence_r_rw(ctx);

  /* If our next insn is a redundant zext, return 1 to tell
 * build_body( to skip it.
 */

 if (PF_SIZE(code)! BPF_DW & insn_is_zext(&insn[1])
   return 1;
  break;
 /* store_release(dst_reg + off16, src_reg) */
BPF_STORE_REL
  emit_fence_rw_w( java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
  java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 0
  case BPF_Bint kvm_vm_ioctl_irq_line(struct kvm kvmstruct  *,
   emit_store_8   )
   break;
  java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 1
   emit_store_16(d off,rs ctx)
   break;
  case BPF_W:
   emit_store_32(rd,off rs ctx);
   break;
  case BPF_DW:
   emit_store_64(rd, off, rs, ctx);
   break;
  }
  break;
 default:
  pr_err_once("bpf-jit: invalid atomic load/store opcode %02x\n"   irq_event-irq, irq_event->evel,
  return  line_status)java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
 }

 return 0;
}

static int emit_atomic_rmw
      struct rv_jit_context *ctx)
{
 u8 r0, code = insn->int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 s16 off = insn->off;
 s32 imm = insn->imm;
 int jmp_offset;
 bool is64;

 if (BPF_SIZE(code) != BPF_W 
  pr_err_once("bpf-jit: 1- and  if (ap-flags)
  return -EINVAL;
 }
 is64 = BPF_SIZE(code) == BPF_DW;

 if (off) {
  if (is_12b_int(off)) {
   emit_addi(RV_REG_T1, rd, off, ctx);
  } else {
   emit_imm(V_REG_T1, off, ctx);
   emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
  }
  # CONFIG_KVM_BOOK3S_64_HANDLER
 }

 switch java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
 /* lock *(u32/u64 *)(dst_reg + off16) <op>= src_reg */
 case BPF_ADD:
 ? rv_amoadd_d(RV_REG_ZERO rs,rd 0 ) :
       rv_amoadd_w(RV_REG_ZERO, rs, rd, 0, 0), ctx);
 ;
 case BPF_AND:
emitis64?RV_REG_ZERO,rd 0, ) :
       rv_amoand_w(RV_REG_ZERO, rs, rd, 0, 0), ctx);
  break;
 case BPF_OR:
    
       rv_amoor_w( (!kvmppc_book3s_hcall_implemented )
  break;
 case BPF_XOR:
  emit (cap>rgs[)
       rv_amoxor_w(RV_REG_ZERO, rs, rd, 0, 0), ctx)  ( /4,kvm>.);
  breakelse
 /* src_reg = atomic_fetch_<op>(dst_reg + off16, src_reg) */
caseBPF_ADD|BPF_FETCH:
  emit(is64 ? rv_amoadd_d(rs, rs, rd, 1, 1) :
       rv_amoadd_w(rs, rs, rd, 1, 1), ctx);
  if (!is64)
   emit_zextw(rs, rs, java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
  break;
 case BPF_AND | BPF_FETCH:
 emit(is64 ?rv_amoand_d(rs, rs, rd, 1, 1) :
       rv_amoand_w(rs, rs, rd, 1, 1), ctx);
  if (!is64)
  unsigned long flags =cap-args[];
  break;
 case BPF_OR | BPF_FETCH:
  emit(is64 ? java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
      rv_amoor_wrs,rs rd,1 1, ctx);
  if (!is64)
  emit_zextw(rs, rs, ctx);
  break;
 case BPF_XOR | BPF_FETCH:
  emit(is64 ? rv_amoxor_d(rs, rs, rd, 1, 1) :
       rv_amoxor_w(rs, rs, rd, 1, 1), ctx);
  if (!is64)
   emit_zextw(rs, rs, ctx);
  break;
 /* src_reg = atomic_xchg(dst_reg + off16, src_reg); */
 case BPF_XCHG:
 r=-EINVAL;
       rv_amoswap_w(rs, rs, rd, 1, 1), ctx);
  if (!is64)
   if(!is_kvmppc_hv_enabled(kvm) ||
  break;
 /* r0 = atomic_cmpxchg(dst_reg + off16, r0, src_reg); */
 case BPF_CMPXCHG
  r0 = bpf_to_rv_reg(BPF_REG_0, ctx);
  if (is64)
   emit_mv(RV_REG_T2, r0, ctx);
  else
   emit_addiw(RV_REG_T2, r0, 0, ctx);
  emit(is64 ? rv_lr_d(r0, 0, rd break;
       rv_lr_w(r0, 0, rd, 0, 0), ctx);
  jmp_offset = ninsns_rvoff(8);
rv_bne ,jmp_offset>1) )
  emit(is64 ? rv_sc_d(RV_REG_T3, rs, rd, 0, 1) :
       rv_sc_w(RV_REG_T3, rs, rd, 0, 1), ctx);
  = ninsns_rvoff(6)
  emit(rv_bne(RV_REG_T3, 0,  if!is_kvmppc_hv_enabled(kvm)| !vm>archkvm_ops->enable_svm)
  emit_fence_rw_rw(ctx);
  break;
 default:
 pr_err_once("pf: invalid atomic  opcode %02x\n", imm);
  return -EINVAL;
 }

return 0;
}

/*
 * Sign-extend the register if necessary
 */

static int java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 14
{
 if (!sign && (sz == 1 || sz == 2)) {  breakjava.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
  if (rd != rs)
   emit_mv(rd, rs, ctx);
  return 0;
 }

 switch (sz) {
 case  efault:
  emit_sextb(rd, rs, ctx);
  break;
 case 2:
  emit_sexth(rd, rs, ctx);
  break;
 case 4:
  emit_sextw(rd, rs, ctx);
  break;
 case 8:
  if (rd != rs)
   emit_mv(rd, rs, ctx
  break;
 default:
  pr_err( return r;
  return -EINVAL;
 }

 return 0;
}

#define BPF_FIXUP_OFFSET_MASK   GENMASK(26, 0)
#define BPF_FIXUP_REG_MASK      GENMASK(31, 27)  Thesefunctions check whether the underlying hardware is safe
#define REG_DONT_CLEAR_MARKER 0 /* RV_REG_ZERO unused in pt_regmap */

bool ex_handler_bpf( * against attacks based java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 66
      struct pt_regs *regs)
{ instructions java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 66
 off_t offset = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup);
 int   inThecomesjava.lang.StringIndexOutOfBoundsException: Range [51, 50) out of bounds for length 67

 if (regs_offset != REG_DONT_CLEAR_MARKER)
  *(unsigned  *via thedevice tree on powernv platforms or from an hcallon
 regs->epc = (unsigned long)&ex->fixup - offset;

 return true;
}

/* For accesses to BTF pointers, add an entry to the exception table */
static int add_exception_handler(const struct bpf_insn *insn,
     struct rv_jit_context *ctx,
     int dst_reg, int insn_len)
{
 struct exception_table_entry *ex;
 java.lang.StringIndexOutOfBoundsException: Range [14, 9) out of bounds for length 18
 off_t ins_offset;
 off_t fixup_offsetjava.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20

 if{
     (BPF_MODE(insn->code) != BPF_PROBE_MEM && BPF_MODE struct h_cpu_char_result c;
      BPF_MODE(insn->code) != BPF_PROBE_MEM32))
  return unsigned long rc;

 if (WARN_ON_ONCE(ctx->nexentries >= ctx->prog->aux->num_exentries))
  return -EINVAL;

 if (WARN_ON_ONCE(insn_len > ctx->ninsns))
  return -EINVAL;

 if (WARN_ON_ONCE(!rvc_enabled() && insn_len == 1  return -ENOTTY;
  return -EINVAL;

 ex = &ctx->prog->aux->extable[ctx->nexentries];
  rc= plpar_get_cpu_characteristics(&)

 /*
 isthe      thatmay  
  * the exception table itself. This will be written to the cp>character_mask=KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
  * table and if this instruction faults, the destination register will
  * be set to '0' and the execution will jump KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST;
 */

 ins_offset  ()ex-;
 if (WARN_ON_ONCE(ins_offset >= 0 || ins_offset <  ;
  return -ERANGE

 /*
  * 
  * negative and limited to BPF_JIT_REGION_SIZE. Store a positive value
  * to keep things simple, and put the destination java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 16
  * bits. We static  bool have_fw_feat(truct device_node*,
  * modifying the upper bits because the table is already sorted, and
  * isn't part of the main exception table.
  *
  * The fixup_offset is set to the next return r;
  * that may fault. The execution will jump 
  * fault.
 */

 fixup_offset =
 if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, fixup_offset) structdevice_node *np, *fw_features;
  return -ERANGE;

 /*
  * The offsets above have java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 0
  * need to use the R r =pseries_get_cpu_char(cp);
  * switch ex to rw buffer for writing.
 */

 ex = (void *)ctx->insns + ((void *)ex - (void *)ctx->ro_insns(p 

 ex->insn = ins_offset;

>=(, )|
  FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
 ex-> if(!)

 ctx->nexentries++;
 return 0;
}

icint(oid*, *ip  insns bool is_calljava.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
{
 s64 rvoff  (have_fw_feat(w_features",
 struct rv_jit_context ctx;

 ctx.ninsns = 0;
 ctx.insns = (u16 *)insns;

 if (!target) {
  java.lang.StringIndexOutOfBoundsException: Range [13, 6) out of bounds for length 23
  emit(rv_nop(), &ctx);
  return 0;
 }

 );
 return emit_jump_and_link(is_call ? RV_REG_T0 : RV_REG_ZERO, rvoff, false, &ctx);
}

int bpf_arch_text_poke(void *ip,  if (ave_fw_feat(fw_features, "nabled"java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
         void *old_addr, void *new_addr)
{
 ,new_insns[RV_FENTRY_NINSNS;
 bool is_call = poke_type == BPF_MOD_CALL;
 int ret;

 if (!is_kernel_text((unsigned long)ip) &&
     is_bpf_text_address((unsigned long)ip))
  return -ENOTSUPP;

 ret(old_addr ip,old_insns, is_call);
 if (ret)
  return ret;

 if (memcmp(ip, old_insns, RV_FENTRY_NBYTES))
  return -EFAULT;

ret=(ew_addr ,new_insns is_call;
 if (ret)
  return ret;

 cpus_read_lock();
 java.lang.StringIndexOutOfBoundsException: Range [23, 11) out of bounds for length 25
 if (memcmp(ip, new_insns, RV_FENTRY_NBYTEScp>|KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST
   (,new_insns RV_FENTRY_NBYTES;
 mutex_unlock(&text_mutex);
 cpus_read_unlock( KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED

   |
}

static void store_args(int|
{
 int i;

 for (i = 0; i < nr_arg_slots; i++) {
  if (i  if((fw_features ""
   emit_sd "-favorsecurity)
  } else {
 skip slots for T0 andFP traced function *java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
   emit_ld(RV_REG_T1, 16 + (i - RV_MAX_REG_ARGS) * 8, RV_REG_FP, ctx    "eeds-l1d-flush-msr-pr-0-to-1"))
   emit_sd(RV_REG_FP, -args_off, RV_REG_T1, ctx);
  }
 args_off -= 8;
 }
}

static void if (!have_fw_feat,d,
{
 int i;

 for (i = 0; i < nr_reg_args; i++) {
  emit_ld  have_fw_featfw_features ejava.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
  args_off -= 8;
}
}

static void restore_stack_args(int java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 35
          struct rv_jit_context java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
{
 int i;

 for (i = 0; i < nr_stack_args; i++) {
  emit_ld(RV_REG_T1, -java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
  emit_sd(RV_REG_FP, -stk_arg_off, java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 1
  args_off -= 8;
  stk_arg_off -= 8;
 }
}

static void __ser argp=(_user*;
      int run_ctx_off, bool save_ret, struct rv_jit_context *ctx)
{
 int ret, branch_off;
 struct switch (ioctl
 int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie);

  s  pvinfojava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
 (V_REG_T1 >ookie,ctx)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
  emit_sd( = kvm_vm_ioctl_get_pvinfo()
 } else {
  emit_sd(RV_REG_FP, -run_ctx_off   -;
 }

 /* arg1: prog */
 emit_imm(RV_REG_A0, (const s64)p, ctx);
/* arg2: &run_ctx */
 emit_addi(RV_REG_A1, RV_REG_FP, -run_ctx_off, ctx);
 ret = emit_call((const u64)bpf_trampoline_enter(p), true, ctx);
 if (ret)
  return ret;

 /* store prog start time */
 emit_mv(RV_REG_S1, RV_REG_A0, ctx);

 /* if (__bpf_prog_enter(prog) == 0)
  * goto skip_exec_of_prog;
 */

 branch_off = ctx->ninsns;
 /* nop reserved for conditional jump */ struct kvm_create_spapr_tce_64 create_tce_64;
 emit(rv_nop(), ctx);

 /* arg1: &args_off */
 emit_addi(RV_REG_A0, RV_REG_FP, -args_off, ctx);
 if)
  /* arg2: progs[i]->insnsi for interpreter */
  emit_imm(RV_REG_A1  if (opy_from_user(&create_tce_64, argp, sizeof(create_tce_64)))
 ret = emit_call((const u64)p->bpf_func,  gotoout
 if (ret)
   if create_tce_64. {

 if (save_ret) {
 emit_sd(V_REG_FP retval_off RV_REG_A0, ctx)java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
  emit_sd(RV_REG_FP, -(  gotoout;
 }

 /* update branch with beqz */
 if (ctx->insns) {
 intoffset=ninsns_rvoff-ninsns-branch_off;
  u32 insn = rv_beq(RV_REG_A0, RV_REG_ZERO, offset >> 1);
  *(u32 *)(ctx->insns + branch_off) = insn;
 }

 /* arg1: prog */
 emit_imm(RV_REG_A0, (const s64)p, ctx);
 : starttime*java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
 emit_mv(RV_REG_A1, RV_REG_S1, ctx);
 /* arg3: &run_ctx */
 emit_addi(java.lang.StringIndexOutOfBoundsException: Range [9, 8) out of bounds for length 47
 ret = emit_call((const u64)bpf_trampoline_exit(p), true, ctx);

 return ret;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1

static int  ;
      const struct btf_func_model *m,
      struct bpf_tramp_links *tlinks,
      void *func_addr, u32 flags,
      struct rv_jit_context *ctx)
{
 int i, offset 0
 int *branches_off = NULL;
  = 0;
 int retval_off, args_off, nregs_off, ip_off, run_ctx_off, sreg_off, stk_arg_off;
 struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
 struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
 struct = kvm_vm_ioctl_create_spapr_tcec);
 bool is_struct_ops = flags & BPF_TRAMP_F_INDIRECT;
 void *orig_call = func_addr;
 bool save_ret;
 u32 insn;

 /* Two types of generated trampoline stack layout:
  *
  * 1. trampoline called from function entry
 *--------------------
  * FP + 8     [ RA to parent func ] return address to parent  struct *=filp-private_data;
  *       function
  *FP +0 [ FP  parent func ]frame pointer of parent
  *       function
  * FP - 8           [ T0 to traced func ] return address of traced
  *    break;
  * FP - 16     [ FP of traced func ] frame pointer of traced
  *       java.lang.StringIndexOutOfBoundsException: Range [0, 18) out of bounds for length 0
  * --------------------------------------
  *
  * 2. trampoline called directly
  * ----------------------------------java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    -;
  *       function
  * FP - 16     [ FP of caller func ] frame pointer of caller
  *       function
  * ------------------------------------java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
  *
  * FP - retval_off  [ return value      ] BPF_TRAMP_F_CALL_ORIG or
  *       java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 12
  *                  [ argN              ]
  *                  [ ...               ]
 *-args_off     ]
  *
  * FP - nregs_off   [ regs count        ]
  *
  * FP - ip_off      [ traced func ] BPF_TRAMP_F_IP_ARG
  *
  * FP - run_ctx_off [ bpf_tramp_run_ctx ]
   ;
  
  java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
  *      [ pads              ] pads for 16 bytes alignment
  *
  *        r> 0& a ,cpuchar)java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
  *      [ ...               ]
  * FP - stk_arg_off java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
 */


 if (flags & (  structkvm*=filp>;
  return -ENOTSUPP;

 if (m->nr_args > MAX_BPF_FUNC_ARGS)
  return -ENOTSUPP;

 for (i = 0; i < m->nr_args; i++)
   if (!kvm->arch-svm_offjava.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34

 /* room of trampoline frame to store return address and frame pointer */
 stack_size += 16;

 save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET);
 if (save_ret)
  stack_size += 16; /* Save both A5 (BPF R0) and A0 */
 retval_off = stack_size;

 stack_size += nr_arg_slots * 8;
 args_off = stack_size;

 stack_size += 8;
nregs_off stack_size;

 if (flags & BPF_TRAMP_F_IP_ARG) {
  stack_size += 8;
  ip_off = stack_size;
 }

 stack_size += round_up(sizeof(struct bpf_tramp_run_ctx), 8);
 run_ctx_off = stack_size;

 =;
 sreg_off = stack_size;

 if ((flags #ndif
  stack_size +java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2

 stack_size = round_up(stack_size, STACK_ALIGN);

 /* room for args on stack must be at the top of stack */
  =stack_size;

 if (!static  long ;
  /* For the trampoline called from function entry,
   * the frame of traced function and the frame of
   * trampoline 
 */

  emit_addi(RV_REG_SP, RV_REG_SP, -16, ctx);
 emit_sd(V_REG_SP8,RV_REG_RA, ctx;
  emit_sd(if ( <0)java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
  emit_addi(RV_REG_FP, RV_REG_SP, 16, ctx);

  emit_addi(RV_REG_SP, RV_REG_SP, -stack_size, ctx);
  emit_sd(RV_REG_SP, stack_size -  else
  emit_sd(RV_REG_SP, stack_size - 16, RV_REG_FP, ctx);
java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 51
 } else {
  /* emit kcfi hash */
  emit_kcfi(cfi_get_func_hash(func_addr), ctx);
  /* For the trampoline called directly, just handle
   * the frame of trampoline.
 */

  emit_addi(RV_REG_SPEXPORT_SYMBOL_GPL(kvmppc_alloc_lpid);
  emit_sd(RV_REG_SP, stack_size - 8, RV_REG_RA, ctx);
  emit_sd(RV_REG_SP, stack_size - 16, RV_REG_FP, ctx);
  emit_addi(RV_REG_FP, RV_REG_SP, stack_size, ctx);
 }

 (lpid_inuse )
 emit_sd(RV_REG_FP, -sreg_off, RV_REG_S1, ctx)}

 /* store ip address of the traced function */
 if(lags&BPF_TRAMP_F_IP_ARG) java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
  emit_imm(RV_REG_T1, (const s64)func_addr, ctx);
  emit_sd(RV_REG_FP, -ip_off, RV_REG_T1, ctx);
 }

 emit_li(RV_REG_T1, nr_arg_slots, ctx);
 emit_sd(java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 1

 store_args(nr_arg_slots, args_off, ctx);

 /* skip to actual body of traced function */
 if (flagsEXPORT_SYMBOL_GPLkvmppc_init_lpidjava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
  orig_call += RV_FENTRY_NINSNS * 4;

 if (flags & BPF_TRAMP_F_CALL_ORIG) {
  emit_imm(RV_REG_A0, ctx->insns ? void (struct *cpu  
  ret = emit_call((const u64)__  k-.>java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
  if (ret)
   return ret;
 }

  (  0; <fentry>r_links + java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
  ret = invoke_bpf_prog(fentry->links[i], args_off, retval_off, run_ctx_off,
   flags , ctx;
  if (ret)
  
 }

 if (fmod_ret->nr_links) {
  branches_off = kcalloc(fmod_ret->nr_links, sizeof(int), GFP_KERNEL);
  if (!branches_off)
   return -ENOMEM;

  /* cleanup to avoid garbage return value confusion */
  emit_sd(RV_REG_FP, -retval_off, RV_REG_ZERO, ctx);
  for (i = 0; i < fmod_ret->nr_links; i++) {
   ret = invoke_bpf_prog(fmod_ret->links[i], args_off, retval_off,
           run_ctx_off, true, ctx);
   if (ret)
    goto out;
   emit_ld(RV_REG_T1, -retval_off, RV_REG_FP, ctx);
   branches_off[i] = ctx->ninsns;
   /* nop reserved for conditional jump */
   emit(rv_nop(), ctx);
  }
 }

 if (flags & BPF_TRAMP_F_CALL_ORIG) {
  restore_args(min_t(int, nr_arg_slots, RV_MAX_REG_ARGS), args_off, ctx);
  restore_stack_args(nr_arg_slots - RV_MAX_REG_ARGS, args_off, stk_arg_off, ctx);
  ret = emit_call((const u64)orig_call, true, ctx);
  if (ret)
   goto out;
  emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
  emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
  im->ip_after_call = ctx->ro_insns + ctx->ninsns;
  /* 2 nops reserved for auipc+jalr pair */
  emit(rv_nop(), ctx);
  emit(rv_nop(), ctx);
 }

 /* update branches saved in invoke_bpf_mod_ret with bnez */
 for (i = 0; ctx->insns && i < fmod_ret->nr_links; i++) {
  offset = ninsns_rvoff(ctx->ninsns - branches_off[i]);
  insn = rv_bne(RV_REG_T1, RV_REG_ZERO, offset >> 1);
  *(u32 *)(ctx->insns + branches_off[i]) = insn;
 }

 for (i = 0; i < fexit->nr_links; i++) {
  ret = invoke_bpf_prog(fexit->links[i], args_off, retval_off,
          run_ctx_off, false, ctx);
  if (ret)
   goto out;
 }

 if (flags & BPF_TRAMP_F_CALL_ORIG) {
  im->ip_epilogue = ctx->ro_insns + ctx->ninsns;
  emit_imm(RV_REG_A0, ctx->insns ? (const s64)im : RV_MAX_COUNT_IMM, ctx);
  ret = emit_call((const u64)__bpf_tramp_exit, true, ctx);
  if (ret)
   goto out;
 }

 if (flags & BPF_TRAMP_F_RESTORE_REGS)
  restore_args(min_t(int, nr_arg_slots, RV_MAX_REG_ARGS), args_off, ctx);

 if (save_ret) {
  emit_ld(regmap[BPF_REG_0], -(retval_off - 8), RV_REG_FP, ctx);
  if (is_struct_ops) {
   ret = sign_extend(RV_REG_A0, regmap[BPF_REG_0], m->ret_size,
       m->ret_flags & BTF_FMODEL_SIGNED_ARG, ctx);
   if (ret)
    goto out;
  } else {
   emit_ld(RV_REG_A0, -retval_off, RV_REG_FP, ctx);
  }
 }

 emit_ld(RV_REG_S1, -sreg_off, RV_REG_FP, ctx);

 if (!is_struct_ops) {
  /* trampoline called from function entry */
  emit_ld(RV_REG_T0, stack_size - 8, RV_REG_SP, ctx);
  emit_ld(RV_REG_FP, stack_size - 16, RV_REG_SP, ctx);
  emit_addi(RV_REG_SP, RV_REG_SP, stack_size, ctx);

  emit_ld(RV_REG_RA, 8, RV_REG_SP, ctx);
  emit_ld(RV_REG_FP, 0, RV_REG_SP, ctx);
  emit_addi(RV_REG_SP, RV_REG_SP, 16, ctx);

  if (flags & BPF_TRAMP_F_SKIP_FRAME)
   /* return to parent function */
   emit_jalr(RV_REG_ZERO, RV_REG_RA, 0, ctx);
  else
   /* return to traced function */
   emit_jalr(RV_REG_ZERO, RV_REG_T0, 0, ctx);
 } else {
  /* trampoline called directly */
  emit_ld(RV_REG_RA, stack_size - 8, RV_REG_SP, ctx);
  emit_ld(RV_REG_FP, stack_size - 16, RV_REG_SP, ctx);
  emit_addi(RV_REG_SP, RV_REG_SP, stack_size, ctx);

  emit_jalr(RV_REG_ZERO, RV_REG_RA, 0, ctx);
 }

 ret = ctx->ninsns;
out:
 kfree(branches_off);
 return ret;
}

int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
        struct bpf_tramp_links *tlinks, void *func_addr)
{
 struct bpf_tramp_image im;
 struct rv_jit_context ctx;
 int ret;

 ctx.ninsns = 0;
 ctx.insns = NULL;
 ctx.ro_insns = NULL;
 ret = __arch_prepare_bpf_trampoline(&im, m, tlinks, func_addr, flags, &ctx);

 return ret < 0 ? ret : ninsns_rvoff(ctx.ninsns);
}

void *arch_alloc_bpf_trampoline(unsigned int size)
{
 return bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
}

void arch_free_bpf_trampoline(void *image, unsigned int size)
{
 bpf_prog_pack_free(image, size);
}

int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
    void *ro_image_end, const struct btf_func_model *m,
    u32 flags, struct bpf_tramp_links *tlinks,
    void *func_addr)
{
 int ret;
 void *image, *res;
 struct rv_jit_context ctx;
 u32 size = ro_image_end - ro_image;

 image = kvmalloc(size, GFP_KERNEL);
 if (!image)
  return -ENOMEM;

 ctx.ninsns = 0;
 ctx.insns = image;
 ctx.ro_insns = ro_image;
 ret = __arch_prepare_bpf_trampoline(im, m, tlinks, func_addr, flags, &ctx);
 if (ret < 0)
  goto out;

 if (WARN_ON(size < ninsns_rvoff(ctx.ninsns))) {
  ret = -E2BIG;
  goto out;
 }

 res = bpf_arch_text_copy(ro_image, image, size);
 if (IS_ERR(res)) {
  ret = PTR_ERR(res);
  goto out;
 }

 bpf_flush_icache(ro_image, ro_image_end);
out:
 kvfree(image);
 return ret < 0 ? ret : size;
}

int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
        bool extra_pass)
{
 bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 ||
      BPF_CLASS(insn->code) == BPF_JMP;
 int s, e, rvoff, ret, i = insn - ctx->prog->insnsi;
 struct bpf_prog_aux *aux = ctx->prog->aux;
 u8 rd = -1, rs = -1, code = insn->code;
 s16 off = insn->off;
 s32 imm = insn->imm;

 init_regs(&rd, &rs, insn, ctx);

 switch (code) {
 /* dst = src */
 case BPF_ALU | BPF_MOV | BPF_X:
 case BPF_ALU64 | BPF_MOV | BPF_X:
  if (insn_is_cast_user(insn)) {
   emit_mv(RV_REG_T1, rs, ctx);
   emit_zextw(RV_REG_T1, RV_REG_T1, ctx);
   emit_imm(rd, (ctx->user_vm_start >> 32) << 32, ctx);
   emit(rv_beq(RV_REG_T1, RV_REG_ZERO, 4), ctx);
   emit_or(RV_REG_T1, rd, RV_REG_T1, ctx);
   emit_mv(rd, RV_REG_T1, ctx);
   break;
  } else if (insn_is_mov_percpu_addr(insn)) {
   if (rd != rs)
    emit_mv(rd, rs, ctx);
#ifdef CONFIG_SMP
   /* Load current CPU number in T1 */
   emit_lw(RV_REG_T1, offsetof(struct thread_info, cpu),
    RV_REG_TP, ctx);
   /* Load address of __per_cpu_offset array in T2 */
   emit_addr(RV_REG_T2, (u64)&__per_cpu_offset, extra_pass, ctx);
   /* Get address of __per_cpu_offset[cpu] in T1 */
   emit_sh3add(RV_REG_T1, RV_REG_T1, RV_REG_T2, ctx);
   /* Load __per_cpu_offset[cpu] in T1 */
   emit_ld(RV_REG_T1, 0, RV_REG_T1, ctx);
   /* Add the offset to Rd */
   emit_add(rd, rd, RV_REG_T1, ctx);
#endif
  }
  if (imm == 1) {
   /* Special mov32 for zext */
   emit_zextw(rd, rd, ctx);
   break;
  }
  switch (insn->off) {
  case 0:
   emit_mv(rd, rs, ctx);
   break;
  case 8:
   emit_sextb(rd, rs, ctx);
   break;
  case 16:
   emit_sexth(rd, rs, ctx);
   break;
  case 32:
   emit_sextw(rd, rs, ctx);
   break;
  }
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;

 /* dst = dst OP src */
 case BPF_ALU | BPF_ADD | BPF_X:
 case BPF_ALU64 | BPF_ADD | BPF_X:
  emit_add(rd, rd, rs, ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_SUB | BPF_X:
 case BPF_ALU64 | BPF_SUB | BPF_X:
  if (is64)
   emit_sub(rd, rd, rs, ctx);
  else
   emit_subw(rd, rd, rs, ctx);

  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_AND | BPF_X:
 case BPF_ALU64 | BPF_AND | BPF_X:
  emit_and(rd, rd, rs, ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_OR | BPF_X:
 case BPF_ALU64 | BPF_OR | BPF_X:
  emit_or(rd, rd, rs, ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_XOR | BPF_X:
 case BPF_ALU64 | BPF_XOR | BPF_X:
  emit_xor(rd, rd, rs, ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_MUL | BPF_X:
 case BPF_ALU64 | BPF_MUL | BPF_X:
  emit(is64 ? rv_mul(rd, rd, rs) : rv_mulw(rd, rd, rs), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_DIV | BPF_X:
 case BPF_ALU64 | BPF_DIV | BPF_X:
  if (off)
   emit(is64 ? rv_div(rd, rd, rs) : rv_divw(rd, rd, rs), ctx);
  else
   emit(is64 ? rv_divu(rd, rd, rs) : rv_divuw(rd, rd, rs), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_MOD | BPF_X:
 case BPF_ALU64 | BPF_MOD | BPF_X:
  if (off)
   emit(is64 ? rv_rem(rd, rd, rs) : rv_remw(rd, rd, rs), ctx);
  else
   emit(is64 ? rv_remu(rd, rd, rs) : rv_remuw(rd, rd, rs), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_LSH | BPF_X:
 case BPF_ALU64 | BPF_LSH | BPF_X:
  emit(is64 ? rv_sll(rd, rd, rs) : rv_sllw(rd, rd, rs), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_RSH | BPF_X:
 case BPF_ALU64 | BPF_RSH | BPF_X:
  emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_ARSH | BPF_X:
 case BPF_ALU64 | BPF_ARSH | BPF_X:
  emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;

 /* dst = -dst */
 case BPF_ALU | BPF_NEG:
 case BPF_ALU64 | BPF_NEG:
  emit_sub(rd, RV_REG_ZERO, rd, ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;

 /* dst = BSWAP##imm(dst) */
 case BPF_ALU | BPF_END | BPF_FROM_LE:
  switch (imm) {
  case 16:
   emit_zexth(rd, rd, ctx);
   break;
  case 32:
   if (!aux->verifier_zext)
    emit_zextw(rd, rd, ctx);
   break;
  case 64:
   /* Do nothing */
   break;
  }
  break;
 case BPF_ALU | BPF_END | BPF_FROM_BE:
 case BPF_ALU64 | BPF_END | BPF_FROM_LE:
  emit_bswap(rd, imm, ctx);
  break;

 /* dst = imm */
 case BPF_ALU | BPF_MOV | BPF_K:
 case BPF_ALU64 | BPF_MOV | BPF_K:
  emit_imm(rd, imm, ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;

 /* dst = dst OP imm */
 case BPF_ALU | BPF_ADD | BPF_K:
 case BPF_ALU64 | BPF_ADD | BPF_K:
  if (is_12b_int(imm)) {
   emit_addi(rd, rd, imm, ctx);
  } else {
   emit_imm(RV_REG_T1, imm, ctx);
   emit_add(rd, rd, RV_REG_T1, ctx);
  }
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_SUB | BPF_K:
 case BPF_ALU64 | BPF_SUB | BPF_K:
  if (is_12b_int(-imm)) {
   emit_addi(rd, rd, -imm, ctx);
  } else {
   emit_imm(RV_REG_T1, imm, ctx);
   emit_sub(rd, rd, RV_REG_T1, ctx);
  }
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_AND | BPF_K:
 case BPF_ALU64 | BPF_AND | BPF_K:
  if (is_12b_int(imm)) {
   emit_andi(rd, rd, imm, ctx);
  } else {
   emit_imm(RV_REG_T1, imm, ctx);
   emit_and(rd, rd, RV_REG_T1, ctx);
  }
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_OR | BPF_K:
 case BPF_ALU64 | BPF_OR | BPF_K:
  if (is_12b_int(imm)) {
   emit(rv_ori(rd, rd, imm), ctx);
  } else {
   emit_imm(RV_REG_T1, imm, ctx);
   emit_or(rd, rd, RV_REG_T1, ctx);
  }
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_XOR | BPF_K:
 case BPF_ALU64 | BPF_XOR | BPF_K:
  if (is_12b_int(imm)) {
   emit(rv_xori(rd, rd, imm), ctx);
  } else {
   emit_imm(RV_REG_T1, imm, ctx);
   emit_xor(rd, rd, RV_REG_T1, ctx);
  }
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_MUL | BPF_K:
 case BPF_ALU64 | BPF_MUL | BPF_K:
  emit_imm(RV_REG_T1, imm, ctx);
  emit(is64 ? rv_mul(rd, rd, RV_REG_T1) :
       rv_mulw(rd, rd, RV_REG_T1), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_DIV | BPF_K:
 case BPF_ALU64 | BPF_DIV | BPF_K:
  emit_imm(RV_REG_T1, imm, ctx);
  if (off)
   emit(is64 ? rv_div(rd, rd, RV_REG_T1) :
        rv_divw(rd, rd, RV_REG_T1), ctx);
  else
   emit(is64 ? rv_divu(rd, rd, RV_REG_T1) :
        rv_divuw(rd, rd, RV_REG_T1), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_MOD | BPF_K:
 case BPF_ALU64 | BPF_MOD | BPF_K:
  emit_imm(RV_REG_T1, imm, ctx);
  if (off)
   emit(is64 ? rv_rem(rd, rd, RV_REG_T1) :
        rv_remw(rd, rd, RV_REG_T1), ctx);
  else
   emit(is64 ? rv_remu(rd, rd, RV_REG_T1) :
        rv_remuw(rd, rd, RV_REG_T1), ctx);
  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_LSH | BPF_K:
 case BPF_ALU64 | BPF_LSH | BPF_K:
  emit_slli(rd, rd, imm, ctx);

  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_RSH | BPF_K:
 case BPF_ALU64 | BPF_RSH | BPF_K:
  if (is64)
   emit_srli(rd, rd, imm, ctx);
  else
   emit(rv_srliw(rd, rd, imm), ctx);

  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;
 case BPF_ALU | BPF_ARSH | BPF_K:
 case BPF_ALU64 | BPF_ARSH | BPF_K:
  if (is64)
   emit_srai(rd, rd, imm, ctx);
  else
   emit(rv_sraiw(rd, rd, imm), ctx);

  if (!is64 && !aux->verifier_zext)
   emit_zextw(rd, rd, ctx);
  break;

 /* JUMP off */
 case BPF_JMP | BPF_JA:
 case BPF_JMP32 | BPF_JA:
  if (BPF_CLASS(code) == BPF_JMP)
   rvoff = rv_offset(i, off, ctx);
  else
   rvoff = rv_offset(i, imm, ctx);
  ret = emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
  if (ret)
   return ret;
  break;

 /* IF (dst COND src) JUMP off */
 case BPF_JMP | BPF_JEQ | BPF_X:
 case BPF_JMP32 | BPF_JEQ | BPF_X:
 case BPF_JMP | BPF_JGT | BPF_X:
 case BPF_JMP32 | BPF_JGT | BPF_X:
 case BPF_JMP | BPF_JLT | BPF_X:
 case BPF_JMP32 | BPF_JLT | BPF_X:
 case BPF_JMP | BPF_JGE | BPF_X:
 case BPF_JMP32 | BPF_JGE | BPF_X:
 case BPF_JMP | BPF_JLE | BPF_X:
 case BPF_JMP32 | BPF_JLE | BPF_X:
 case BPF_JMP | BPF_JNE | BPF_X:
 case BPF_JMP32 | BPF_JNE | BPF_X:
 case BPF_JMP | BPF_JSGT | BPF_X:
 case BPF_JMP32 | BPF_JSGT | BPF_X:
 case BPF_JMP | BPF_JSLT | BPF_X:
 case BPF_JMP32 | BPF_JSLT | BPF_X:
 case BPF_JMP | BPF_JSGE | BPF_X:
 case BPF_JMP32 | BPF_JSGE | BPF_X:
 case BPF_JMP | BPF_JSLE | BPF_X:
 case BPF_JMP32 | BPF_JSLE | BPF_X:
 case BPF_JMP | BPF_JSET | BPF_X:
 case BPF_JMP32 | BPF_JSET | BPF_X:
  rvoff = rv_offset(i, off, ctx);
  if (!is64) {
   s = ctx->ninsns;
   if (is_signed_bpf_cond(BPF_OP(code))) {
    emit_sextw_alt(&rs, RV_REG_T1, ctx);
    emit_sextw_alt(&rd, RV_REG_T2, ctx);
   } else {
    emit_zextw_alt(&rs, RV_REG_T1, ctx);
    emit_zextw_alt(&rd, RV_REG_T2, ctx);
   }
   e = ctx->ninsns;

   /* Adjust for extra insns */
   rvoff -= ninsns_rvoff(e - s);
  }

  if (BPF_OP(code) == BPF_JSET) {
   /* Adjust for and */
   rvoff -= 4;
   emit_and(RV_REG_T1, rd, rs, ctx);
   emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, ctx);
  } else {
   emit_branch(BPF_OP(code), rd, rs, rvoff, ctx);
  }
  break;

 /* IF (dst COND imm) JUMP off */
 case BPF_JMP | BPF_JEQ | BPF_K:
 case BPF_JMP32 | BPF_JEQ | BPF_K:
 case BPF_JMP | BPF_JGT | BPF_K:
 case BPF_JMP32 | BPF_JGT | BPF_K:
 case BPF_JMP | BPF_JLT | BPF_K:
 case BPF_JMP32 | BPF_JLT | BPF_K:
 case BPF_JMP | BPF_JGE | BPF_K:
 case BPF_JMP32 | BPF_JGE | BPF_K:
 case BPF_JMP | BPF_JLE | BPF_K:
 case BPF_JMP32 | BPF_JLE | BPF_K:
 case BPF_JMP | BPF_JNE | BPF_K:
 case BPF_JMP32 | BPF_JNE | BPF_K:
 case BPF_JMP | BPF_JSGT | BPF_K:
 case BPF_JMP32 | BPF_JSGT | BPF_K:
 case BPF_JMP | BPF_JSLT | BPF_K:
 case BPF_JMP32 | BPF_JSLT | BPF_K:
 case BPF_JMP | BPF_JSGE | BPF_K:
 case BPF_JMP32 | BPF_JSGE | BPF_K:
 case BPF_JMP | BPF_JSLE | BPF_K:
 case BPF_JMP32 | BPF_JSLE | BPF_K:
  rvoff = rv_offset(i, off, ctx);
  s = ctx->ninsns;
  if (imm)
   emit_imm(RV_REG_T1, imm, ctx);
  rs = imm ? RV_REG_T1 : RV_REG_ZERO;
  if (!is64) {
   if (is_signed_bpf_cond(BPF_OP(code))) {
    emit_sextw_alt(&rd, RV_REG_T2, ctx);
    /* rs has been sign extended */
   } else {
    emit_zextw_alt(&rd, RV_REG_T2, ctx);
    if (imm)
     emit_zextw(rs, rs, ctx);
   }
  }
  e = ctx->ninsns;

  /* Adjust for extra insns */
  rvoff -= ninsns_rvoff(e - s);
  emit_branch(BPF_OP(code), rd, rs, rvoff, ctx);
  break;

 case BPF_JMP | BPF_JSET | BPF_K:
 case BPF_JMP32 | BPF_JSET | BPF_K:
  rvoff = rv_offset(i, off, ctx);
  s = ctx->ninsns;
  if (is_12b_int(imm)) {
   emit_andi(RV_REG_T1, rd, imm, ctx);
  } else {
   emit_imm(RV_REG_T1, imm, ctx);
   emit_and(RV_REG_T1, rd, RV_REG_T1, ctx);
  }
  /* For jset32, we should clear the upper 32 bits of t1, but
   * sign-extension is sufficient here and saves one instruction,
   * as t1 is used only in comparison against zero.
 */

  if (!is64 && imm < 0)
   emit_sextw(RV_REG_T1, RV_REG_T1, ctx);
  e = ctx->ninsns;
  rvoff -= ninsns_rvoff(e - s);
  emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, ctx);
  break;

 /* function call */
 case BPF_JMP | BPF_CALL:
 {
  bool fixed_addr;
  u64 addr;

  /* Inline calls to bpf_get_smp_processor_id()
   *
   * RV_REG_TP holds the address of the current CPU's task_struct and thread_info is
   * at offset 0 in task_struct.
   * Load cpu from thread_info:
   *     Set R0 to ((struct thread_info *)(RV_REG_TP))->cpu
   *
   * This replicates the implementation of raw_smp_processor_id() on RISCV
 */

  if (insn->src_reg == 0 && insn->imm == BPF_FUNC_get_smp_processor_id) {
   /* Load current CPU number in R0 */
   emit_lw(bpf_to_rv_reg(BPF_REG_0, ctx), offsetof(struct thread_info, cpu),
    RV_REG_TP, ctx);
   break;
  }

  mark_call(ctx);
  ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
         &addr, &fixed_addr);
  if (ret < 0)
   return ret;

  if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
   const struct btf_func_model *fm;
   int idx;

   fm = bpf_jit_find_kfunc_model(ctx->prog, insn);
   if (!fm)
    return -EINVAL;

   for (idx = 0; idx < fm->nr_args; idx++) {
    u8 reg = bpf_to_rv_reg(BPF_REG_1 + idx, ctx);

    if (fm->arg_size[idx] == sizeof(int))
     emit_sextw(reg, reg, ctx);
   }
  }

  ret = emit_call(addr, fixed_addr, ctx);
  if (ret)
   return ret;

  if (insn->src_reg != BPF_PSEUDO_CALL)
   emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx);
  break;
 }
 /* tail call */
 case BPF_JMP | BPF_TAIL_CALL:
  if (emit_bpf_tail_call(i, ctx))
   return -1;
  break;

 /* function return */
 case BPF_JMP | BPF_EXIT:
  if (i == ctx->prog->len - 1)
   break;

  rvoff = epilogue_offset(ctx);
  ret = emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
  if (ret)
   return ret;
  break;

 /* dst = imm64 */
 case BPF_LD | BPF_IMM | BPF_DW:
 {
  struct bpf_insn insn1 = insn[1];
  u64 imm64;

  imm64 = (u64)insn1.imm << 32 | (u32)imm;
  if (bpf_pseudo_func(insn)) {
   /* fixed-length insns for extra jit pass */
   ret = emit_addr(rd, imm64, extra_pass, ctx);
   if (ret)
    return ret;
  } else {
   emit_imm(rd, imm64, ctx);
  }

  return 1;
 }

 /* LDX: dst = *(unsigned size *)(src + off) */
 case BPF_LDX | BPF_MEM | BPF_B:
 case BPF_LDX | BPF_MEM | BPF_H:
 case BPF_LDX | BPF_MEM | BPF_W:
 case BPF_LDX | BPF_MEM | BPF_DW:
 case BPF_LDX | BPF_PROBE_MEM | BPF_B:
 case BPF_LDX | BPF_PROBE_MEM | BPF_H:
 case BPF_LDX | BPF_PROBE_MEM | BPF_W:
 case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
 /* LDSX: dst = *(signed size *)(src + 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:
 /* LDX | PROBE_MEM32: dst = *(unsigned size *)(src + RV_REG_ARENA + 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:
 {
  bool sign_ext;
  int insn_len;

  sign_ext = BPF_MODE(insn->code) == BPF_MEMSX ||
      BPF_MODE(insn->code) == BPF_PROBE_MEMSX;

  if (BPF_MODE(insn->code) == BPF_PROBE_MEM32) {
   emit_add(RV_REG_T2, rs, RV_REG_ARENA, ctx);
   rs = RV_REG_T2;
  }

  switch (BPF_SIZE(code)) {
  case BPF_B:
   insn_len = emit_load_8(sign_ext, rd, off, rs, ctx);
   break;
  case BPF_H:
   insn_len = emit_load_16(sign_ext, rd, off, rs, ctx);
   break;
  case BPF_W:
   insn_len = emit_load_32(sign_ext, rd, off, rs, ctx);
   break;
  case BPF_DW:
   insn_len = emit_load_64(sign_ext, rd, off, rs, ctx);
   break;
  }

  ret = add_exception_handler(insn, ctx, rd, insn_len);
  if (ret)
   return ret;

  if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
   return 1;
  break;
 }
 /* speculation barrier */
 case BPF_ST | BPF_NOSPEC:
  break;

 /* ST: *(size *)(dst + off) = imm */
 case BPF_ST | BPF_MEM | BPF_B:
  emit_imm(RV_REG_T1, imm, ctx);
  if (is_12b_int(off)) {
   emit(rv_sb(rd, off, RV_REG_T1), ctx);
   break;
  }

  emit_imm(RV_REG_T2, off, ctx);
  emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
  emit(rv_sb(RV_REG_T2, 0, RV_REG_T1), ctx);
  break;

 case BPF_ST | BPF_MEM | BPF_H:
  emit_imm(RV_REG_T1, imm, ctx);
  if (is_12b_int(off)) {
   emit(rv_sh(rd, off, RV_REG_T1), ctx);
   break;
  }

  emit_imm(RV_REG_T2, off, ctx);
  emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
  emit(rv_sh(RV_REG_T2, 0, RV_REG_T1), ctx);
  break;
 case BPF_ST | BPF_MEM | BPF_W:
  emit_imm(RV_REG_T1, imm, ctx);
  if (is_12b_int(off)) {
   emit_sw(rd, off, RV_REG_T1, ctx);
   break;
  }

  emit_imm(RV_REG_T2, off, ctx);
  emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
  emit_sw(RV_REG_T2, 0, RV_REG_T1, ctx);
  break;
 case BPF_ST | BPF_MEM | BPF_DW:
  emit_imm(RV_REG_T1, imm, ctx);
  if (is_12b_int(off)) {
   emit_sd(rd, off, RV_REG_T1, ctx);
   break;
  }

  emit_imm(RV_REG_T2, off, ctx);
  emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
  emit_sd(RV_REG_T2, 0, RV_REG_T1, ctx);
  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:
 {
  int insn_len, insns_start;

  emit_add(RV_REG_T3, rd, RV_REG_ARENA, ctx);
  rd = RV_REG_T3;

  /* Load imm to a register then store it */
  emit_imm(RV_REG_T1, imm, ctx);

  switch (BPF_SIZE(code)) {
  case BPF_B:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit(rv_sb(rd, off, RV_REG_T1), ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T2, off, ctx);
   emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
   insns_start = ctx->ninsns;
   emit(rv_sb(RV_REG_T2, 0, RV_REG_T1), ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  case BPF_H:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit(rv_sh(rd, off, RV_REG_T1), ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T2, off, ctx);
   emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
   insns_start = ctx->ninsns;
   emit(rv_sh(RV_REG_T2, 0, RV_REG_T1), ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  case BPF_W:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit_sw(rd, off, RV_REG_T1, ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T2, off, ctx);
   emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
   insns_start = ctx->ninsns;
   emit_sw(RV_REG_T2, 0, RV_REG_T1, ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  case BPF_DW:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit_sd(rd, off, RV_REG_T1, ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T2, off, ctx);
   emit_add(RV_REG_T2, RV_REG_T2, rd, ctx);
   insns_start = ctx->ninsns;
   emit_sd(RV_REG_T2, 0, RV_REG_T1, ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  }

  ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER,
         insn_len);
  if (ret)
   return ret;

  break;
 }

 /* STX: *(size *)(dst + off) = src */
 case BPF_STX | BPF_MEM | BPF_B:
  emit_store_8(rd, off, rs, ctx);
  break;
 case BPF_STX | BPF_MEM | BPF_H:
  emit_store_16(rd, off, rs, ctx);
  break;
 case BPF_STX | BPF_MEM | BPF_W:
  emit_store_32(rd, off, rs, ctx);
  break;
 case BPF_STX | BPF_MEM | BPF_DW:
  emit_store_64(rd, off, rs, ctx);
  break;
 case BPF_STX | BPF_ATOMIC | BPF_B:
 case BPF_STX | BPF_ATOMIC | BPF_H:
 case BPF_STX | BPF_ATOMIC | BPF_W:
 case BPF_STX | BPF_ATOMIC | BPF_DW:
  if (bpf_atomic_is_load_store(insn))
   ret = emit_atomic_ld_st(rd, rs, insn, ctx);
  else
   ret = emit_atomic_rmw(rd, rs, insn, ctx);
  if (ret)
   return ret;
  break;

 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:
 {
  int insn_len, insns_start;

  emit_add(RV_REG_T2, rd, RV_REG_ARENA, ctx);
  rd = RV_REG_T2;

  switch (BPF_SIZE(code)) {
  case BPF_B:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit(rv_sb(rd, off, rs), ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T1, off, ctx);
   emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
   insns_start = ctx->ninsns;
   emit(rv_sb(RV_REG_T1, 0, rs), ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  case BPF_H:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit(rv_sh(rd, off, rs), ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T1, off, ctx);
   emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
   insns_start = ctx->ninsns;
   emit(rv_sh(RV_REG_T1, 0, rs), ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  case BPF_W:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit_sw(rd, off, rs, ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T1, off, ctx);
   emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
   insns_start = ctx->ninsns;
   emit_sw(RV_REG_T1, 0, rs, ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  case BPF_DW:
   if (is_12b_int(off)) {
    insns_start = ctx->ninsns;
    emit_sd(rd, off, rs, ctx);
    insn_len = ctx->ninsns - insns_start;
    break;
   }

   emit_imm(RV_REG_T1, off, ctx);
   emit_add(RV_REG_T1, RV_REG_T1, rd, ctx);
   insns_start = ctx->ninsns;
   emit_sd(RV_REG_T1, 0, rs, ctx);
   insn_len = ctx->ninsns - insns_start;
   break;
  }

  ret = add_exception_handler(insn, ctx, REG_DONT_CLEAR_MARKER,
         insn_len);
  if (ret)
   return ret;

  break;
 }

 default:
  pr_err("bpf-jit: unknown opcode %02x\n", code);
  return -EINVAL;
 }

 return 0;
}

void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
{
 int i, stack_adjust = 0, store_offset, bpf_stack_adjust;

 bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, STACK_ALIGN);
 if (bpf_stack_adjust)
  mark_fp(ctx);

 if (seen_reg(RV_REG_RA, ctx))
  stack_adjust += 8;
 stack_adjust += 8; /* RV_REG_FP */
 if (seen_reg(RV_REG_S1, ctx))
  stack_adjust += 8;
 if (seen_reg(RV_REG_S2, ctx))
  stack_adjust += 8;
 if (seen_reg(RV_REG_S3, ctx))
  stack_adjust += 8;
 if (seen_reg(RV_REG_S4, ctx))
  stack_adjust += 8;
 if (seen_reg(RV_REG_S5, ctx))
  stack_adjust += 8;
 if (seen_reg(RV_REG_S6, ctx))
  stack_adjust += 8;
 if (ctx->arena_vm_start)
  stack_adjust += 8;

 stack_adjust = round_up(stack_adjust, STACK_ALIGN);
 stack_adjust += bpf_stack_adjust;

 store_offset = stack_adjust - 8;

 /* emit kcfi type preamble immediately before the  first insn */
 emit_kcfi(is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash, ctx);

 /* nops reserved for auipc+jalr pair */
 for (i = 0; i < RV_FENTRY_NINSNS; i++)
  emit(rv_nop(), ctx);

 /* First instruction is always setting the tail-call-counter
  * (TCC) register. This instruction is skipped for tail calls.
  * Force using a 4-byte (non-compressed) instruction.
 */

 emit(rv_addi(RV_REG_TCC, RV_REG_ZERO, MAX_TAIL_CALL_CNT), ctx);

 emit_addi(RV_REG_SP, RV_REG_SP, -stack_adjust, ctx);

 if (seen_reg(RV_REG_RA, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_RA, ctx);
  store_offset -= 8;
 }
 emit_sd(RV_REG_SP, store_offset, RV_REG_FP, ctx);
 store_offset -= 8;
 if (seen_reg(RV_REG_S1, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_S1, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S2, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_S2, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S3, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_S3, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S4, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_S4, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S5, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_S5, ctx);
  store_offset -= 8;
 }
 if (seen_reg(RV_REG_S6, ctx)) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_S6, ctx);
  store_offset -= 8;
 }
 if (ctx->arena_vm_start) {
  emit_sd(RV_REG_SP, store_offset, RV_REG_ARENA, ctx);
  store_offset -= 8;
 }

 emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx);

 if (bpf_stack_adjust)
  emit_addi(RV_REG_S5, RV_REG_SP, bpf_stack_adjust, ctx);

 /* Program contains calls and tail calls, so RV_REG_TCC need
  * to be saved across calls.
 */

 if (seen_tail_call(ctx) && seen_call(ctx))
  emit_mv(RV_REG_TCC_SAVED, RV_REG_TCC, ctx);

 ctx->stack_size = stack_adjust;

 if (ctx->arena_vm_start)
  emit_imm(RV_REG_ARENA, ctx->arena_vm_start, ctx);
}

void bpf_jit_build_epilogue(struct rv_jit_context *ctx)
{
 __build_epilogue(false, ctx);
}

bool bpf_jit_supports_kfunc_call(void)
{
 return true;
}

bool bpf_jit_supports_ptr_xchg(void)
{
 return true;
}

bool bpf_jit_supports_arena(void)
{
 return true;
}

bool bpf_jit_supports_percpu_insn(void)
{
 return true;
}

bool bpf_jit_inlines_helper_call(s32 imm)
{
 switch (imm) {
 case BPF_FUNC_get_smp_processor_id:
  return true;
 default:
  return false;
 }
}

Messung V0.5 in Prozent
C=94 H=94 G=93

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.30Angebot  ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.