162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * BPF JIT compiler for RV32G 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020 Luke Nelson <luke.r.nels@gmail.com> 662306a36Sopenharmony_ci * Copyright (c) 2020 Xi Wang <xi.wang@gmail.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * The code is based on the BPF JIT compiler for RV64G by Björn Töpel and 962306a36Sopenharmony_ci * the BPF JIT compiler for 32-bit ARM by Shubham Bansal and Mircea Gherzan. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/bpf.h> 1362306a36Sopenharmony_ci#include <linux/filter.h> 1462306a36Sopenharmony_ci#include "bpf_jit.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * Stack layout during BPF program execution: 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * high 2062306a36Sopenharmony_ci * RV32 fp => +----------+ 2162306a36Sopenharmony_ci * | saved ra | 2262306a36Sopenharmony_ci * | saved fp | RV32 callee-saved registers 2362306a36Sopenharmony_ci * | ... | 2462306a36Sopenharmony_ci * +----------+ <= (fp - 4 * NR_SAVED_REGISTERS) 2562306a36Sopenharmony_ci * | hi(R6) | 2662306a36Sopenharmony_ci * | lo(R6) | 2762306a36Sopenharmony_ci * | hi(R7) | JIT scratch space for BPF registers 2862306a36Sopenharmony_ci * | lo(R7) | 2962306a36Sopenharmony_ci * | ... | 3062306a36Sopenharmony_ci * BPF_REG_FP => +----------+ <= (fp - 4 * NR_SAVED_REGISTERS 3162306a36Sopenharmony_ci * | | - 4 * BPF_JIT_SCRATCH_REGS) 3262306a36Sopenharmony_ci * | | 3362306a36Sopenharmony_ci * | ... | BPF program stack 3462306a36Sopenharmony_ci * | | 3562306a36Sopenharmony_ci * RV32 sp => +----------+ 3662306a36Sopenharmony_ci * | | 3762306a36Sopenharmony_ci * | ... | Function call stack 3862306a36Sopenharmony_ci * | | 3962306a36Sopenharmony_ci * +----------+ 4062306a36Sopenharmony_ci * low 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cienum { 4462306a36Sopenharmony_ci /* Stack layout - these are offsets from top of JIT scratch space. */ 4562306a36Sopenharmony_ci BPF_R6_HI, 4662306a36Sopenharmony_ci BPF_R6_LO, 4762306a36Sopenharmony_ci BPF_R7_HI, 4862306a36Sopenharmony_ci BPF_R7_LO, 4962306a36Sopenharmony_ci BPF_R8_HI, 5062306a36Sopenharmony_ci BPF_R8_LO, 5162306a36Sopenharmony_ci BPF_R9_HI, 5262306a36Sopenharmony_ci BPF_R9_LO, 5362306a36Sopenharmony_ci BPF_AX_HI, 5462306a36Sopenharmony_ci BPF_AX_LO, 5562306a36Sopenharmony_ci /* Stack space for BPF_REG_6 through BPF_REG_9 and BPF_REG_AX. */ 5662306a36Sopenharmony_ci BPF_JIT_SCRATCH_REGS, 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Number of callee-saved registers stored to stack: ra, fp, s1--s7. */ 6062306a36Sopenharmony_ci#define NR_SAVED_REGISTERS 9 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Offset from fp for BPF registers stored on stack. */ 6362306a36Sopenharmony_ci#define STACK_OFFSET(k) (-4 - (4 * NR_SAVED_REGISTERS) - (4 * (k))) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define TMP_REG_1 (MAX_BPF_JIT_REG + 0) 6662306a36Sopenharmony_ci#define TMP_REG_2 (MAX_BPF_JIT_REG + 1) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define RV_REG_TCC RV_REG_T6 6962306a36Sopenharmony_ci#define RV_REG_TCC_SAVED RV_REG_S7 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic const s8 bpf2rv32[][2] = { 7262306a36Sopenharmony_ci /* Return value from in-kernel function, and exit value from eBPF. */ 7362306a36Sopenharmony_ci [BPF_REG_0] = {RV_REG_S2, RV_REG_S1}, 7462306a36Sopenharmony_ci /* Arguments from eBPF program to in-kernel function. */ 7562306a36Sopenharmony_ci [BPF_REG_1] = {RV_REG_A1, RV_REG_A0}, 7662306a36Sopenharmony_ci [BPF_REG_2] = {RV_REG_A3, RV_REG_A2}, 7762306a36Sopenharmony_ci [BPF_REG_3] = {RV_REG_A5, RV_REG_A4}, 7862306a36Sopenharmony_ci [BPF_REG_4] = {RV_REG_A7, RV_REG_A6}, 7962306a36Sopenharmony_ci [BPF_REG_5] = {RV_REG_S4, RV_REG_S3}, 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * Callee-saved registers that in-kernel function will preserve. 8262306a36Sopenharmony_ci * Stored on the stack. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci [BPF_REG_6] = {STACK_OFFSET(BPF_R6_HI), STACK_OFFSET(BPF_R6_LO)}, 8562306a36Sopenharmony_ci [BPF_REG_7] = {STACK_OFFSET(BPF_R7_HI), STACK_OFFSET(BPF_R7_LO)}, 8662306a36Sopenharmony_ci [BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)}, 8762306a36Sopenharmony_ci [BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)}, 8862306a36Sopenharmony_ci /* Read-only frame pointer to access BPF stack. */ 8962306a36Sopenharmony_ci [BPF_REG_FP] = {RV_REG_S6, RV_REG_S5}, 9062306a36Sopenharmony_ci /* Temporary register for blinding constants. Stored on the stack. */ 9162306a36Sopenharmony_ci [BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)}, 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * Temporary registers used by the JIT to operate on registers stored 9462306a36Sopenharmony_ci * on the stack. Save t0 and t1 to be used as temporaries in generated 9562306a36Sopenharmony_ci * code. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci [TMP_REG_1] = {RV_REG_T3, RV_REG_T2}, 9862306a36Sopenharmony_ci [TMP_REG_2] = {RV_REG_T5, RV_REG_T4}, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic s8 hi(const s8 *r) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return r[0]; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic s8 lo(const s8 *r) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return r[1]; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void emit_imm(const s8 rd, s32 imm, struct rv_jit_context *ctx) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci u32 upper = (imm + (1 << 11)) >> 12; 11462306a36Sopenharmony_ci u32 lower = imm & 0xfff; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (upper) { 11762306a36Sopenharmony_ci emit(rv_lui(rd, upper), ctx); 11862306a36Sopenharmony_ci emit(rv_addi(rd, rd, lower), ctx); 11962306a36Sopenharmony_ci } else { 12062306a36Sopenharmony_ci emit(rv_addi(rd, RV_REG_ZERO, lower), ctx); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void emit_imm32(const s8 *rd, s32 imm, struct rv_jit_context *ctx) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci /* Emit immediate into lower bits. */ 12762306a36Sopenharmony_ci emit_imm(lo(rd), imm, ctx); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Sign-extend into upper bits. */ 13062306a36Sopenharmony_ci if (imm >= 0) 13162306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, -1), ctx); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void emit_imm64(const s8 *rd, s32 imm_hi, s32 imm_lo, 13762306a36Sopenharmony_ci struct rv_jit_context *ctx) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci emit_imm(lo(rd), imm_lo, ctx); 14062306a36Sopenharmony_ci emit_imm(hi(rd), imm_hi, ctx); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci int stack_adjust = ctx->stack_size; 14662306a36Sopenharmony_ci const s8 *r0 = bpf2rv32[BPF_REG_0]; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* Set return value if not tail call. */ 14962306a36Sopenharmony_ci if (!is_tail_call) { 15062306a36Sopenharmony_ci emit(rv_addi(RV_REG_A0, lo(r0), 0), ctx); 15162306a36Sopenharmony_ci emit(rv_addi(RV_REG_A1, hi(r0), 0), ctx); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Restore callee-saved registers. */ 15562306a36Sopenharmony_ci emit(rv_lw(RV_REG_RA, stack_adjust - 4, RV_REG_SP), ctx); 15662306a36Sopenharmony_ci emit(rv_lw(RV_REG_FP, stack_adjust - 8, RV_REG_SP), ctx); 15762306a36Sopenharmony_ci emit(rv_lw(RV_REG_S1, stack_adjust - 12, RV_REG_SP), ctx); 15862306a36Sopenharmony_ci emit(rv_lw(RV_REG_S2, stack_adjust - 16, RV_REG_SP), ctx); 15962306a36Sopenharmony_ci emit(rv_lw(RV_REG_S3, stack_adjust - 20, RV_REG_SP), ctx); 16062306a36Sopenharmony_ci emit(rv_lw(RV_REG_S4, stack_adjust - 24, RV_REG_SP), ctx); 16162306a36Sopenharmony_ci emit(rv_lw(RV_REG_S5, stack_adjust - 28, RV_REG_SP), ctx); 16262306a36Sopenharmony_ci emit(rv_lw(RV_REG_S6, stack_adjust - 32, RV_REG_SP), ctx); 16362306a36Sopenharmony_ci emit(rv_lw(RV_REG_S7, stack_adjust - 36, RV_REG_SP), ctx); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci emit(rv_addi(RV_REG_SP, RV_REG_SP, stack_adjust), ctx); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (is_tail_call) { 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * goto *(t0 + 4); 17062306a36Sopenharmony_ci * Skips first instruction of prologue which initializes tail 17162306a36Sopenharmony_ci * call counter. Assumes t0 contains address of target program, 17262306a36Sopenharmony_ci * see emit_bpf_tail_call. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci emit(rv_jalr(RV_REG_ZERO, RV_REG_T0, 4), ctx); 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci emit(rv_jalr(RV_REG_ZERO, RV_REG_RA, 0), ctx); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic bool is_stacked(s8 reg) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return reg < 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const s8 *bpf_get_reg64(const s8 *reg, const s8 *tmp, 18662306a36Sopenharmony_ci struct rv_jit_context *ctx) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci if (is_stacked(hi(reg))) { 18962306a36Sopenharmony_ci emit(rv_lw(hi(tmp), hi(reg), RV_REG_FP), ctx); 19062306a36Sopenharmony_ci emit(rv_lw(lo(tmp), lo(reg), RV_REG_FP), ctx); 19162306a36Sopenharmony_ci reg = tmp; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci return reg; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void bpf_put_reg64(const s8 *reg, const s8 *src, 19762306a36Sopenharmony_ci struct rv_jit_context *ctx) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci if (is_stacked(hi(reg))) { 20062306a36Sopenharmony_ci emit(rv_sw(RV_REG_FP, hi(reg), hi(src)), ctx); 20162306a36Sopenharmony_ci emit(rv_sw(RV_REG_FP, lo(reg), lo(src)), ctx); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic const s8 *bpf_get_reg32(const s8 *reg, const s8 *tmp, 20662306a36Sopenharmony_ci struct rv_jit_context *ctx) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci if (is_stacked(lo(reg))) { 20962306a36Sopenharmony_ci emit(rv_lw(lo(tmp), lo(reg), RV_REG_FP), ctx); 21062306a36Sopenharmony_ci reg = tmp; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci return reg; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void bpf_put_reg32(const s8 *reg, const s8 *src, 21662306a36Sopenharmony_ci struct rv_jit_context *ctx) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci if (is_stacked(lo(reg))) { 21962306a36Sopenharmony_ci emit(rv_sw(RV_REG_FP, lo(reg), lo(src)), ctx); 22062306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 22162306a36Sopenharmony_ci emit(rv_sw(RV_REG_FP, hi(reg), RV_REG_ZERO), ctx); 22262306a36Sopenharmony_ci } else if (!ctx->prog->aux->verifier_zext) { 22362306a36Sopenharmony_ci emit(rv_addi(hi(reg), RV_REG_ZERO, 0), ctx); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void emit_jump_and_link(u8 rd, s32 rvoff, bool force_jalr, 22862306a36Sopenharmony_ci struct rv_jit_context *ctx) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci s32 upper, lower; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (rvoff && is_21b_int(rvoff) && !force_jalr) { 23362306a36Sopenharmony_ci emit(rv_jal(rd, rvoff >> 1), ctx); 23462306a36Sopenharmony_ci return; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci upper = (rvoff + (1 << 11)) >> 12; 23862306a36Sopenharmony_ci lower = rvoff & 0xfff; 23962306a36Sopenharmony_ci emit(rv_auipc(RV_REG_T1, upper), ctx); 24062306a36Sopenharmony_ci emit(rv_jalr(rd, RV_REG_T1, lower), ctx); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void emit_alu_i64(const s8 *dst, s32 imm, 24462306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 op) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 24762306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci switch (op) { 25062306a36Sopenharmony_ci case BPF_MOV: 25162306a36Sopenharmony_ci emit_imm32(rd, imm, ctx); 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case BPF_AND: 25462306a36Sopenharmony_ci if (is_12b_int(imm)) { 25562306a36Sopenharmony_ci emit(rv_andi(lo(rd), lo(rd), imm), ctx); 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 25862306a36Sopenharmony_ci emit(rv_and(lo(rd), lo(rd), RV_REG_T0), ctx); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci if (imm >= 0) 26162306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci case BPF_OR: 26462306a36Sopenharmony_ci if (is_12b_int(imm)) { 26562306a36Sopenharmony_ci emit(rv_ori(lo(rd), lo(rd), imm), ctx); 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 26862306a36Sopenharmony_ci emit(rv_or(lo(rd), lo(rd), RV_REG_T0), ctx); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci if (imm < 0) 27162306a36Sopenharmony_ci emit(rv_ori(hi(rd), RV_REG_ZERO, -1), ctx); 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci case BPF_XOR: 27462306a36Sopenharmony_ci if (is_12b_int(imm)) { 27562306a36Sopenharmony_ci emit(rv_xori(lo(rd), lo(rd), imm), ctx); 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 27862306a36Sopenharmony_ci emit(rv_xor(lo(rd), lo(rd), RV_REG_T0), ctx); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci if (imm < 0) 28162306a36Sopenharmony_ci emit(rv_xori(hi(rd), hi(rd), -1), ctx); 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci case BPF_LSH: 28462306a36Sopenharmony_ci if (imm >= 32) { 28562306a36Sopenharmony_ci emit(rv_slli(hi(rd), lo(rd), imm - 32), ctx); 28662306a36Sopenharmony_ci emit(rv_addi(lo(rd), RV_REG_ZERO, 0), ctx); 28762306a36Sopenharmony_ci } else if (imm == 0) { 28862306a36Sopenharmony_ci /* Do nothing. */ 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci emit(rv_srli(RV_REG_T0, lo(rd), 32 - imm), ctx); 29162306a36Sopenharmony_ci emit(rv_slli(hi(rd), hi(rd), imm), ctx); 29262306a36Sopenharmony_ci emit(rv_or(hi(rd), RV_REG_T0, hi(rd)), ctx); 29362306a36Sopenharmony_ci emit(rv_slli(lo(rd), lo(rd), imm), ctx); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case BPF_RSH: 29762306a36Sopenharmony_ci if (imm >= 32) { 29862306a36Sopenharmony_ci emit(rv_srli(lo(rd), hi(rd), imm - 32), ctx); 29962306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 30062306a36Sopenharmony_ci } else if (imm == 0) { 30162306a36Sopenharmony_ci /* Do nothing. */ 30262306a36Sopenharmony_ci } else { 30362306a36Sopenharmony_ci emit(rv_slli(RV_REG_T0, hi(rd), 32 - imm), ctx); 30462306a36Sopenharmony_ci emit(rv_srli(lo(rd), lo(rd), imm), ctx); 30562306a36Sopenharmony_ci emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx); 30662306a36Sopenharmony_ci emit(rv_srli(hi(rd), hi(rd), imm), ctx); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case BPF_ARSH: 31062306a36Sopenharmony_ci if (imm >= 32) { 31162306a36Sopenharmony_ci emit(rv_srai(lo(rd), hi(rd), imm - 32), ctx); 31262306a36Sopenharmony_ci emit(rv_srai(hi(rd), hi(rd), 31), ctx); 31362306a36Sopenharmony_ci } else if (imm == 0) { 31462306a36Sopenharmony_ci /* Do nothing. */ 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci emit(rv_slli(RV_REG_T0, hi(rd), 32 - imm), ctx); 31762306a36Sopenharmony_ci emit(rv_srli(lo(rd), lo(rd), imm), ctx); 31862306a36Sopenharmony_ci emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx); 31962306a36Sopenharmony_ci emit(rv_srai(hi(rd), hi(rd), imm), ctx); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void emit_alu_i32(const s8 *dst, s32 imm, 32862306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 op) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 33162306a36Sopenharmony_ci const s8 *rd = bpf_get_reg32(dst, tmp1, ctx); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci switch (op) { 33462306a36Sopenharmony_ci case BPF_MOV: 33562306a36Sopenharmony_ci emit_imm(lo(rd), imm, ctx); 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci case BPF_ADD: 33862306a36Sopenharmony_ci if (is_12b_int(imm)) { 33962306a36Sopenharmony_ci emit(rv_addi(lo(rd), lo(rd), imm), ctx); 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 34262306a36Sopenharmony_ci emit(rv_add(lo(rd), lo(rd), RV_REG_T0), ctx); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci case BPF_SUB: 34662306a36Sopenharmony_ci if (is_12b_int(-imm)) { 34762306a36Sopenharmony_ci emit(rv_addi(lo(rd), lo(rd), -imm), ctx); 34862306a36Sopenharmony_ci } else { 34962306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 35062306a36Sopenharmony_ci emit(rv_sub(lo(rd), lo(rd), RV_REG_T0), ctx); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci case BPF_AND: 35462306a36Sopenharmony_ci if (is_12b_int(imm)) { 35562306a36Sopenharmony_ci emit(rv_andi(lo(rd), lo(rd), imm), ctx); 35662306a36Sopenharmony_ci } else { 35762306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 35862306a36Sopenharmony_ci emit(rv_and(lo(rd), lo(rd), RV_REG_T0), ctx); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case BPF_OR: 36262306a36Sopenharmony_ci if (is_12b_int(imm)) { 36362306a36Sopenharmony_ci emit(rv_ori(lo(rd), lo(rd), imm), ctx); 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 36662306a36Sopenharmony_ci emit(rv_or(lo(rd), lo(rd), RV_REG_T0), ctx); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci case BPF_XOR: 37062306a36Sopenharmony_ci if (is_12b_int(imm)) { 37162306a36Sopenharmony_ci emit(rv_xori(lo(rd), lo(rd), imm), ctx); 37262306a36Sopenharmony_ci } else { 37362306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 37462306a36Sopenharmony_ci emit(rv_xor(lo(rd), lo(rd), RV_REG_T0), ctx); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case BPF_LSH: 37862306a36Sopenharmony_ci if (is_12b_int(imm)) { 37962306a36Sopenharmony_ci emit(rv_slli(lo(rd), lo(rd), imm), ctx); 38062306a36Sopenharmony_ci } else { 38162306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 38262306a36Sopenharmony_ci emit(rv_sll(lo(rd), lo(rd), RV_REG_T0), ctx); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case BPF_RSH: 38662306a36Sopenharmony_ci if (is_12b_int(imm)) { 38762306a36Sopenharmony_ci emit(rv_srli(lo(rd), lo(rd), imm), ctx); 38862306a36Sopenharmony_ci } else { 38962306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 39062306a36Sopenharmony_ci emit(rv_srl(lo(rd), lo(rd), RV_REG_T0), ctx); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case BPF_ARSH: 39462306a36Sopenharmony_ci if (is_12b_int(imm)) { 39562306a36Sopenharmony_ci emit(rv_srai(lo(rd), lo(rd), imm), ctx); 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci emit_imm(RV_REG_T0, imm, ctx); 39862306a36Sopenharmony_ci emit(rv_sra(lo(rd), lo(rd), RV_REG_T0), ctx); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci bpf_put_reg32(dst, rd, ctx); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void emit_alu_r64(const s8 *dst, const s8 *src, 40762306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 op) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 41062306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 41162306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 41262306a36Sopenharmony_ci const s8 *rs = bpf_get_reg64(src, tmp2, ctx); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci switch (op) { 41562306a36Sopenharmony_ci case BPF_MOV: 41662306a36Sopenharmony_ci emit(rv_addi(lo(rd), lo(rs), 0), ctx); 41762306a36Sopenharmony_ci emit(rv_addi(hi(rd), hi(rs), 0), ctx); 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case BPF_ADD: 42062306a36Sopenharmony_ci if (rd == rs) { 42162306a36Sopenharmony_ci emit(rv_srli(RV_REG_T0, lo(rd), 31), ctx); 42262306a36Sopenharmony_ci emit(rv_slli(hi(rd), hi(rd), 1), ctx); 42362306a36Sopenharmony_ci emit(rv_or(hi(rd), RV_REG_T0, hi(rd)), ctx); 42462306a36Sopenharmony_ci emit(rv_slli(lo(rd), lo(rd), 1), ctx); 42562306a36Sopenharmony_ci } else { 42662306a36Sopenharmony_ci emit(rv_add(lo(rd), lo(rd), lo(rs)), ctx); 42762306a36Sopenharmony_ci emit(rv_sltu(RV_REG_T0, lo(rd), lo(rs)), ctx); 42862306a36Sopenharmony_ci emit(rv_add(hi(rd), hi(rd), hi(rs)), ctx); 42962306a36Sopenharmony_ci emit(rv_add(hi(rd), hi(rd), RV_REG_T0), ctx); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci case BPF_SUB: 43362306a36Sopenharmony_ci emit(rv_sub(RV_REG_T1, hi(rd), hi(rs)), ctx); 43462306a36Sopenharmony_ci emit(rv_sltu(RV_REG_T0, lo(rd), lo(rs)), ctx); 43562306a36Sopenharmony_ci emit(rv_sub(hi(rd), RV_REG_T1, RV_REG_T0), ctx); 43662306a36Sopenharmony_ci emit(rv_sub(lo(rd), lo(rd), lo(rs)), ctx); 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case BPF_AND: 43962306a36Sopenharmony_ci emit(rv_and(lo(rd), lo(rd), lo(rs)), ctx); 44062306a36Sopenharmony_ci emit(rv_and(hi(rd), hi(rd), hi(rs)), ctx); 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci case BPF_OR: 44362306a36Sopenharmony_ci emit(rv_or(lo(rd), lo(rd), lo(rs)), ctx); 44462306a36Sopenharmony_ci emit(rv_or(hi(rd), hi(rd), hi(rs)), ctx); 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case BPF_XOR: 44762306a36Sopenharmony_ci emit(rv_xor(lo(rd), lo(rd), lo(rs)), ctx); 44862306a36Sopenharmony_ci emit(rv_xor(hi(rd), hi(rd), hi(rs)), ctx); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case BPF_MUL: 45162306a36Sopenharmony_ci emit(rv_mul(RV_REG_T0, hi(rs), lo(rd)), ctx); 45262306a36Sopenharmony_ci emit(rv_mul(hi(rd), hi(rd), lo(rs)), ctx); 45362306a36Sopenharmony_ci emit(rv_mulhu(RV_REG_T1, lo(rd), lo(rs)), ctx); 45462306a36Sopenharmony_ci emit(rv_add(hi(rd), hi(rd), RV_REG_T0), ctx); 45562306a36Sopenharmony_ci emit(rv_mul(lo(rd), lo(rd), lo(rs)), ctx); 45662306a36Sopenharmony_ci emit(rv_add(hi(rd), hi(rd), RV_REG_T1), ctx); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case BPF_LSH: 45962306a36Sopenharmony_ci emit(rv_addi(RV_REG_T0, lo(rs), -32), ctx); 46062306a36Sopenharmony_ci emit(rv_blt(RV_REG_T0, RV_REG_ZERO, 8), ctx); 46162306a36Sopenharmony_ci emit(rv_sll(hi(rd), lo(rd), RV_REG_T0), ctx); 46262306a36Sopenharmony_ci emit(rv_addi(lo(rd), RV_REG_ZERO, 0), ctx); 46362306a36Sopenharmony_ci emit(rv_jal(RV_REG_ZERO, 16), ctx); 46462306a36Sopenharmony_ci emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 31), ctx); 46562306a36Sopenharmony_ci emit(rv_srli(RV_REG_T0, lo(rd), 1), ctx); 46662306a36Sopenharmony_ci emit(rv_sub(RV_REG_T1, RV_REG_T1, lo(rs)), ctx); 46762306a36Sopenharmony_ci emit(rv_srl(RV_REG_T0, RV_REG_T0, RV_REG_T1), ctx); 46862306a36Sopenharmony_ci emit(rv_sll(hi(rd), hi(rd), lo(rs)), ctx); 46962306a36Sopenharmony_ci emit(rv_or(hi(rd), RV_REG_T0, hi(rd)), ctx); 47062306a36Sopenharmony_ci emit(rv_sll(lo(rd), lo(rd), lo(rs)), ctx); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case BPF_RSH: 47362306a36Sopenharmony_ci emit(rv_addi(RV_REG_T0, lo(rs), -32), ctx); 47462306a36Sopenharmony_ci emit(rv_blt(RV_REG_T0, RV_REG_ZERO, 8), ctx); 47562306a36Sopenharmony_ci emit(rv_srl(lo(rd), hi(rd), RV_REG_T0), ctx); 47662306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 47762306a36Sopenharmony_ci emit(rv_jal(RV_REG_ZERO, 16), ctx); 47862306a36Sopenharmony_ci emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 31), ctx); 47962306a36Sopenharmony_ci emit(rv_slli(RV_REG_T0, hi(rd), 1), ctx); 48062306a36Sopenharmony_ci emit(rv_sub(RV_REG_T1, RV_REG_T1, lo(rs)), ctx); 48162306a36Sopenharmony_ci emit(rv_sll(RV_REG_T0, RV_REG_T0, RV_REG_T1), ctx); 48262306a36Sopenharmony_ci emit(rv_srl(lo(rd), lo(rd), lo(rs)), ctx); 48362306a36Sopenharmony_ci emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx); 48462306a36Sopenharmony_ci emit(rv_srl(hi(rd), hi(rd), lo(rs)), ctx); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci case BPF_ARSH: 48762306a36Sopenharmony_ci emit(rv_addi(RV_REG_T0, lo(rs), -32), ctx); 48862306a36Sopenharmony_ci emit(rv_blt(RV_REG_T0, RV_REG_ZERO, 8), ctx); 48962306a36Sopenharmony_ci emit(rv_sra(lo(rd), hi(rd), RV_REG_T0), ctx); 49062306a36Sopenharmony_ci emit(rv_srai(hi(rd), hi(rd), 31), ctx); 49162306a36Sopenharmony_ci emit(rv_jal(RV_REG_ZERO, 16), ctx); 49262306a36Sopenharmony_ci emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 31), ctx); 49362306a36Sopenharmony_ci emit(rv_slli(RV_REG_T0, hi(rd), 1), ctx); 49462306a36Sopenharmony_ci emit(rv_sub(RV_REG_T1, RV_REG_T1, lo(rs)), ctx); 49562306a36Sopenharmony_ci emit(rv_sll(RV_REG_T0, RV_REG_T0, RV_REG_T1), ctx); 49662306a36Sopenharmony_ci emit(rv_srl(lo(rd), lo(rd), lo(rs)), ctx); 49762306a36Sopenharmony_ci emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx); 49862306a36Sopenharmony_ci emit(rv_sra(hi(rd), hi(rd), lo(rs)), ctx); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci case BPF_NEG: 50162306a36Sopenharmony_ci emit(rv_sub(lo(rd), RV_REG_ZERO, lo(rd)), ctx); 50262306a36Sopenharmony_ci emit(rv_sltu(RV_REG_T0, RV_REG_ZERO, lo(rd)), ctx); 50362306a36Sopenharmony_ci emit(rv_sub(hi(rd), RV_REG_ZERO, hi(rd)), ctx); 50462306a36Sopenharmony_ci emit(rv_sub(hi(rd), hi(rd), RV_REG_T0), ctx); 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic void emit_alu_r32(const s8 *dst, const s8 *src, 51262306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 op) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 51562306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 51662306a36Sopenharmony_ci const s8 *rd = bpf_get_reg32(dst, tmp1, ctx); 51762306a36Sopenharmony_ci const s8 *rs = bpf_get_reg32(src, tmp2, ctx); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci switch (op) { 52062306a36Sopenharmony_ci case BPF_MOV: 52162306a36Sopenharmony_ci emit(rv_addi(lo(rd), lo(rs), 0), ctx); 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case BPF_ADD: 52462306a36Sopenharmony_ci emit(rv_add(lo(rd), lo(rd), lo(rs)), ctx); 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci case BPF_SUB: 52762306a36Sopenharmony_ci emit(rv_sub(lo(rd), lo(rd), lo(rs)), ctx); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci case BPF_AND: 53062306a36Sopenharmony_ci emit(rv_and(lo(rd), lo(rd), lo(rs)), ctx); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case BPF_OR: 53362306a36Sopenharmony_ci emit(rv_or(lo(rd), lo(rd), lo(rs)), ctx); 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci case BPF_XOR: 53662306a36Sopenharmony_ci emit(rv_xor(lo(rd), lo(rd), lo(rs)), ctx); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case BPF_MUL: 53962306a36Sopenharmony_ci emit(rv_mul(lo(rd), lo(rd), lo(rs)), ctx); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case BPF_DIV: 54262306a36Sopenharmony_ci emit(rv_divu(lo(rd), lo(rd), lo(rs)), ctx); 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case BPF_MOD: 54562306a36Sopenharmony_ci emit(rv_remu(lo(rd), lo(rd), lo(rs)), ctx); 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci case BPF_LSH: 54862306a36Sopenharmony_ci emit(rv_sll(lo(rd), lo(rd), lo(rs)), ctx); 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case BPF_RSH: 55162306a36Sopenharmony_ci emit(rv_srl(lo(rd), lo(rd), lo(rs)), ctx); 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case BPF_ARSH: 55462306a36Sopenharmony_ci emit(rv_sra(lo(rd), lo(rd), lo(rs)), ctx); 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci case BPF_NEG: 55762306a36Sopenharmony_ci emit(rv_sub(lo(rd), RV_REG_ZERO, lo(rd)), ctx); 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci bpf_put_reg32(dst, rd, ctx); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic int emit_branch_r64(const s8 *src1, const s8 *src2, s32 rvoff, 56562306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 op) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int e, s = ctx->ninsns; 56862306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 56962306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci const s8 *rs1 = bpf_get_reg64(src1, tmp1, ctx); 57262306a36Sopenharmony_ci const s8 *rs2 = bpf_get_reg64(src2, tmp2, ctx); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* 57562306a36Sopenharmony_ci * NO_JUMP skips over the rest of the instructions and the 57662306a36Sopenharmony_ci * emit_jump_and_link, meaning the BPF branch is not taken. 57762306a36Sopenharmony_ci * JUMP skips directly to the emit_jump_and_link, meaning 57862306a36Sopenharmony_ci * the BPF branch is taken. 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * The fallthrough case results in the BPF branch being taken. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci#define NO_JUMP(idx) (6 + (2 * (idx))) 58362306a36Sopenharmony_ci#define JUMP(idx) (2 + (2 * (idx))) 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci switch (op) { 58662306a36Sopenharmony_ci case BPF_JEQ: 58762306a36Sopenharmony_ci emit(rv_bne(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 58862306a36Sopenharmony_ci emit(rv_bne(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci case BPF_JGT: 59162306a36Sopenharmony_ci emit(rv_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx); 59262306a36Sopenharmony_ci emit(rv_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 59362306a36Sopenharmony_ci emit(rv_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci case BPF_JLT: 59662306a36Sopenharmony_ci emit(rv_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx); 59762306a36Sopenharmony_ci emit(rv_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 59862306a36Sopenharmony_ci emit(rv_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case BPF_JGE: 60162306a36Sopenharmony_ci emit(rv_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx); 60262306a36Sopenharmony_ci emit(rv_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 60362306a36Sopenharmony_ci emit(rv_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci case BPF_JLE: 60662306a36Sopenharmony_ci emit(rv_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx); 60762306a36Sopenharmony_ci emit(rv_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 60862306a36Sopenharmony_ci emit(rv_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case BPF_JNE: 61162306a36Sopenharmony_ci emit(rv_bne(hi(rs1), hi(rs2), JUMP(1)), ctx); 61262306a36Sopenharmony_ci emit(rv_beq(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci case BPF_JSGT: 61562306a36Sopenharmony_ci emit(rv_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx); 61662306a36Sopenharmony_ci emit(rv_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 61762306a36Sopenharmony_ci emit(rv_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case BPF_JSLT: 62062306a36Sopenharmony_ci emit(rv_blt(hi(rs1), hi(rs2), JUMP(2)), ctx); 62162306a36Sopenharmony_ci emit(rv_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 62262306a36Sopenharmony_ci emit(rv_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci case BPF_JSGE: 62562306a36Sopenharmony_ci emit(rv_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx); 62662306a36Sopenharmony_ci emit(rv_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 62762306a36Sopenharmony_ci emit(rv_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case BPF_JSLE: 63062306a36Sopenharmony_ci emit(rv_blt(hi(rs1), hi(rs2), JUMP(2)), ctx); 63162306a36Sopenharmony_ci emit(rv_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 63262306a36Sopenharmony_ci emit(rv_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case BPF_JSET: 63562306a36Sopenharmony_ci emit(rv_and(RV_REG_T0, hi(rs1), hi(rs2)), ctx); 63662306a36Sopenharmony_ci emit(rv_bne(RV_REG_T0, RV_REG_ZERO, JUMP(2)), ctx); 63762306a36Sopenharmony_ci emit(rv_and(RV_REG_T0, lo(rs1), lo(rs2)), ctx); 63862306a36Sopenharmony_ci emit(rv_beq(RV_REG_T0, RV_REG_ZERO, NO_JUMP(0)), ctx); 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci#undef NO_JUMP 64362306a36Sopenharmony_ci#undef JUMP 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci e = ctx->ninsns; 64662306a36Sopenharmony_ci /* Adjust for extra insns. */ 64762306a36Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 64862306a36Sopenharmony_ci emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx); 64962306a36Sopenharmony_ci return 0; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int emit_bcc(u8 op, u8 rd, u8 rs, int rvoff, struct rv_jit_context *ctx) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci int e, s = ctx->ninsns; 65562306a36Sopenharmony_ci bool far = false; 65662306a36Sopenharmony_ci int off; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (op == BPF_JSET) { 65962306a36Sopenharmony_ci /* 66062306a36Sopenharmony_ci * BPF_JSET is a special case: it has no inverse so we always 66162306a36Sopenharmony_ci * treat it as a far branch. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci far = true; 66462306a36Sopenharmony_ci } else if (!is_13b_int(rvoff)) { 66562306a36Sopenharmony_ci op = invert_bpf_cond(op); 66662306a36Sopenharmony_ci far = true; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* 67062306a36Sopenharmony_ci * For a far branch, the condition is negated and we jump over the 67162306a36Sopenharmony_ci * branch itself, and the two instructions from emit_jump_and_link. 67262306a36Sopenharmony_ci * For a near branch, just use rvoff. 67362306a36Sopenharmony_ci */ 67462306a36Sopenharmony_ci off = far ? 6 : (rvoff >> 1); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci switch (op) { 67762306a36Sopenharmony_ci case BPF_JEQ: 67862306a36Sopenharmony_ci emit(rv_beq(rd, rs, off), ctx); 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci case BPF_JGT: 68162306a36Sopenharmony_ci emit(rv_bgtu(rd, rs, off), ctx); 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci case BPF_JLT: 68462306a36Sopenharmony_ci emit(rv_bltu(rd, rs, off), ctx); 68562306a36Sopenharmony_ci break; 68662306a36Sopenharmony_ci case BPF_JGE: 68762306a36Sopenharmony_ci emit(rv_bgeu(rd, rs, off), ctx); 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci case BPF_JLE: 69062306a36Sopenharmony_ci emit(rv_bleu(rd, rs, off), ctx); 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case BPF_JNE: 69362306a36Sopenharmony_ci emit(rv_bne(rd, rs, off), ctx); 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci case BPF_JSGT: 69662306a36Sopenharmony_ci emit(rv_bgt(rd, rs, off), ctx); 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci case BPF_JSLT: 69962306a36Sopenharmony_ci emit(rv_blt(rd, rs, off), ctx); 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci case BPF_JSGE: 70262306a36Sopenharmony_ci emit(rv_bge(rd, rs, off), ctx); 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci case BPF_JSLE: 70562306a36Sopenharmony_ci emit(rv_ble(rd, rs, off), ctx); 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case BPF_JSET: 70862306a36Sopenharmony_ci emit(rv_and(RV_REG_T0, rd, rs), ctx); 70962306a36Sopenharmony_ci emit(rv_beq(RV_REG_T0, RV_REG_ZERO, off), ctx); 71062306a36Sopenharmony_ci break; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (far) { 71462306a36Sopenharmony_ci e = ctx->ninsns; 71562306a36Sopenharmony_ci /* Adjust for extra insns. */ 71662306a36Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 71762306a36Sopenharmony_ci emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci return 0; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int emit_branch_r32(const s8 *src1, const s8 *src2, s32 rvoff, 72362306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 op) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci int e, s = ctx->ninsns; 72662306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 72762306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci const s8 *rs1 = bpf_get_reg32(src1, tmp1, ctx); 73062306a36Sopenharmony_ci const s8 *rs2 = bpf_get_reg32(src2, tmp2, ctx); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci e = ctx->ninsns; 73362306a36Sopenharmony_ci /* Adjust for extra insns. */ 73462306a36Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (emit_bcc(op, lo(rs1), lo(rs2), rvoff, ctx)) 73762306a36Sopenharmony_ci return -1; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic void emit_call(bool fixed, u64 addr, struct rv_jit_context *ctx) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci const s8 *r0 = bpf2rv32[BPF_REG_0]; 74562306a36Sopenharmony_ci const s8 *r5 = bpf2rv32[BPF_REG_5]; 74662306a36Sopenharmony_ci u32 upper = ((u32)addr + (1 << 11)) >> 12; 74762306a36Sopenharmony_ci u32 lower = addr & 0xfff; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* R1-R4 already in correct registers---need to push R5 to stack. */ 75062306a36Sopenharmony_ci emit(rv_addi(RV_REG_SP, RV_REG_SP, -16), ctx); 75162306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, 0, lo(r5)), ctx); 75262306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, 4, hi(r5)), ctx); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Backup TCC. */ 75562306a36Sopenharmony_ci emit(rv_addi(RV_REG_TCC_SAVED, RV_REG_TCC, 0), ctx); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* 75862306a36Sopenharmony_ci * Use lui/jalr pair to jump to absolute address. Don't use emit_imm as 75962306a36Sopenharmony_ci * the number of emitted instructions should not depend on the value of 76062306a36Sopenharmony_ci * addr. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ci emit(rv_lui(RV_REG_T1, upper), ctx); 76362306a36Sopenharmony_ci emit(rv_jalr(RV_REG_RA, RV_REG_T1, lower), ctx); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Restore TCC. */ 76662306a36Sopenharmony_ci emit(rv_addi(RV_REG_TCC, RV_REG_TCC_SAVED, 0), ctx); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* Set return value and restore stack. */ 76962306a36Sopenharmony_ci emit(rv_addi(lo(r0), RV_REG_A0, 0), ctx); 77062306a36Sopenharmony_ci emit(rv_addi(hi(r0), RV_REG_A1, 0), ctx); 77162306a36Sopenharmony_ci emit(rv_addi(RV_REG_SP, RV_REG_SP, 16), ctx); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * R1 -> &ctx 77862306a36Sopenharmony_ci * R2 -> &array 77962306a36Sopenharmony_ci * R3 -> index 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ci int tc_ninsn, off, start_insn = ctx->ninsns; 78262306a36Sopenharmony_ci const s8 *arr_reg = bpf2rv32[BPF_REG_2]; 78362306a36Sopenharmony_ci const s8 *idx_reg = bpf2rv32[BPF_REG_3]; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci tc_ninsn = insn ? ctx->offset[insn] - ctx->offset[insn - 1] : 78662306a36Sopenharmony_ci ctx->offset[0]; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* max_entries = array->map.max_entries; */ 78962306a36Sopenharmony_ci off = offsetof(struct bpf_array, map.max_entries); 79062306a36Sopenharmony_ci if (is_12b_check(off, insn)) 79162306a36Sopenharmony_ci return -1; 79262306a36Sopenharmony_ci emit(rv_lw(RV_REG_T1, off, lo(arr_reg)), ctx); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * if (index >= max_entries) 79662306a36Sopenharmony_ci * goto out; 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ci off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn)); 79962306a36Sopenharmony_ci emit_bcc(BPF_JGE, lo(idx_reg), RV_REG_T1, off, ctx); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* 80262306a36Sopenharmony_ci * if (--tcc < 0) 80362306a36Sopenharmony_ci * goto out; 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ci emit(rv_addi(RV_REG_TCC, RV_REG_TCC, -1), ctx); 80662306a36Sopenharmony_ci off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn)); 80762306a36Sopenharmony_ci emit_bcc(BPF_JSLT, RV_REG_TCC, RV_REG_ZERO, off, ctx); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* 81062306a36Sopenharmony_ci * prog = array->ptrs[index]; 81162306a36Sopenharmony_ci * if (!prog) 81262306a36Sopenharmony_ci * goto out; 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci emit(rv_slli(RV_REG_T0, lo(idx_reg), 2), ctx); 81562306a36Sopenharmony_ci emit(rv_add(RV_REG_T0, RV_REG_T0, lo(arr_reg)), ctx); 81662306a36Sopenharmony_ci off = offsetof(struct bpf_array, ptrs); 81762306a36Sopenharmony_ci if (is_12b_check(off, insn)) 81862306a36Sopenharmony_ci return -1; 81962306a36Sopenharmony_ci emit(rv_lw(RV_REG_T0, off, RV_REG_T0), ctx); 82062306a36Sopenharmony_ci off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn)); 82162306a36Sopenharmony_ci emit_bcc(BPF_JEQ, RV_REG_T0, RV_REG_ZERO, off, ctx); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* 82462306a36Sopenharmony_ci * tcc = temp_tcc; 82562306a36Sopenharmony_ci * goto *(prog->bpf_func + 4); 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci off = offsetof(struct bpf_prog, bpf_func); 82862306a36Sopenharmony_ci if (is_12b_check(off, insn)) 82962306a36Sopenharmony_ci return -1; 83062306a36Sopenharmony_ci emit(rv_lw(RV_REG_T0, off, RV_REG_T0), ctx); 83162306a36Sopenharmony_ci /* Epilogue jumps to *(t0 + 4). */ 83262306a36Sopenharmony_ci __build_epilogue(true, ctx); 83362306a36Sopenharmony_ci return 0; 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic int emit_load_r64(const s8 *dst, const s8 *src, s16 off, 83762306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 size) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 84062306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 84162306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 84262306a36Sopenharmony_ci const s8 *rs = bpf_get_reg64(src, tmp2, ctx); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci emit_imm(RV_REG_T0, off, ctx); 84562306a36Sopenharmony_ci emit(rv_add(RV_REG_T0, RV_REG_T0, lo(rs)), ctx); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci switch (size) { 84862306a36Sopenharmony_ci case BPF_B: 84962306a36Sopenharmony_ci emit(rv_lbu(lo(rd), 0, RV_REG_T0), ctx); 85062306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 85162306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci case BPF_H: 85462306a36Sopenharmony_ci emit(rv_lhu(lo(rd), 0, RV_REG_T0), ctx); 85562306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 85662306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci case BPF_W: 85962306a36Sopenharmony_ci emit(rv_lw(lo(rd), 0, RV_REG_T0), ctx); 86062306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 86162306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci case BPF_DW: 86462306a36Sopenharmony_ci emit(rv_lw(lo(rd), 0, RV_REG_T0), ctx); 86562306a36Sopenharmony_ci emit(rv_lw(hi(rd), 4, RV_REG_T0), ctx); 86662306a36Sopenharmony_ci break; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 87062306a36Sopenharmony_ci return 0; 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic int emit_store_r64(const s8 *dst, const s8 *src, s16 off, 87462306a36Sopenharmony_ci struct rv_jit_context *ctx, const u8 size, 87562306a36Sopenharmony_ci const u8 mode) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 87862306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 87962306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 88062306a36Sopenharmony_ci const s8 *rs = bpf_get_reg64(src, tmp2, ctx); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (mode == BPF_ATOMIC && size != BPF_W) 88362306a36Sopenharmony_ci return -1; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci emit_imm(RV_REG_T0, off, ctx); 88662306a36Sopenharmony_ci emit(rv_add(RV_REG_T0, RV_REG_T0, lo(rd)), ctx); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci switch (size) { 88962306a36Sopenharmony_ci case BPF_B: 89062306a36Sopenharmony_ci emit(rv_sb(RV_REG_T0, 0, lo(rs)), ctx); 89162306a36Sopenharmony_ci break; 89262306a36Sopenharmony_ci case BPF_H: 89362306a36Sopenharmony_ci emit(rv_sh(RV_REG_T0, 0, lo(rs)), ctx); 89462306a36Sopenharmony_ci break; 89562306a36Sopenharmony_ci case BPF_W: 89662306a36Sopenharmony_ci switch (mode) { 89762306a36Sopenharmony_ci case BPF_MEM: 89862306a36Sopenharmony_ci emit(rv_sw(RV_REG_T0, 0, lo(rs)), ctx); 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci case BPF_ATOMIC: /* Only BPF_ADD supported */ 90162306a36Sopenharmony_ci emit(rv_amoadd_w(RV_REG_ZERO, lo(rs), RV_REG_T0, 0, 0), 90262306a36Sopenharmony_ci ctx); 90362306a36Sopenharmony_ci break; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci case BPF_DW: 90762306a36Sopenharmony_ci emit(rv_sw(RV_REG_T0, 0, lo(rs)), ctx); 90862306a36Sopenharmony_ci emit(rv_sw(RV_REG_T0, 4, hi(rs)), ctx); 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci return 0; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic void emit_rev16(const s8 rd, struct rv_jit_context *ctx) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci emit(rv_slli(rd, rd, 16), ctx); 91862306a36Sopenharmony_ci emit(rv_slli(RV_REG_T1, rd, 8), ctx); 91962306a36Sopenharmony_ci emit(rv_srli(rd, rd, 8), ctx); 92062306a36Sopenharmony_ci emit(rv_add(RV_REG_T1, rd, RV_REG_T1), ctx); 92162306a36Sopenharmony_ci emit(rv_srli(rd, RV_REG_T1, 16), ctx); 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic void emit_rev32(const s8 rd, struct rv_jit_context *ctx) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 0), ctx); 92762306a36Sopenharmony_ci emit(rv_andi(RV_REG_T0, rd, 255), ctx); 92862306a36Sopenharmony_ci emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx); 92962306a36Sopenharmony_ci emit(rv_slli(RV_REG_T1, RV_REG_T1, 8), ctx); 93062306a36Sopenharmony_ci emit(rv_srli(rd, rd, 8), ctx); 93162306a36Sopenharmony_ci emit(rv_andi(RV_REG_T0, rd, 255), ctx); 93262306a36Sopenharmony_ci emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx); 93362306a36Sopenharmony_ci emit(rv_slli(RV_REG_T1, RV_REG_T1, 8), ctx); 93462306a36Sopenharmony_ci emit(rv_srli(rd, rd, 8), ctx); 93562306a36Sopenharmony_ci emit(rv_andi(RV_REG_T0, rd, 255), ctx); 93662306a36Sopenharmony_ci emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx); 93762306a36Sopenharmony_ci emit(rv_slli(RV_REG_T1, RV_REG_T1, 8), ctx); 93862306a36Sopenharmony_ci emit(rv_srli(rd, rd, 8), ctx); 93962306a36Sopenharmony_ci emit(rv_andi(RV_REG_T0, rd, 255), ctx); 94062306a36Sopenharmony_ci emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx); 94162306a36Sopenharmony_ci emit(rv_addi(rd, RV_REG_T1, 0), ctx); 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic void emit_zext64(const s8 *dst, struct rv_jit_context *ctx) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci const s8 *rd; 94762306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci rd = bpf_get_reg64(dst, tmp1, ctx); 95062306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 95162306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ciint bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, 95562306a36Sopenharmony_ci bool extra_pass) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 || 95862306a36Sopenharmony_ci BPF_CLASS(insn->code) == BPF_JMP; 95962306a36Sopenharmony_ci int s, e, rvoff, i = insn - ctx->prog->insnsi; 96062306a36Sopenharmony_ci u8 code = insn->code; 96162306a36Sopenharmony_ci s16 off = insn->off; 96262306a36Sopenharmony_ci s32 imm = insn->imm; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci const s8 *dst = bpf2rv32[insn->dst_reg]; 96562306a36Sopenharmony_ci const s8 *src = bpf2rv32[insn->src_reg]; 96662306a36Sopenharmony_ci const s8 *tmp1 = bpf2rv32[TMP_REG_1]; 96762306a36Sopenharmony_ci const s8 *tmp2 = bpf2rv32[TMP_REG_2]; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci switch (code) { 97062306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_X: 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_X: 97362306a36Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_K: 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_X: 97662306a36Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_K: 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_X: 97962306a36Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_X: 98062306a36Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_X: 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_X: 98362306a36Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_K: 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_X: 98662306a36Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_X: 98762306a36Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_X: 98862306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_K) { 98962306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 99062306a36Sopenharmony_ci src = tmp2; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci emit_alu_r64(dst, src, ctx, BPF_OP(code)); 99362306a36Sopenharmony_ci break; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci case BPF_ALU64 | BPF_NEG: 99662306a36Sopenharmony_ci emit_alu_r64(dst, tmp2, ctx, BPF_OP(code)); 99762306a36Sopenharmony_ci break; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_X: 100062306a36Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_K: 100162306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_X: 100262306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_K: 100362306a36Sopenharmony_ci goto notsupported; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_K: 100662306a36Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_K: 100762306a36Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_K: 100862306a36Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_K: 100962306a36Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_K: 101062306a36Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_K: 101162306a36Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_K: 101262306a36Sopenharmony_ci emit_alu_i64(dst, imm, ctx, BPF_OP(code)); 101362306a36Sopenharmony_ci break; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_X: 101662306a36Sopenharmony_ci if (imm == 1) { 101762306a36Sopenharmony_ci /* Special mov32 for zext. */ 101862306a36Sopenharmony_ci emit_zext64(dst, ctx); 101962306a36Sopenharmony_ci break; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci fallthrough; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_X: 102462306a36Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_X: 102562306a36Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_X: 102662306a36Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_X: 102762306a36Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_X: 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_X: 103062306a36Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_K: 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_X: 103362306a36Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_K: 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_X: 103662306a36Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_K: 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_X: 103962306a36Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_X: 104062306a36Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_X: 104162306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_K) { 104262306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 104362306a36Sopenharmony_ci src = tmp2; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci emit_alu_r32(dst, src, ctx, BPF_OP(code)); 104662306a36Sopenharmony_ci break; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_K: 104962306a36Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_K: 105062306a36Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_K: 105162306a36Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_K: 105262306a36Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_K: 105362306a36Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_K: 105462306a36Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_K: 105562306a36Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_K: 105662306a36Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_K: 105762306a36Sopenharmony_ci /* 105862306a36Sopenharmony_ci * mul,div,mod are handled in the BPF_X case since there are 105962306a36Sopenharmony_ci * no RISC-V I-type equivalents. 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_ci emit_alu_i32(dst, imm, ctx, BPF_OP(code)); 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci case BPF_ALU | BPF_NEG: 106562306a36Sopenharmony_ci /* 106662306a36Sopenharmony_ci * src is ignored---choose tmp2 as a dummy register since it 106762306a36Sopenharmony_ci * is not on the stack. 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_ci emit_alu_r32(dst, tmp2, ctx, BPF_OP(code)); 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_LE: 107362306a36Sopenharmony_ci { 107462306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci switch (imm) { 107762306a36Sopenharmony_ci case 16: 107862306a36Sopenharmony_ci emit(rv_slli(lo(rd), lo(rd), 16), ctx); 107962306a36Sopenharmony_ci emit(rv_srli(lo(rd), lo(rd), 16), ctx); 108062306a36Sopenharmony_ci fallthrough; 108162306a36Sopenharmony_ci case 32: 108262306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 108362306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case 64: 108662306a36Sopenharmony_ci /* Do nothing. */ 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci default: 108962306a36Sopenharmony_ci pr_err("bpf-jit: BPF_END imm %d invalid\n", imm); 109062306a36Sopenharmony_ci return -1; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 109462306a36Sopenharmony_ci break; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_BE: 109862306a36Sopenharmony_ci { 109962306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci switch (imm) { 110262306a36Sopenharmony_ci case 16: 110362306a36Sopenharmony_ci emit_rev16(lo(rd), ctx); 110462306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 110562306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 110662306a36Sopenharmony_ci break; 110762306a36Sopenharmony_ci case 32: 110862306a36Sopenharmony_ci emit_rev32(lo(rd), ctx); 110962306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 111062306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx); 111162306a36Sopenharmony_ci break; 111262306a36Sopenharmony_ci case 64: 111362306a36Sopenharmony_ci /* Swap upper and lower halves. */ 111462306a36Sopenharmony_ci emit(rv_addi(RV_REG_T0, lo(rd), 0), ctx); 111562306a36Sopenharmony_ci emit(rv_addi(lo(rd), hi(rd), 0), ctx); 111662306a36Sopenharmony_ci emit(rv_addi(hi(rd), RV_REG_T0, 0), ctx); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* Swap each half. */ 111962306a36Sopenharmony_ci emit_rev32(lo(rd), ctx); 112062306a36Sopenharmony_ci emit_rev32(hi(rd), ctx); 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci default: 112362306a36Sopenharmony_ci pr_err("bpf-jit: BPF_END imm %d invalid\n", imm); 112462306a36Sopenharmony_ci return -1; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci case BPF_JMP | BPF_JA: 113262306a36Sopenharmony_ci rvoff = rv_offset(i, off, ctx); 113362306a36Sopenharmony_ci emit_jump_and_link(RV_REG_ZERO, rvoff, false, ctx); 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci case BPF_JMP | BPF_CALL: 113762306a36Sopenharmony_ci { 113862306a36Sopenharmony_ci bool fixed; 113962306a36Sopenharmony_ci int ret; 114062306a36Sopenharmony_ci u64 addr; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, &addr, 114362306a36Sopenharmony_ci &fixed); 114462306a36Sopenharmony_ci if (ret < 0) 114562306a36Sopenharmony_ci return ret; 114662306a36Sopenharmony_ci emit_call(fixed, addr, ctx); 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: 115162306a36Sopenharmony_ci if (emit_bpf_tail_call(i, ctx)) 115262306a36Sopenharmony_ci return -1; 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: 115662306a36Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: 115762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: 115862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: 116162306a36Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: 116262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: 116362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: 116662306a36Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: 116762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: 116862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: 117162306a36Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: 117262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: 117362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: 117662306a36Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: 117762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: 117862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: 118162306a36Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: 118262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: 118362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: 118662306a36Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: 118762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: 118862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: 119162306a36Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: 119262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: 119362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: 119662306a36Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: 119762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: 119862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: 120162306a36Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: 120262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: 120362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: 120662306a36Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: 120762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: 120862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: 120962306a36Sopenharmony_ci rvoff = rv_offset(i, off, ctx); 121062306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_K) { 121162306a36Sopenharmony_ci s = ctx->ninsns; 121262306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 121362306a36Sopenharmony_ci src = tmp2; 121462306a36Sopenharmony_ci e = ctx->ninsns; 121562306a36Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (is64) 121962306a36Sopenharmony_ci emit_branch_r64(dst, src, rvoff, ctx, BPF_OP(code)); 122062306a36Sopenharmony_ci else 122162306a36Sopenharmony_ci emit_branch_r32(dst, src, rvoff, ctx, BPF_OP(code)); 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci case BPF_JMP | BPF_EXIT: 122562306a36Sopenharmony_ci if (i == ctx->prog->len - 1) 122662306a36Sopenharmony_ci break; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci rvoff = epilogue_offset(ctx); 122962306a36Sopenharmony_ci emit_jump_and_link(RV_REG_ZERO, rvoff, false, ctx); 123062306a36Sopenharmony_ci break; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci case BPF_LD | BPF_IMM | BPF_DW: 123362306a36Sopenharmony_ci { 123462306a36Sopenharmony_ci struct bpf_insn insn1 = insn[1]; 123562306a36Sopenharmony_ci s32 imm_lo = imm; 123662306a36Sopenharmony_ci s32 imm_hi = insn1.imm; 123762306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci emit_imm64(rd, imm_hi, imm_lo, ctx); 124062306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 124162306a36Sopenharmony_ci return 1; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_B: 124562306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_H: 124662306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_W: 124762306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_DW: 124862306a36Sopenharmony_ci if (emit_load_r64(dst, src, off, ctx, BPF_SIZE(code))) 124962306a36Sopenharmony_ci return -1; 125062306a36Sopenharmony_ci break; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* speculation barrier */ 125362306a36Sopenharmony_ci case BPF_ST | BPF_NOSPEC: 125462306a36Sopenharmony_ci break; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_B: 125762306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_H: 125862306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_W: 125962306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_DW: 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_B: 126262306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_H: 126362306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_W: 126462306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_DW: 126562306a36Sopenharmony_ci if (BPF_CLASS(code) == BPF_ST) { 126662306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 126762306a36Sopenharmony_ci src = tmp2; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code), 127162306a36Sopenharmony_ci BPF_MODE(code))) 127262306a36Sopenharmony_ci return -1; 127362306a36Sopenharmony_ci break; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci case BPF_STX | BPF_ATOMIC | BPF_W: 127662306a36Sopenharmony_ci if (insn->imm != BPF_ADD) { 127762306a36Sopenharmony_ci pr_info_once( 127862306a36Sopenharmony_ci "bpf-jit: not supported: atomic operation %02x ***\n", 127962306a36Sopenharmony_ci insn->imm); 128062306a36Sopenharmony_ci return -EFAULT; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code), 128462306a36Sopenharmony_ci BPF_MODE(code))) 128562306a36Sopenharmony_ci return -1; 128662306a36Sopenharmony_ci break; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci /* No hardware support for 8-byte atomics in RV32. */ 128962306a36Sopenharmony_ci case BPF_STX | BPF_ATOMIC | BPF_DW: 129062306a36Sopenharmony_ci /* Fallthrough. */ 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cinotsupported: 129362306a36Sopenharmony_ci pr_info_once("bpf-jit: not supported: opcode %02x ***\n", code); 129462306a36Sopenharmony_ci return -EFAULT; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci default: 129762306a36Sopenharmony_ci pr_err("bpf-jit: unknown opcode %02x\n", code); 129862306a36Sopenharmony_ci return -EINVAL; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci return 0; 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_civoid bpf_jit_build_prologue(struct rv_jit_context *ctx) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci const s8 *fp = bpf2rv32[BPF_REG_FP]; 130762306a36Sopenharmony_ci const s8 *r1 = bpf2rv32[BPF_REG_1]; 130862306a36Sopenharmony_ci int stack_adjust = 0; 130962306a36Sopenharmony_ci int bpf_stack_adjust = 131062306a36Sopenharmony_ci round_up(ctx->prog->aux->stack_depth, STACK_ALIGN); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* Make space for callee-saved registers. */ 131362306a36Sopenharmony_ci stack_adjust += NR_SAVED_REGISTERS * sizeof(u32); 131462306a36Sopenharmony_ci /* Make space for BPF registers on stack. */ 131562306a36Sopenharmony_ci stack_adjust += BPF_JIT_SCRATCH_REGS * sizeof(u32); 131662306a36Sopenharmony_ci /* Make space for BPF stack. */ 131762306a36Sopenharmony_ci stack_adjust += bpf_stack_adjust; 131862306a36Sopenharmony_ci /* Round up for stack alignment. */ 131962306a36Sopenharmony_ci stack_adjust = round_up(stack_adjust, STACK_ALIGN); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* 132262306a36Sopenharmony_ci * The first instruction sets the tail-call-counter (TCC) register. 132362306a36Sopenharmony_ci * This instruction is skipped by tail calls. 132462306a36Sopenharmony_ci */ 132562306a36Sopenharmony_ci emit(rv_addi(RV_REG_TCC, RV_REG_ZERO, MAX_TAIL_CALL_CNT), ctx); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci emit(rv_addi(RV_REG_SP, RV_REG_SP, -stack_adjust), ctx); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* Save callee-save registers. */ 133062306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 4, RV_REG_RA), ctx); 133162306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 8, RV_REG_FP), ctx); 133262306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 12, RV_REG_S1), ctx); 133362306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 16, RV_REG_S2), ctx); 133462306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 20, RV_REG_S3), ctx); 133562306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 24, RV_REG_S4), ctx); 133662306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 28, RV_REG_S5), ctx); 133762306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 32, RV_REG_S6), ctx); 133862306a36Sopenharmony_ci emit(rv_sw(RV_REG_SP, stack_adjust - 36, RV_REG_S7), ctx); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* Set fp: used as the base address for stacked BPF registers. */ 134162306a36Sopenharmony_ci emit(rv_addi(RV_REG_FP, RV_REG_SP, stack_adjust), ctx); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci /* Set up BPF frame pointer. */ 134462306a36Sopenharmony_ci emit(rv_addi(lo(fp), RV_REG_SP, bpf_stack_adjust), ctx); 134562306a36Sopenharmony_ci emit(rv_addi(hi(fp), RV_REG_ZERO, 0), ctx); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci /* Set up BPF context pointer. */ 134862306a36Sopenharmony_ci emit(rv_addi(lo(r1), RV_REG_A0, 0), ctx); 134962306a36Sopenharmony_ci emit(rv_addi(hi(r1), RV_REG_ZERO, 0), ctx); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci ctx->stack_size = stack_adjust; 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_civoid bpf_jit_build_epilogue(struct rv_jit_context *ctx) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci __build_epilogue(false, ctx); 135762306a36Sopenharmony_ci} 1358