18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* BPF JIT compiler for RV64G 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright(c) 2019 Björn Töpel <bjorn.topel@gmail.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bpf.h> 98c2ecf20Sopenharmony_ci#include <linux/filter.h> 108c2ecf20Sopenharmony_ci#include "bpf_jit.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define RV_REG_TCC RV_REG_A6 138c2ecf20Sopenharmony_ci#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic const int regmap[] = { 168c2ecf20Sopenharmony_ci [BPF_REG_0] = RV_REG_A5, 178c2ecf20Sopenharmony_ci [BPF_REG_1] = RV_REG_A0, 188c2ecf20Sopenharmony_ci [BPF_REG_2] = RV_REG_A1, 198c2ecf20Sopenharmony_ci [BPF_REG_3] = RV_REG_A2, 208c2ecf20Sopenharmony_ci [BPF_REG_4] = RV_REG_A3, 218c2ecf20Sopenharmony_ci [BPF_REG_5] = RV_REG_A4, 228c2ecf20Sopenharmony_ci [BPF_REG_6] = RV_REG_S1, 238c2ecf20Sopenharmony_ci [BPF_REG_7] = RV_REG_S2, 248c2ecf20Sopenharmony_ci [BPF_REG_8] = RV_REG_S3, 258c2ecf20Sopenharmony_ci [BPF_REG_9] = RV_REG_S4, 268c2ecf20Sopenharmony_ci [BPF_REG_FP] = RV_REG_S5, 278c2ecf20Sopenharmony_ci [BPF_REG_AX] = RV_REG_T0, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cienum { 318c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_TAIL_CALL = 0, 328c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_CALL = RV_REG_RA, 338c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_S1 = RV_REG_S1, 348c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_S2 = RV_REG_S2, 358c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_S3 = RV_REG_S3, 368c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_S4 = RV_REG_S4, 378c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_S5 = RV_REG_S5, 388c2ecf20Sopenharmony_ci RV_CTX_F_SEEN_S6 = RV_REG_S6, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic u8 bpf_to_rv_reg(int bpf_reg, struct rv_jit_context *ctx) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci u8 reg = regmap[bpf_reg]; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci switch (reg) { 468c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S1: 478c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S2: 488c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S3: 498c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S4: 508c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S5: 518c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S6: 528c2ecf20Sopenharmony_ci __set_bit(reg, &ctx->flags); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci return reg; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic bool seen_reg(int reg, struct rv_jit_context *ctx) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci switch (reg) { 608c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_CALL: 618c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S1: 628c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S2: 638c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S3: 648c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S4: 658c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S5: 668c2ecf20Sopenharmony_ci case RV_CTX_F_SEEN_S6: 678c2ecf20Sopenharmony_ci return test_bit(reg, &ctx->flags); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci return false; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void mark_fp(struct rv_jit_context *ctx) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci __set_bit(RV_CTX_F_SEEN_S5, &ctx->flags); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void mark_call(struct rv_jit_context *ctx) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci __set_bit(RV_CTX_F_SEEN_CALL, &ctx->flags); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic bool seen_call(struct rv_jit_context *ctx) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return test_bit(RV_CTX_F_SEEN_CALL, &ctx->flags); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void mark_tail_call(struct rv_jit_context *ctx) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci __set_bit(RV_CTX_F_SEEN_TAIL_CALL, &ctx->flags); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic bool seen_tail_call(struct rv_jit_context *ctx) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return test_bit(RV_CTX_F_SEEN_TAIL_CALL, &ctx->flags); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic u8 rv_tail_call_reg(struct rv_jit_context *ctx) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci mark_tail_call(ctx); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (seen_call(ctx)) { 1028c2ecf20Sopenharmony_ci __set_bit(RV_CTX_F_SEEN_S6, &ctx->flags); 1038c2ecf20Sopenharmony_ci return RV_REG_S6; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci return RV_REG_A6; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic bool is_32b_int(s64 val) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci return -(1L << 31) <= val && val < (1L << 31); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic bool in_auipc_jalr_range(s64 val) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * auipc+jalr can reach any signed PC-relative offset in the range 1178c2ecf20Sopenharmony_ci * [-2^31 - 2^11, 2^31 - 2^11). 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci return (-(1L << 31) - (1L << 11)) <= val && 1208c2ecf20Sopenharmony_ci val < ((1L << 31) - (1L << 11)); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void emit_imm(u8 rd, s64 val, struct rv_jit_context *ctx) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci /* Note that the immediate from the add is sign-extended, 1268c2ecf20Sopenharmony_ci * which means that we need to compensate this by adding 2^12, 1278c2ecf20Sopenharmony_ci * when the 12th bit is set. A simpler way of doing this, and 1288c2ecf20Sopenharmony_ci * getting rid of the check, is to just add 2**11 before the 1298c2ecf20Sopenharmony_ci * shift. The "Loading a 32-Bit constant" example from the 1308c2ecf20Sopenharmony_ci * "Computer Organization and Design, RISC-V edition" book by 1318c2ecf20Sopenharmony_ci * Patterson/Hennessy highlights this fact. 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * This also means that we need to process LSB to MSB. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci s64 upper = (val + (1 << 11)) >> 12; 1368c2ecf20Sopenharmony_ci /* Sign-extend lower 12 bits to 64 bits since immediates for li, addiw, 1378c2ecf20Sopenharmony_ci * and addi are signed and RVC checks will perform signed comparisons. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci s64 lower = ((val & 0xfff) << 52) >> 52; 1408c2ecf20Sopenharmony_ci int shift; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (is_32b_int(val)) { 1438c2ecf20Sopenharmony_ci if (upper) 1448c2ecf20Sopenharmony_ci emit_lui(rd, upper, ctx); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!upper) { 1478c2ecf20Sopenharmony_ci emit_li(rd, lower, ctx); 1488c2ecf20Sopenharmony_ci return; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci emit_addiw(rd, rd, lower, ctx); 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci shift = __ffs(upper); 1568c2ecf20Sopenharmony_ci upper >>= shift; 1578c2ecf20Sopenharmony_ci shift += 12; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci emit_imm(rd, upper, ctx); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci emit_slli(rd, rd, shift, ctx); 1628c2ecf20Sopenharmony_ci if (lower) 1638c2ecf20Sopenharmony_ci emit_addi(rd, rd, lower, ctx); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int stack_adjust = ctx->stack_size, store_offset = stack_adjust - 8; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_RA, ctx)) { 1718c2ecf20Sopenharmony_ci emit_ld(RV_REG_RA, store_offset, RV_REG_SP, ctx); 1728c2ecf20Sopenharmony_ci store_offset -= 8; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci emit_ld(RV_REG_FP, store_offset, RV_REG_SP, ctx); 1758c2ecf20Sopenharmony_ci store_offset -= 8; 1768c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S1, ctx)) { 1778c2ecf20Sopenharmony_ci emit_ld(RV_REG_S1, store_offset, RV_REG_SP, ctx); 1788c2ecf20Sopenharmony_ci store_offset -= 8; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S2, ctx)) { 1818c2ecf20Sopenharmony_ci emit_ld(RV_REG_S2, store_offset, RV_REG_SP, ctx); 1828c2ecf20Sopenharmony_ci store_offset -= 8; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S3, ctx)) { 1858c2ecf20Sopenharmony_ci emit_ld(RV_REG_S3, store_offset, RV_REG_SP, ctx); 1868c2ecf20Sopenharmony_ci store_offset -= 8; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S4, ctx)) { 1898c2ecf20Sopenharmony_ci emit_ld(RV_REG_S4, store_offset, RV_REG_SP, ctx); 1908c2ecf20Sopenharmony_ci store_offset -= 8; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S5, ctx)) { 1938c2ecf20Sopenharmony_ci emit_ld(RV_REG_S5, store_offset, RV_REG_SP, ctx); 1948c2ecf20Sopenharmony_ci store_offset -= 8; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S6, ctx)) { 1978c2ecf20Sopenharmony_ci emit_ld(RV_REG_S6, store_offset, RV_REG_SP, ctx); 1988c2ecf20Sopenharmony_ci store_offset -= 8; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci emit_addi(RV_REG_SP, RV_REG_SP, stack_adjust, ctx); 2028c2ecf20Sopenharmony_ci /* Set return value. */ 2038c2ecf20Sopenharmony_ci if (!is_tail_call) 2048c2ecf20Sopenharmony_ci emit_addiw(RV_REG_A0, RV_REG_A5, 0, ctx); 2058c2ecf20Sopenharmony_ci emit_jalr(RV_REG_ZERO, is_tail_call ? RV_REG_T3 : RV_REG_RA, 2068c2ecf20Sopenharmony_ci is_tail_call ? 4 : 0, /* skip TCC init */ 2078c2ecf20Sopenharmony_ci ctx); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void emit_bcc(u8 cond, u8 rd, u8 rs, int rvoff, 2118c2ecf20Sopenharmony_ci struct rv_jit_context *ctx) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci switch (cond) { 2148c2ecf20Sopenharmony_ci case BPF_JEQ: 2158c2ecf20Sopenharmony_ci emit(rv_beq(rd, rs, rvoff >> 1), ctx); 2168c2ecf20Sopenharmony_ci return; 2178c2ecf20Sopenharmony_ci case BPF_JGT: 2188c2ecf20Sopenharmony_ci emit(rv_bltu(rs, rd, rvoff >> 1), ctx); 2198c2ecf20Sopenharmony_ci return; 2208c2ecf20Sopenharmony_ci case BPF_JLT: 2218c2ecf20Sopenharmony_ci emit(rv_bltu(rd, rs, rvoff >> 1), ctx); 2228c2ecf20Sopenharmony_ci return; 2238c2ecf20Sopenharmony_ci case BPF_JGE: 2248c2ecf20Sopenharmony_ci emit(rv_bgeu(rd, rs, rvoff >> 1), ctx); 2258c2ecf20Sopenharmony_ci return; 2268c2ecf20Sopenharmony_ci case BPF_JLE: 2278c2ecf20Sopenharmony_ci emit(rv_bgeu(rs, rd, rvoff >> 1), ctx); 2288c2ecf20Sopenharmony_ci return; 2298c2ecf20Sopenharmony_ci case BPF_JNE: 2308c2ecf20Sopenharmony_ci emit(rv_bne(rd, rs, rvoff >> 1), ctx); 2318c2ecf20Sopenharmony_ci return; 2328c2ecf20Sopenharmony_ci case BPF_JSGT: 2338c2ecf20Sopenharmony_ci emit(rv_blt(rs, rd, rvoff >> 1), ctx); 2348c2ecf20Sopenharmony_ci return; 2358c2ecf20Sopenharmony_ci case BPF_JSLT: 2368c2ecf20Sopenharmony_ci emit(rv_blt(rd, rs, rvoff >> 1), ctx); 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci case BPF_JSGE: 2398c2ecf20Sopenharmony_ci emit(rv_bge(rd, rs, rvoff >> 1), ctx); 2408c2ecf20Sopenharmony_ci return; 2418c2ecf20Sopenharmony_ci case BPF_JSLE: 2428c2ecf20Sopenharmony_ci emit(rv_bge(rs, rd, rvoff >> 1), ctx); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void emit_branch(u8 cond, u8 rd, u8 rs, int rvoff, 2478c2ecf20Sopenharmony_ci struct rv_jit_context *ctx) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci s64 upper, lower; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (is_13b_int(rvoff)) { 2528c2ecf20Sopenharmony_ci emit_bcc(cond, rd, rs, rvoff, ctx); 2538c2ecf20Sopenharmony_ci return; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Adjust for jal */ 2578c2ecf20Sopenharmony_ci rvoff -= 4; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Transform, e.g.: 2608c2ecf20Sopenharmony_ci * bne rd,rs,foo 2618c2ecf20Sopenharmony_ci * to 2628c2ecf20Sopenharmony_ci * beq rd,rs,<.L1> 2638c2ecf20Sopenharmony_ci * (auipc foo) 2648c2ecf20Sopenharmony_ci * jal(r) foo 2658c2ecf20Sopenharmony_ci * .L1 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci cond = invert_bpf_cond(cond); 2688c2ecf20Sopenharmony_ci if (is_21b_int(rvoff)) { 2698c2ecf20Sopenharmony_ci emit_bcc(cond, rd, rs, 8, ctx); 2708c2ecf20Sopenharmony_ci emit(rv_jal(RV_REG_ZERO, rvoff >> 1), ctx); 2718c2ecf20Sopenharmony_ci return; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* 32b No need for an additional rvoff adjustment, since we 2758c2ecf20Sopenharmony_ci * get that from the auipc at PC', where PC = PC' + 4. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci upper = (rvoff + (1 << 11)) >> 12; 2788c2ecf20Sopenharmony_ci lower = rvoff & 0xfff; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci emit_bcc(cond, rd, rs, 12, ctx); 2818c2ecf20Sopenharmony_ci emit(rv_auipc(RV_REG_T1, upper), ctx); 2828c2ecf20Sopenharmony_ci emit(rv_jalr(RV_REG_ZERO, RV_REG_T1, lower), ctx); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void emit_zext_32(u8 reg, struct rv_jit_context *ctx) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci emit_slli(reg, reg, 32, ctx); 2888c2ecf20Sopenharmony_ci emit_srli(reg, reg, 32, ctx); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int tc_ninsn, off, start_insn = ctx->ninsns; 2948c2ecf20Sopenharmony_ci u8 tcc = rv_tail_call_reg(ctx); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* a0: &ctx 2978c2ecf20Sopenharmony_ci * a1: &array 2988c2ecf20Sopenharmony_ci * a2: index 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * if (index >= array->map.max_entries) 3018c2ecf20Sopenharmony_ci * goto out; 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci tc_ninsn = insn ? ctx->offset[insn] - ctx->offset[insn - 1] : 3048c2ecf20Sopenharmony_ci ctx->offset[0]; 3058c2ecf20Sopenharmony_ci emit_zext_32(RV_REG_A2, ctx); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci off = offsetof(struct bpf_array, map.max_entries); 3088c2ecf20Sopenharmony_ci if (is_12b_check(off, insn)) 3098c2ecf20Sopenharmony_ci return -1; 3108c2ecf20Sopenharmony_ci emit(rv_lwu(RV_REG_T1, off, RV_REG_A1), ctx); 3118c2ecf20Sopenharmony_ci off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn)); 3128c2ecf20Sopenharmony_ci emit_branch(BPF_JGE, RV_REG_A2, RV_REG_T1, off, ctx); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* if (TCC-- < 0) 3158c2ecf20Sopenharmony_ci * goto out; 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci emit_addi(RV_REG_T1, tcc, -1, ctx); 3188c2ecf20Sopenharmony_ci off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn)); 3198c2ecf20Sopenharmony_ci emit_branch(BPF_JSLT, tcc, RV_REG_ZERO, off, ctx); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* prog = array->ptrs[index]; 3228c2ecf20Sopenharmony_ci * if (!prog) 3238c2ecf20Sopenharmony_ci * goto out; 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_A2, 3, ctx); 3268c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_A1, ctx); 3278c2ecf20Sopenharmony_ci off = offsetof(struct bpf_array, ptrs); 3288c2ecf20Sopenharmony_ci if (is_12b_check(off, insn)) 3298c2ecf20Sopenharmony_ci return -1; 3308c2ecf20Sopenharmony_ci emit_ld(RV_REG_T2, off, RV_REG_T2, ctx); 3318c2ecf20Sopenharmony_ci off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn)); 3328c2ecf20Sopenharmony_ci emit_branch(BPF_JEQ, RV_REG_T2, RV_REG_ZERO, off, ctx); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* goto *(prog->bpf_func + 4); */ 3358c2ecf20Sopenharmony_ci off = offsetof(struct bpf_prog, bpf_func); 3368c2ecf20Sopenharmony_ci if (is_12b_check(off, insn)) 3378c2ecf20Sopenharmony_ci return -1; 3388c2ecf20Sopenharmony_ci emit_ld(RV_REG_T3, off, RV_REG_T2, ctx); 3398c2ecf20Sopenharmony_ci emit_mv(RV_REG_TCC, RV_REG_T1, ctx); 3408c2ecf20Sopenharmony_ci __build_epilogue(true, ctx); 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void init_regs(u8 *rd, u8 *rs, const struct bpf_insn *insn, 3458c2ecf20Sopenharmony_ci struct rv_jit_context *ctx) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci u8 code = insn->code; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci switch (code) { 3508c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JA: 3518c2ecf20Sopenharmony_ci case BPF_JMP | BPF_CALL: 3528c2ecf20Sopenharmony_ci case BPF_JMP | BPF_EXIT: 3538c2ecf20Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci default: 3568c2ecf20Sopenharmony_ci *rd = bpf_to_rv_reg(insn->dst_reg, ctx); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (code & (BPF_ALU | BPF_X) || code & (BPF_ALU64 | BPF_X) || 3608c2ecf20Sopenharmony_ci code & (BPF_JMP | BPF_X) || code & (BPF_JMP32 | BPF_X) || 3618c2ecf20Sopenharmony_ci code & BPF_LDX || code & BPF_STX) 3628c2ecf20Sopenharmony_ci *rs = bpf_to_rv_reg(insn->src_reg, ctx); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic void emit_zext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci emit_mv(RV_REG_T2, *rd, ctx); 3688c2ecf20Sopenharmony_ci emit_zext_32(RV_REG_T2, ctx); 3698c2ecf20Sopenharmony_ci emit_mv(RV_REG_T1, *rs, ctx); 3708c2ecf20Sopenharmony_ci emit_zext_32(RV_REG_T1, ctx); 3718c2ecf20Sopenharmony_ci *rd = RV_REG_T2; 3728c2ecf20Sopenharmony_ci *rs = RV_REG_T1; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void emit_sext_32_rd_rs(u8 *rd, u8 *rs, struct rv_jit_context *ctx) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci emit_addiw(RV_REG_T2, *rd, 0, ctx); 3788c2ecf20Sopenharmony_ci emit_addiw(RV_REG_T1, *rs, 0, ctx); 3798c2ecf20Sopenharmony_ci *rd = RV_REG_T2; 3808c2ecf20Sopenharmony_ci *rs = RV_REG_T1; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void emit_zext_32_rd_t1(u8 *rd, struct rv_jit_context *ctx) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci emit_mv(RV_REG_T2, *rd, ctx); 3868c2ecf20Sopenharmony_ci emit_zext_32(RV_REG_T2, ctx); 3878c2ecf20Sopenharmony_ci emit_zext_32(RV_REG_T1, ctx); 3888c2ecf20Sopenharmony_ci *rd = RV_REG_T2; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic void emit_sext_32_rd(u8 *rd, struct rv_jit_context *ctx) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci emit_addiw(RV_REG_T2, *rd, 0, ctx); 3948c2ecf20Sopenharmony_ci *rd = RV_REG_T2; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int emit_jump_and_link(u8 rd, s64 rvoff, bool fixed_addr, 3988c2ecf20Sopenharmony_ci struct rv_jit_context *ctx) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci s64 upper, lower; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (rvoff && fixed_addr && is_21b_int(rvoff)) { 4038c2ecf20Sopenharmony_ci emit(rv_jal(rd, rvoff >> 1), ctx); 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci } else if (in_auipc_jalr_range(rvoff)) { 4068c2ecf20Sopenharmony_ci upper = (rvoff + (1 << 11)) >> 12; 4078c2ecf20Sopenharmony_ci lower = rvoff & 0xfff; 4088c2ecf20Sopenharmony_ci emit(rv_auipc(RV_REG_T1, upper), ctx); 4098c2ecf20Sopenharmony_ci emit(rv_jalr(rd, RV_REG_T1, lower), ctx); 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci pr_err("bpf-jit: target offset 0x%llx is out of range\n", rvoff); 4148c2ecf20Sopenharmony_ci return -ERANGE; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic bool is_signed_bpf_cond(u8 cond) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return cond == BPF_JSGT || cond == BPF_JSLT || 4208c2ecf20Sopenharmony_ci cond == BPF_JSGE || cond == BPF_JSLE; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int emit_call(u64 addr, bool fixed_addr, struct rv_jit_context *ctx) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci s64 off = 0; 4268c2ecf20Sopenharmony_ci u64 ip; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (addr && ctx->insns) { 4298c2ecf20Sopenharmony_ci ip = (u64)(long)(ctx->insns + ctx->ninsns); 4308c2ecf20Sopenharmony_ci off = addr - ip; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return emit_jump_and_link(RV_REG_RA, off, fixed_addr, ctx); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ciint bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, 4378c2ecf20Sopenharmony_ci bool extra_pass) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 || 4408c2ecf20Sopenharmony_ci BPF_CLASS(insn->code) == BPF_JMP; 4418c2ecf20Sopenharmony_ci int s, e, rvoff, ret, i = insn - ctx->prog->insnsi; 4428c2ecf20Sopenharmony_ci struct bpf_prog_aux *aux = ctx->prog->aux; 4438c2ecf20Sopenharmony_ci u8 rd = -1, rs = -1, code = insn->code; 4448c2ecf20Sopenharmony_ci s16 off = insn->off; 4458c2ecf20Sopenharmony_ci s32 imm = insn->imm; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci init_regs(&rd, &rs, insn, ctx); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci switch (code) { 4508c2ecf20Sopenharmony_ci /* dst = src */ 4518c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_X: 4528c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_X: 4538c2ecf20Sopenharmony_ci if (imm == 1) { 4548c2ecf20Sopenharmony_ci /* Special mov32 for zext */ 4558c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci emit_mv(rd, rs, ctx); 4598c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 4608c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* dst = dst OP src */ 4648c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_X: 4658c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_X: 4668c2ecf20Sopenharmony_ci emit_add(rd, rd, rs, ctx); 4678c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 4688c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_X: 4718c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_X: 4728c2ecf20Sopenharmony_ci if (is64) 4738c2ecf20Sopenharmony_ci emit_sub(rd, rd, rs, ctx); 4748c2ecf20Sopenharmony_ci else 4758c2ecf20Sopenharmony_ci emit_subw(rd, rd, rs, ctx); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 4788c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_X: 4818c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_X: 4828c2ecf20Sopenharmony_ci emit_and(rd, rd, rs, ctx); 4838c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 4848c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_X: 4878c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_X: 4888c2ecf20Sopenharmony_ci emit_or(rd, rd, rs, ctx); 4898c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 4908c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_X: 4938c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_X: 4948c2ecf20Sopenharmony_ci emit_xor(rd, rd, rs, ctx); 4958c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 4968c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_X: 4998c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_X: 5008c2ecf20Sopenharmony_ci emit(is64 ? rv_mul(rd, rd, rs) : rv_mulw(rd, rd, rs), ctx); 5018c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5028c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_X: 5058c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_X: 5068c2ecf20Sopenharmony_ci emit(is64 ? rv_divu(rd, rd, rs) : rv_divuw(rd, rd, rs), ctx); 5078c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5088c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_X: 5118c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_X: 5128c2ecf20Sopenharmony_ci emit(is64 ? rv_remu(rd, rd, rs) : rv_remuw(rd, rd, rs), ctx); 5138c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5148c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_X: 5178c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_X: 5188c2ecf20Sopenharmony_ci emit(is64 ? rv_sll(rd, rd, rs) : rv_sllw(rd, rd, rs), ctx); 5198c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5208c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_X: 5238c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_X: 5248c2ecf20Sopenharmony_ci emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx); 5258c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5268c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_X: 5298c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_X: 5308c2ecf20Sopenharmony_ci emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx); 5318c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5328c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* dst = -dst */ 5368c2ecf20Sopenharmony_ci case BPF_ALU | BPF_NEG: 5378c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_NEG: 5388c2ecf20Sopenharmony_ci emit_sub(rd, RV_REG_ZERO, rd, ctx); 5398c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 5408c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* dst = BSWAP##imm(dst) */ 5448c2ecf20Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_LE: 5458c2ecf20Sopenharmony_ci switch (imm) { 5468c2ecf20Sopenharmony_ci case 16: 5478c2ecf20Sopenharmony_ci emit_slli(rd, rd, 48, ctx); 5488c2ecf20Sopenharmony_ci emit_srli(rd, rd, 48, ctx); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case 32: 5518c2ecf20Sopenharmony_ci if (!aux->verifier_zext) 5528c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci case 64: 5558c2ecf20Sopenharmony_ci /* Do nothing */ 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_BE: 5618c2ecf20Sopenharmony_ci emit_li(RV_REG_T2, 0, ctx); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5648c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5658c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 5668c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 5678c2ecf20Sopenharmony_ci if (imm == 16) 5688c2ecf20Sopenharmony_ci goto out_be; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5718c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5728c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 5738c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5768c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5778c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 5788c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 5798c2ecf20Sopenharmony_ci if (imm == 32) 5808c2ecf20Sopenharmony_ci goto out_be; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5838c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5848c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 5858c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5888c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5898c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 5908c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5938c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5948c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 5958c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 5988c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 5998c2ecf20Sopenharmony_ci emit_slli(RV_REG_T2, RV_REG_T2, 8, ctx); 6008c2ecf20Sopenharmony_ci emit_srli(rd, rd, 8, ctx); 6018c2ecf20Sopenharmony_ciout_be: 6028c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, 0xff, ctx); 6038c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, RV_REG_T1, ctx); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci emit_mv(rd, RV_REG_T2, ctx); 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* dst = imm */ 6098c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_K: 6108c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_K: 6118c2ecf20Sopenharmony_ci emit_imm(rd, imm, ctx); 6128c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6138c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* dst = dst OP imm */ 6178c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_K: 6188c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_K: 6198c2ecf20Sopenharmony_ci if (is_12b_int(imm)) { 6208c2ecf20Sopenharmony_ci emit_addi(rd, rd, imm, ctx); 6218c2ecf20Sopenharmony_ci } else { 6228c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6238c2ecf20Sopenharmony_ci emit_add(rd, rd, RV_REG_T1, ctx); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6268c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_K: 6298c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_K: 6308c2ecf20Sopenharmony_ci if (is_12b_int(-imm)) { 6318c2ecf20Sopenharmony_ci emit_addi(rd, rd, -imm, ctx); 6328c2ecf20Sopenharmony_ci } else { 6338c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6348c2ecf20Sopenharmony_ci emit_sub(rd, rd, RV_REG_T1, ctx); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6378c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_K: 6408c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_K: 6418c2ecf20Sopenharmony_ci if (is_12b_int(imm)) { 6428c2ecf20Sopenharmony_ci emit_andi(rd, rd, imm, ctx); 6438c2ecf20Sopenharmony_ci } else { 6448c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6458c2ecf20Sopenharmony_ci emit_and(rd, rd, RV_REG_T1, ctx); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6488c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6498c2ecf20Sopenharmony_ci break; 6508c2ecf20Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_K: 6518c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_K: 6528c2ecf20Sopenharmony_ci if (is_12b_int(imm)) { 6538c2ecf20Sopenharmony_ci emit(rv_ori(rd, rd, imm), ctx); 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6568c2ecf20Sopenharmony_ci emit_or(rd, rd, RV_REG_T1, ctx); 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6598c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_K: 6628c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_K: 6638c2ecf20Sopenharmony_ci if (is_12b_int(imm)) { 6648c2ecf20Sopenharmony_ci emit(rv_xori(rd, rd, imm), ctx); 6658c2ecf20Sopenharmony_ci } else { 6668c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6678c2ecf20Sopenharmony_ci emit_xor(rd, rd, RV_REG_T1, ctx); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6708c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_K: 6738c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_K: 6748c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6758c2ecf20Sopenharmony_ci emit(is64 ? rv_mul(rd, rd, RV_REG_T1) : 6768c2ecf20Sopenharmony_ci rv_mulw(rd, rd, RV_REG_T1), ctx); 6778c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6788c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_K: 6818c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_K: 6828c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6838c2ecf20Sopenharmony_ci emit(is64 ? rv_divu(rd, rd, RV_REG_T1) : 6848c2ecf20Sopenharmony_ci rv_divuw(rd, rd, RV_REG_T1), ctx); 6858c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6868c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_K: 6898c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_K: 6908c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 6918c2ecf20Sopenharmony_ci emit(is64 ? rv_remu(rd, rd, RV_REG_T1) : 6928c2ecf20Sopenharmony_ci rv_remuw(rd, rd, RV_REG_T1), ctx); 6938c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 6948c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_K: 6978c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_K: 6988c2ecf20Sopenharmony_ci emit_slli(rd, rd, imm, ctx); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 7018c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_K: 7048c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_K: 7058c2ecf20Sopenharmony_ci if (is64) 7068c2ecf20Sopenharmony_ci emit_srli(rd, rd, imm, ctx); 7078c2ecf20Sopenharmony_ci else 7088c2ecf20Sopenharmony_ci emit(rv_srliw(rd, rd, imm), ctx); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 7118c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_K: 7148c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_K: 7158c2ecf20Sopenharmony_ci if (is64) 7168c2ecf20Sopenharmony_ci emit_srai(rd, rd, imm, ctx); 7178c2ecf20Sopenharmony_ci else 7188c2ecf20Sopenharmony_ci emit(rv_sraiw(rd, rd, imm), ctx); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (!is64 && !aux->verifier_zext) 7218c2ecf20Sopenharmony_ci emit_zext_32(rd, ctx); 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* JUMP off */ 7258c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JA: 7268c2ecf20Sopenharmony_ci rvoff = rv_offset(i, off, ctx); 7278c2ecf20Sopenharmony_ci ret = emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx); 7288c2ecf20Sopenharmony_ci if (ret) 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* IF (dst COND src) JUMP off */ 7338c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: 7348c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: 7358c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: 7368c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: 7378c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: 7388c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: 7398c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: 7408c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: 7418c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: 7428c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: 7438c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: 7448c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: 7458c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: 7468c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: 7478c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: 7488c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: 7498c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: 7508c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: 7518c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: 7528c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: 7538c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: 7548c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: 7558c2ecf20Sopenharmony_ci rvoff = rv_offset(i, off, ctx); 7568c2ecf20Sopenharmony_ci if (!is64) { 7578c2ecf20Sopenharmony_ci s = ctx->ninsns; 7588c2ecf20Sopenharmony_ci if (is_signed_bpf_cond(BPF_OP(code))) 7598c2ecf20Sopenharmony_ci emit_sext_32_rd_rs(&rd, &rs, ctx); 7608c2ecf20Sopenharmony_ci else 7618c2ecf20Sopenharmony_ci emit_zext_32_rd_rs(&rd, &rs, ctx); 7628c2ecf20Sopenharmony_ci e = ctx->ninsns; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Adjust for extra insns */ 7658c2ecf20Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (BPF_OP(code) == BPF_JSET) { 7698c2ecf20Sopenharmony_ci /* Adjust for and */ 7708c2ecf20Sopenharmony_ci rvoff -= 4; 7718c2ecf20Sopenharmony_ci emit_and(RV_REG_T1, rd, rs, ctx); 7728c2ecf20Sopenharmony_ci emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, 7738c2ecf20Sopenharmony_ci ctx); 7748c2ecf20Sopenharmony_ci } else { 7758c2ecf20Sopenharmony_ci emit_branch(BPF_OP(code), rd, rs, rvoff, ctx); 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* IF (dst COND imm) JUMP off */ 7808c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: 7818c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: 7828c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: 7838c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: 7848c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: 7858c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: 7868c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: 7878c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: 7888c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: 7898c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: 7908c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: 7918c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: 7928c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: 7938c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: 7948c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: 7958c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: 7968c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: 7978c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: 7988c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: 7998c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: 8008c2ecf20Sopenharmony_ci rvoff = rv_offset(i, off, ctx); 8018c2ecf20Sopenharmony_ci s = ctx->ninsns; 8028c2ecf20Sopenharmony_ci if (imm) { 8038c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 8048c2ecf20Sopenharmony_ci rs = RV_REG_T1; 8058c2ecf20Sopenharmony_ci } else { 8068c2ecf20Sopenharmony_ci /* If imm is 0, simply use zero register. */ 8078c2ecf20Sopenharmony_ci rs = RV_REG_ZERO; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci if (!is64) { 8108c2ecf20Sopenharmony_ci if (is_signed_bpf_cond(BPF_OP(code))) 8118c2ecf20Sopenharmony_ci emit_sext_32_rd(&rd, ctx); 8128c2ecf20Sopenharmony_ci else 8138c2ecf20Sopenharmony_ci emit_zext_32_rd_t1(&rd, ctx); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci e = ctx->ninsns; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Adjust for extra insns */ 8188c2ecf20Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 8198c2ecf20Sopenharmony_ci emit_branch(BPF_OP(code), rd, rs, rvoff, ctx); 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: 8238c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: 8248c2ecf20Sopenharmony_ci rvoff = rv_offset(i, off, ctx); 8258c2ecf20Sopenharmony_ci s = ctx->ninsns; 8268c2ecf20Sopenharmony_ci if (is_12b_int(imm)) { 8278c2ecf20Sopenharmony_ci emit_andi(RV_REG_T1, rd, imm, ctx); 8288c2ecf20Sopenharmony_ci } else { 8298c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 8308c2ecf20Sopenharmony_ci emit_and(RV_REG_T1, rd, RV_REG_T1, ctx); 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci /* For jset32, we should clear the upper 32 bits of t1, but 8338c2ecf20Sopenharmony_ci * sign-extension is sufficient here and saves one instruction, 8348c2ecf20Sopenharmony_ci * as t1 is used only in comparison against zero. 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci if (!is64 && imm < 0) 8378c2ecf20Sopenharmony_ci emit_addiw(RV_REG_T1, RV_REG_T1, 0, ctx); 8388c2ecf20Sopenharmony_ci e = ctx->ninsns; 8398c2ecf20Sopenharmony_ci rvoff -= ninsns_rvoff(e - s); 8408c2ecf20Sopenharmony_ci emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, ctx); 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* function call */ 8448c2ecf20Sopenharmony_ci case BPF_JMP | BPF_CALL: 8458c2ecf20Sopenharmony_ci { 8468c2ecf20Sopenharmony_ci bool fixed_addr; 8478c2ecf20Sopenharmony_ci u64 addr; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci mark_call(ctx); 8508c2ecf20Sopenharmony_ci ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, 8518c2ecf20Sopenharmony_ci &addr, &fixed_addr); 8528c2ecf20Sopenharmony_ci if (ret < 0) 8538c2ecf20Sopenharmony_ci return ret; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci ret = emit_call(addr, fixed_addr, ctx); 8568c2ecf20Sopenharmony_ci if (ret) 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (insn->src_reg != BPF_PSEUDO_CALL) 8608c2ecf20Sopenharmony_ci emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx); 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci /* tail call */ 8648c2ecf20Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: 8658c2ecf20Sopenharmony_ci if (emit_bpf_tail_call(i, ctx)) 8668c2ecf20Sopenharmony_ci return -1; 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* function return */ 8708c2ecf20Sopenharmony_ci case BPF_JMP | BPF_EXIT: 8718c2ecf20Sopenharmony_ci if (i == ctx->prog->len - 1) 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci rvoff = epilogue_offset(ctx); 8758c2ecf20Sopenharmony_ci ret = emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx); 8768c2ecf20Sopenharmony_ci if (ret) 8778c2ecf20Sopenharmony_ci return ret; 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* dst = imm64 */ 8818c2ecf20Sopenharmony_ci case BPF_LD | BPF_IMM | BPF_DW: 8828c2ecf20Sopenharmony_ci { 8838c2ecf20Sopenharmony_ci struct bpf_insn insn1 = insn[1]; 8848c2ecf20Sopenharmony_ci u64 imm64; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci imm64 = (u64)insn1.imm << 32 | (u32)imm; 8878c2ecf20Sopenharmony_ci emit_imm(rd, imm64, ctx); 8888c2ecf20Sopenharmony_ci return 1; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* LDX: dst = *(size *)(src + off) */ 8928c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_B: 8938c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 8948c2ecf20Sopenharmony_ci emit(rv_lbu(rd, off, rs), ctx); 8958c2ecf20Sopenharmony_ci break; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 8998c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); 9008c2ecf20Sopenharmony_ci emit(rv_lbu(rd, 0, RV_REG_T1), ctx); 9018c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 9028c2ecf20Sopenharmony_ci return 1; 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_H: 9058c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9068c2ecf20Sopenharmony_ci emit(rv_lhu(rd, off, rs), ctx); 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 9118c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); 9128c2ecf20Sopenharmony_ci emit(rv_lhu(rd, 0, RV_REG_T1), ctx); 9138c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 9148c2ecf20Sopenharmony_ci return 1; 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_W: 9178c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9188c2ecf20Sopenharmony_ci emit(rv_lwu(rd, off, rs), ctx); 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 9238c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); 9248c2ecf20Sopenharmony_ci emit(rv_lwu(rd, 0, RV_REG_T1), ctx); 9258c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 9268c2ecf20Sopenharmony_ci return 1; 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_DW: 9298c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9308c2ecf20Sopenharmony_ci emit_ld(rd, off, rs, ctx); 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 9358c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rs, ctx); 9368c2ecf20Sopenharmony_ci emit_ld(rd, 0, RV_REG_T1, ctx); 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* speculation barrier */ 9408c2ecf20Sopenharmony_ci case BPF_ST | BPF_NOSPEC: 9418c2ecf20Sopenharmony_ci break; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* ST: *(size *)(dst + off) = imm */ 9448c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_B: 9458c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 9468c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9478c2ecf20Sopenharmony_ci emit(rv_sb(rd, off, RV_REG_T1), ctx); 9488c2ecf20Sopenharmony_ci break; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci emit_imm(RV_REG_T2, off, ctx); 9528c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); 9538c2ecf20Sopenharmony_ci emit(rv_sb(RV_REG_T2, 0, RV_REG_T1), ctx); 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_H: 9578c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 9588c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9598c2ecf20Sopenharmony_ci emit(rv_sh(rd, off, RV_REG_T1), ctx); 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci emit_imm(RV_REG_T2, off, ctx); 9648c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); 9658c2ecf20Sopenharmony_ci emit(rv_sh(RV_REG_T2, 0, RV_REG_T1), ctx); 9668c2ecf20Sopenharmony_ci break; 9678c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_W: 9688c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 9698c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9708c2ecf20Sopenharmony_ci emit_sw(rd, off, RV_REG_T1, ctx); 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci emit_imm(RV_REG_T2, off, ctx); 9758c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); 9768c2ecf20Sopenharmony_ci emit_sw(RV_REG_T2, 0, RV_REG_T1, ctx); 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_DW: 9798c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, imm, ctx); 9808c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9818c2ecf20Sopenharmony_ci emit_sd(rd, off, RV_REG_T1, ctx); 9828c2ecf20Sopenharmony_ci break; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci emit_imm(RV_REG_T2, off, ctx); 9868c2ecf20Sopenharmony_ci emit_add(RV_REG_T2, RV_REG_T2, rd, ctx); 9878c2ecf20Sopenharmony_ci emit_sd(RV_REG_T2, 0, RV_REG_T1, ctx); 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* STX: *(size *)(dst + off) = src */ 9918c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_B: 9928c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 9938c2ecf20Sopenharmony_ci emit(rv_sb(rd, off, rs), ctx); 9948c2ecf20Sopenharmony_ci break; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 9988c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); 9998c2ecf20Sopenharmony_ci emit(rv_sb(RV_REG_T1, 0, rs), ctx); 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_H: 10028c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 10038c2ecf20Sopenharmony_ci emit(rv_sh(rd, off, rs), ctx); 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 10088c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); 10098c2ecf20Sopenharmony_ci emit(rv_sh(RV_REG_T1, 0, rs), ctx); 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_W: 10128c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 10138c2ecf20Sopenharmony_ci emit_sw(rd, off, rs, ctx); 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 10188c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); 10198c2ecf20Sopenharmony_ci emit_sw(RV_REG_T1, 0, rs, ctx); 10208c2ecf20Sopenharmony_ci break; 10218c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_DW: 10228c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 10238c2ecf20Sopenharmony_ci emit_sd(rd, off, rs, ctx); 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 10288c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); 10298c2ecf20Sopenharmony_ci emit_sd(RV_REG_T1, 0, rs, ctx); 10308c2ecf20Sopenharmony_ci break; 10318c2ecf20Sopenharmony_ci /* STX XADD: lock *(u32 *)(dst + off) += src */ 10328c2ecf20Sopenharmony_ci case BPF_STX | BPF_XADD | BPF_W: 10338c2ecf20Sopenharmony_ci /* STX XADD: lock *(u64 *)(dst + off) += src */ 10348c2ecf20Sopenharmony_ci case BPF_STX | BPF_XADD | BPF_DW: 10358c2ecf20Sopenharmony_ci if (off) { 10368c2ecf20Sopenharmony_ci if (is_12b_int(off)) { 10378c2ecf20Sopenharmony_ci emit_addi(RV_REG_T1, rd, off, ctx); 10388c2ecf20Sopenharmony_ci } else { 10398c2ecf20Sopenharmony_ci emit_imm(RV_REG_T1, off, ctx); 10408c2ecf20Sopenharmony_ci emit_add(RV_REG_T1, RV_REG_T1, rd, ctx); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci rd = RV_REG_T1; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci emit(BPF_SIZE(code) == BPF_W ? 10478c2ecf20Sopenharmony_ci rv_amoadd_w(RV_REG_ZERO, rs, rd, 0, 0) : 10488c2ecf20Sopenharmony_ci rv_amoadd_d(RV_REG_ZERO, rs, rd, 0, 0), ctx); 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci default: 10518c2ecf20Sopenharmony_ci pr_err("bpf-jit: unknown opcode %02x\n", code); 10528c2ecf20Sopenharmony_ci return -EINVAL; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci return 0; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_civoid bpf_jit_build_prologue(struct rv_jit_context *ctx) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci int stack_adjust = 0, store_offset, bpf_stack_adjust; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16); 10638c2ecf20Sopenharmony_ci if (bpf_stack_adjust) 10648c2ecf20Sopenharmony_ci mark_fp(ctx); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_RA, ctx)) 10678c2ecf20Sopenharmony_ci stack_adjust += 8; 10688c2ecf20Sopenharmony_ci stack_adjust += 8; /* RV_REG_FP */ 10698c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S1, ctx)) 10708c2ecf20Sopenharmony_ci stack_adjust += 8; 10718c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S2, ctx)) 10728c2ecf20Sopenharmony_ci stack_adjust += 8; 10738c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S3, ctx)) 10748c2ecf20Sopenharmony_ci stack_adjust += 8; 10758c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S4, ctx)) 10768c2ecf20Sopenharmony_ci stack_adjust += 8; 10778c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S5, ctx)) 10788c2ecf20Sopenharmony_ci stack_adjust += 8; 10798c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S6, ctx)) 10808c2ecf20Sopenharmony_ci stack_adjust += 8; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci stack_adjust = round_up(stack_adjust, 16); 10838c2ecf20Sopenharmony_ci stack_adjust += bpf_stack_adjust; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci store_offset = stack_adjust - 8; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* First instruction is always setting the tail-call-counter 10888c2ecf20Sopenharmony_ci * (TCC) register. This instruction is skipped for tail calls. 10898c2ecf20Sopenharmony_ci * Force using a 4-byte (non-compressed) instruction. 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_ci emit(rv_addi(RV_REG_TCC, RV_REG_ZERO, MAX_TAIL_CALL_CNT), ctx); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci emit_addi(RV_REG_SP, RV_REG_SP, -stack_adjust, ctx); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_RA, ctx)) { 10968c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_RA, ctx); 10978c2ecf20Sopenharmony_ci store_offset -= 8; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_FP, ctx); 11008c2ecf20Sopenharmony_ci store_offset -= 8; 11018c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S1, ctx)) { 11028c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_S1, ctx); 11038c2ecf20Sopenharmony_ci store_offset -= 8; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S2, ctx)) { 11068c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_S2, ctx); 11078c2ecf20Sopenharmony_ci store_offset -= 8; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S3, ctx)) { 11108c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_S3, ctx); 11118c2ecf20Sopenharmony_ci store_offset -= 8; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S4, ctx)) { 11148c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_S4, ctx); 11158c2ecf20Sopenharmony_ci store_offset -= 8; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S5, ctx)) { 11188c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_S5, ctx); 11198c2ecf20Sopenharmony_ci store_offset -= 8; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci if (seen_reg(RV_REG_S6, ctx)) { 11228c2ecf20Sopenharmony_ci emit_sd(RV_REG_SP, store_offset, RV_REG_S6, ctx); 11238c2ecf20Sopenharmony_ci store_offset -= 8; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (bpf_stack_adjust) 11298c2ecf20Sopenharmony_ci emit_addi(RV_REG_S5, RV_REG_SP, bpf_stack_adjust, ctx); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* Program contains calls and tail calls, so RV_REG_TCC need 11328c2ecf20Sopenharmony_ci * to be saved across calls. 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci if (seen_tail_call(ctx) && seen_call(ctx)) 11358c2ecf20Sopenharmony_ci emit_mv(RV_REG_TCC_SAVED, RV_REG_TCC, ctx); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci ctx->stack_size = stack_adjust; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_civoid bpf_jit_build_epilogue(struct rv_jit_context *ctx) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci __build_epilogue(false, ctx); 11438c2ecf20Sopenharmony_ci} 1144