162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * BPF JIT compiler for PA-RISC (32-bit) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2023 Helge Deller <deller@gmx.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * The code is based on the BPF JIT compiler for RV64 by Björn Töpel and 862306a36Sopenharmony_ci * the BPF JIT compiler for 32-bit ARM by Shubham Bansal and Mircea Gherzan. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/bpf.h> 1262306a36Sopenharmony_ci#include <linux/filter.h> 1362306a36Sopenharmony_ci#include <linux/libgcc.h> 1462306a36Sopenharmony_ci#include "bpf_jit.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * Stack layout during BPF program execution (note: stack grows up): 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * high 2062306a36Sopenharmony_ci * HPPA32 sp => +----------+ <= HPPA32 fp 2162306a36Sopenharmony_ci * | saved sp | 2262306a36Sopenharmony_ci * | saved rp | 2362306a36Sopenharmony_ci * | ... | HPPA32 callee-saved registers 2462306a36Sopenharmony_ci * | curr args| 2562306a36Sopenharmony_ci * | local var| 2662306a36Sopenharmony_ci * +----------+ <= (sp - 4 * NR_SAVED_REGISTERS) 2762306a36Sopenharmony_ci * | lo(R9) | 2862306a36Sopenharmony_ci * | hi(R9) | 2962306a36Sopenharmony_ci * | lo(FP) | JIT scratch space for BPF registers 3062306a36Sopenharmony_ci * | hi(FP) | 3162306a36Sopenharmony_ci * | ... | 3262306a36Sopenharmony_ci * +----------+ <= (sp - 4 * NR_SAVED_REGISTERS 3362306a36Sopenharmony_ci * | | - 4 * BPF_JIT_SCRATCH_REGS) 3462306a36Sopenharmony_ci * | | 3562306a36Sopenharmony_ci * | ... | BPF program stack 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_R8_HI, 4662306a36Sopenharmony_ci BPF_R8_LO, 4762306a36Sopenharmony_ci BPF_R9_HI, 4862306a36Sopenharmony_ci BPF_R9_LO, 4962306a36Sopenharmony_ci BPF_FP_HI, 5062306a36Sopenharmony_ci BPF_FP_LO, 5162306a36Sopenharmony_ci BPF_AX_HI, 5262306a36Sopenharmony_ci BPF_AX_LO, 5362306a36Sopenharmony_ci BPF_R0_TEMP_HI, 5462306a36Sopenharmony_ci BPF_R0_TEMP_LO, 5562306a36Sopenharmony_ci BPF_JIT_SCRATCH_REGS, 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* Number of callee-saved registers stored to stack: rp, r3-r18. */ 5962306a36Sopenharmony_ci#define NR_SAVED_REGISTERS (18 - 3 + 1 + 8) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Offset from fp for BPF registers stored on stack. */ 6262306a36Sopenharmony_ci#define STACK_OFFSET(k) (- (NR_SAVED_REGISTERS + k + 1)) 6362306a36Sopenharmony_ci#define STACK_ALIGN FRAME_SIZE 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define EXIT_PTR_LOAD(reg) hppa_ldw(-0x08, HPPA_REG_SP, reg) 6662306a36Sopenharmony_ci#define EXIT_PTR_STORE(reg) hppa_stw(reg, -0x08, HPPA_REG_SP) 6762306a36Sopenharmony_ci#define EXIT_PTR_JUMP(reg, nop) hppa_bv(HPPA_REG_ZERO, reg, nop) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define TMP_REG_1 (MAX_BPF_JIT_REG + 0) 7062306a36Sopenharmony_ci#define TMP_REG_2 (MAX_BPF_JIT_REG + 1) 7162306a36Sopenharmony_ci#define TMP_REG_R0 (MAX_BPF_JIT_REG + 2) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const s8 regmap[][2] = { 7462306a36Sopenharmony_ci /* Return value from in-kernel function, and exit value from eBPF. */ 7562306a36Sopenharmony_ci [BPF_REG_0] = {HPPA_REG_RET0, HPPA_REG_RET1}, /* HI/LOW */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Arguments from eBPF program to in-kernel function. */ 7862306a36Sopenharmony_ci [BPF_REG_1] = {HPPA_R(3), HPPA_R(4)}, 7962306a36Sopenharmony_ci [BPF_REG_2] = {HPPA_R(5), HPPA_R(6)}, 8062306a36Sopenharmony_ci [BPF_REG_3] = {HPPA_R(7), HPPA_R(8)}, 8162306a36Sopenharmony_ci [BPF_REG_4] = {HPPA_R(9), HPPA_R(10)}, 8262306a36Sopenharmony_ci [BPF_REG_5] = {HPPA_R(11), HPPA_R(12)}, 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci [BPF_REG_6] = {HPPA_R(13), HPPA_R(14)}, 8562306a36Sopenharmony_ci [BPF_REG_7] = {HPPA_R(15), HPPA_R(16)}, 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Callee-saved registers that in-kernel function will preserve. 8862306a36Sopenharmony_ci * Stored on the stack. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci [BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)}, 9162306a36Sopenharmony_ci [BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)}, 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Read-only frame pointer to access BPF stack. Not needed. */ 9462306a36Sopenharmony_ci [BPF_REG_FP] = {STACK_OFFSET(BPF_FP_HI), STACK_OFFSET(BPF_FP_LO)}, 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* Temporary register for blinding constants. Stored on the stack. */ 9762306a36Sopenharmony_ci [BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)}, 9862306a36Sopenharmony_ci /* 9962306a36Sopenharmony_ci * Temporary registers used by the JIT to operate on registers stored 10062306a36Sopenharmony_ci * on the stack. Save t0 and t1 to be used as temporaries in generated 10162306a36Sopenharmony_ci * code. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci [TMP_REG_1] = {HPPA_REG_T3, HPPA_REG_T2}, 10462306a36Sopenharmony_ci [TMP_REG_2] = {HPPA_REG_T5, HPPA_REG_T4}, 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* temporary space for BPF_R0 during libgcc and millicode calls */ 10762306a36Sopenharmony_ci [TMP_REG_R0] = {STACK_OFFSET(BPF_R0_TEMP_HI), STACK_OFFSET(BPF_R0_TEMP_LO)}, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic s8 hi(const s8 *r) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return r[0]; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic s8 lo(const s8 *r) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci return r[1]; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void emit_hppa_copy(const s8 rs, const s8 rd, struct hppa_jit_context *ctx) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci REG_SET_SEEN(ctx, rd); 12362306a36Sopenharmony_ci if (OPTIMIZE_HPPA && (rs == rd)) 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci REG_SET_SEEN(ctx, rs); 12662306a36Sopenharmony_ci emit(hppa_copy(rs, rd), ctx); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void emit_hppa_xor(const s8 r1, const s8 r2, const s8 r3, struct hppa_jit_context *ctx) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci REG_SET_SEEN(ctx, r1); 13262306a36Sopenharmony_ci REG_SET_SEEN(ctx, r2); 13362306a36Sopenharmony_ci REG_SET_SEEN(ctx, r3); 13462306a36Sopenharmony_ci if (OPTIMIZE_HPPA && (r1 == r2)) { 13562306a36Sopenharmony_ci emit(hppa_copy(HPPA_REG_ZERO, r3), ctx); 13662306a36Sopenharmony_ci } else { 13762306a36Sopenharmony_ci emit(hppa_xor(r1, r2, r3), ctx); 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void emit_imm(const s8 rd, s32 imm, struct hppa_jit_context *ctx) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci u32 lower = im11(imm); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci REG_SET_SEEN(ctx, rd); 14662306a36Sopenharmony_ci if (OPTIMIZE_HPPA && relative_bits_ok(imm, 14)) { 14762306a36Sopenharmony_ci emit(hppa_ldi(imm, rd), ctx); 14862306a36Sopenharmony_ci return; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci emit(hppa_ldil(imm, rd), ctx); 15162306a36Sopenharmony_ci if (OPTIMIZE_HPPA && (lower == 0)) 15262306a36Sopenharmony_ci return; 15362306a36Sopenharmony_ci emit(hppa_ldo(lower, rd, rd), ctx); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void emit_imm32(const s8 *rd, s32 imm, struct hppa_jit_context *ctx) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci /* Emit immediate into lower bits. */ 15962306a36Sopenharmony_ci REG_SET_SEEN(ctx, lo(rd)); 16062306a36Sopenharmony_ci emit_imm(lo(rd), imm, ctx); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Sign-extend into upper bits. */ 16362306a36Sopenharmony_ci REG_SET_SEEN(ctx, hi(rd)); 16462306a36Sopenharmony_ci if (imm >= 0) 16562306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 16662306a36Sopenharmony_ci else 16762306a36Sopenharmony_ci emit(hppa_ldi(-1, hi(rd)), ctx); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void emit_imm64(const s8 *rd, s32 imm_hi, s32 imm_lo, 17162306a36Sopenharmony_ci struct hppa_jit_context *ctx) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci emit_imm(hi(rd), imm_hi, ctx); 17462306a36Sopenharmony_ci emit_imm(lo(rd), imm_lo, ctx); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void __build_epilogue(bool is_tail_call, struct hppa_jit_context *ctx) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci const s8 *r0 = regmap[BPF_REG_0]; 18062306a36Sopenharmony_ci int i; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (is_tail_call) { 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * goto *(t0 + 4); 18562306a36Sopenharmony_ci * Skips first instruction of prologue which initializes tail 18662306a36Sopenharmony_ci * call counter. Assumes t0 contains address of target program, 18762306a36Sopenharmony_ci * see emit_bpf_tail_call. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci emit(hppa_ldo(1 * HPPA_INSN_SIZE, HPPA_REG_T0, HPPA_REG_T0), ctx); 19062306a36Sopenharmony_ci emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_T0, EXEC_NEXT_INSTR), ctx); 19162306a36Sopenharmony_ci /* in delay slot: */ 19262306a36Sopenharmony_ci emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_IN_INIT), ctx); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* load epilogue function pointer and jump to it. */ 19862306a36Sopenharmony_ci /* exit point is either directly below, or the outest TCC exit function */ 19962306a36Sopenharmony_ci emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx); 20062306a36Sopenharmony_ci emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* NOTE: we are 32-bit and big-endian, so return lower 32-bit value */ 20362306a36Sopenharmony_ci emit_hppa_copy(lo(r0), HPPA_REG_RET0, ctx); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Restore callee-saved registers. */ 20662306a36Sopenharmony_ci for (i = 3; i <= 18; i++) { 20762306a36Sopenharmony_ci if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i))) 20862306a36Sopenharmony_ci continue; 20962306a36Sopenharmony_ci emit(hppa_ldw(-REG_SIZE * (8 + (i-3)), HPPA_REG_SP, HPPA_R(i)), ctx); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* load original return pointer (stored by outest TCC function) */ 21362306a36Sopenharmony_ci emit(hppa_ldw(-0x14, HPPA_REG_SP, HPPA_REG_RP), ctx); 21462306a36Sopenharmony_ci emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_RP, EXEC_NEXT_INSTR), ctx); 21562306a36Sopenharmony_ci /* in delay slot: */ 21662306a36Sopenharmony_ci emit(hppa_ldw(-0x04, HPPA_REG_SP, HPPA_REG_SP), ctx); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic bool is_stacked(s8 reg) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return reg < 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic const s8 *bpf_get_reg64_offset(const s8 *reg, const s8 *tmp, 22562306a36Sopenharmony_ci u16 offset_sp, struct hppa_jit_context *ctx) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci if (is_stacked(hi(reg))) { 22862306a36Sopenharmony_ci emit(hppa_ldw(REG_SIZE * hi(reg) - offset_sp, HPPA_REG_SP, hi(tmp)), ctx); 22962306a36Sopenharmony_ci emit(hppa_ldw(REG_SIZE * lo(reg) - offset_sp, HPPA_REG_SP, lo(tmp)), ctx); 23062306a36Sopenharmony_ci reg = tmp; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci REG_SET_SEEN(ctx, hi(reg)); 23362306a36Sopenharmony_ci REG_SET_SEEN(ctx, lo(reg)); 23462306a36Sopenharmony_ci return reg; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic const s8 *bpf_get_reg64(const s8 *reg, const s8 *tmp, 23862306a36Sopenharmony_ci struct hppa_jit_context *ctx) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci return bpf_get_reg64_offset(reg, tmp, 0, ctx); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const s8 *bpf_get_reg64_ref(const s8 *reg, const s8 *tmp, 24462306a36Sopenharmony_ci bool must_load, struct hppa_jit_context *ctx) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci if (!OPTIMIZE_HPPA) 24762306a36Sopenharmony_ci return bpf_get_reg64(reg, tmp, ctx); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (is_stacked(hi(reg))) { 25062306a36Sopenharmony_ci if (must_load) 25162306a36Sopenharmony_ci emit(hppa_ldw(REG_SIZE * hi(reg), HPPA_REG_SP, hi(tmp)), ctx); 25262306a36Sopenharmony_ci reg = tmp; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci REG_SET_SEEN(ctx, hi(reg)); 25562306a36Sopenharmony_ci REG_SET_SEEN(ctx, lo(reg)); 25662306a36Sopenharmony_ci return reg; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic void bpf_put_reg64(const s8 *reg, const s8 *src, 26162306a36Sopenharmony_ci struct hppa_jit_context *ctx) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci if (is_stacked(hi(reg))) { 26462306a36Sopenharmony_ci emit(hppa_stw(hi(src), REG_SIZE * hi(reg), HPPA_REG_SP), ctx); 26562306a36Sopenharmony_ci emit(hppa_stw(lo(src), REG_SIZE * lo(reg), HPPA_REG_SP), ctx); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void bpf_save_R0(struct hppa_jit_context *ctx) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci bpf_put_reg64(regmap[TMP_REG_R0], regmap[BPF_REG_0], ctx); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void bpf_restore_R0(struct hppa_jit_context *ctx) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci bpf_get_reg64(regmap[TMP_REG_R0], regmap[BPF_REG_0], ctx); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic const s8 *bpf_get_reg32(const s8 *reg, const s8 *tmp, 28162306a36Sopenharmony_ci struct hppa_jit_context *ctx) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci if (is_stacked(lo(reg))) { 28462306a36Sopenharmony_ci emit(hppa_ldw(REG_SIZE * lo(reg), HPPA_REG_SP, lo(tmp)), ctx); 28562306a36Sopenharmony_ci reg = tmp; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci REG_SET_SEEN(ctx, lo(reg)); 28862306a36Sopenharmony_ci return reg; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic const s8 *bpf_get_reg32_ref(const s8 *reg, const s8 *tmp, 29262306a36Sopenharmony_ci struct hppa_jit_context *ctx) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci if (!OPTIMIZE_HPPA) 29562306a36Sopenharmony_ci return bpf_get_reg32(reg, tmp, ctx); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (is_stacked(hi(reg))) { 29862306a36Sopenharmony_ci reg = tmp; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci REG_SET_SEEN(ctx, lo(reg)); 30162306a36Sopenharmony_ci return reg; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void bpf_put_reg32(const s8 *reg, const s8 *src, 30562306a36Sopenharmony_ci struct hppa_jit_context *ctx) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci if (is_stacked(lo(reg))) { 30862306a36Sopenharmony_ci REG_SET_SEEN(ctx, lo(src)); 30962306a36Sopenharmony_ci emit(hppa_stw(lo(src), REG_SIZE * lo(reg), HPPA_REG_SP), ctx); 31062306a36Sopenharmony_ci if (1 && !ctx->prog->aux->verifier_zext) { 31162306a36Sopenharmony_ci REG_SET_SEEN(ctx, hi(reg)); 31262306a36Sopenharmony_ci emit(hppa_stw(HPPA_REG_ZERO, REG_SIZE * hi(reg), HPPA_REG_SP), ctx); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci } else if (1 && !ctx->prog->aux->verifier_zext) { 31562306a36Sopenharmony_ci REG_SET_SEEN(ctx, hi(reg)); 31662306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(reg), ctx); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* extern hppa millicode functions */ 32162306a36Sopenharmony_ciextern void $$mulI(void); 32262306a36Sopenharmony_ciextern void $$divU(void); 32362306a36Sopenharmony_ciextern void $$remU(void); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void emit_call_millicode(void *func, const s8 arg0, 32662306a36Sopenharmony_ci const s8 arg1, u8 opcode, struct hppa_jit_context *ctx) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci u32 func_addr; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci emit_hppa_copy(arg0, HPPA_REG_ARG0, ctx); 33162306a36Sopenharmony_ci emit_hppa_copy(arg1, HPPA_REG_ARG1, ctx); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* libcgcc overwrites HPPA_REG_RET0/1, save temp. in dest. */ 33462306a36Sopenharmony_ci if (arg0 != HPPA_REG_RET1) 33562306a36Sopenharmony_ci bpf_save_R0(ctx); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci func_addr = (uintptr_t) dereference_function_descriptor(func); 33862306a36Sopenharmony_ci emit(hppa_ldil(func_addr, HPPA_REG_R31), ctx); 33962306a36Sopenharmony_ci /* skip the following be_l instruction if divisor is zero. */ 34062306a36Sopenharmony_ci if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) { 34162306a36Sopenharmony_ci if (BPF_OP(opcode) == BPF_DIV) 34262306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET1, ctx); 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET1, ctx); 34562306a36Sopenharmony_ci emit(hppa_or_cond(HPPA_REG_ARG1, HPPA_REG_ZERO, 1, 0, HPPA_REG_ZERO), ctx); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci /* Note: millicode functions use r31 as return pointer instead of rp */ 34862306a36Sopenharmony_ci emit(hppa_be_l(im11(func_addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx); 34962306a36Sopenharmony_ci emit(hppa_nop(), ctx); /* this nop is needed here for delay slot */ 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Note: millicode functions return result in RET1, not RET0 */ 35262306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_RET1, arg0, ctx); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* restore HPPA_REG_RET0/1, temp. save in dest. */ 35562306a36Sopenharmony_ci if (arg0 != HPPA_REG_RET1) 35662306a36Sopenharmony_ci bpf_restore_R0(ctx); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void emit_call_libgcc_ll(void *func, const s8 *arg0, 36062306a36Sopenharmony_ci const s8 *arg1, u8 opcode, struct hppa_jit_context *ctx) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci u32 func_addr; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci emit_hppa_copy(lo(arg0), HPPA_REG_ARG0, ctx); 36562306a36Sopenharmony_ci emit_hppa_copy(hi(arg0), HPPA_REG_ARG1, ctx); 36662306a36Sopenharmony_ci emit_hppa_copy(lo(arg1), HPPA_REG_ARG2, ctx); 36762306a36Sopenharmony_ci emit_hppa_copy(hi(arg1), HPPA_REG_ARG3, ctx); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* libcgcc overwrites HPPA_REG_RET0/_RET1, so keep copy of R0 on stack */ 37062306a36Sopenharmony_ci if (hi(arg0) != HPPA_REG_RET0) 37162306a36Sopenharmony_ci bpf_save_R0(ctx); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* prepare stack */ 37462306a36Sopenharmony_ci emit(hppa_ldo(2 * FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci func_addr = (uintptr_t) dereference_function_descriptor(func); 37762306a36Sopenharmony_ci emit(hppa_ldil(func_addr, HPPA_REG_R31), ctx); 37862306a36Sopenharmony_ci /* zero out the following be_l instruction if divisor is 0 (and set default values) */ 37962306a36Sopenharmony_ci if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) { 38062306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET0, ctx); 38162306a36Sopenharmony_ci if (BPF_OP(opcode) == BPF_DIV) 38262306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET1, ctx); 38362306a36Sopenharmony_ci else 38462306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET1, ctx); 38562306a36Sopenharmony_ci emit(hppa_or_cond(HPPA_REG_ARG2, HPPA_REG_ARG3, 1, 0, HPPA_REG_ZERO), ctx); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci emit(hppa_be_l(im11(func_addr) >> 2, HPPA_REG_R31, EXEC_NEXT_INSTR), ctx); 38862306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_R31, HPPA_REG_RP, ctx); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* restore stack */ 39162306a36Sopenharmony_ci emit(hppa_ldo(-2 * FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_RET0, hi(arg0), ctx); 39462306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_RET1, lo(arg0), ctx); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* restore HPPA_REG_RET0/_RET1 */ 39762306a36Sopenharmony_ci if (hi(arg0) != HPPA_REG_RET0) 39862306a36Sopenharmony_ci bpf_restore_R0(ctx); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void emit_jump(s32 paoff, bool force_far, 40262306a36Sopenharmony_ci struct hppa_jit_context *ctx) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci unsigned long pc, addr; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Note: allocate 2 instructions for jumps if force_far is set. */ 40762306a36Sopenharmony_ci if (relative_bits_ok(paoff - HPPA_BRANCH_DISPLACEMENT, 17)) { 40862306a36Sopenharmony_ci /* use BL,short branch followed by nop() */ 40962306a36Sopenharmony_ci emit(hppa_bl(paoff - HPPA_BRANCH_DISPLACEMENT, HPPA_REG_ZERO), ctx); 41062306a36Sopenharmony_ci if (force_far) 41162306a36Sopenharmony_ci emit(hppa_nop(), ctx); 41262306a36Sopenharmony_ci return; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci pc = (uintptr_t) &ctx->insns[ctx->ninsns]; 41662306a36Sopenharmony_ci addr = pc + (paoff * HPPA_INSN_SIZE); 41762306a36Sopenharmony_ci emit(hppa_ldil(addr, HPPA_REG_R31), ctx); 41862306a36Sopenharmony_ci emit(hppa_be_l(im11(addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx); // be,l,n addr(sr4,r31), %sr0, %r31 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void emit_alu_i64(const s8 *dst, s32 imm, 42262306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 op) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 42562306a36Sopenharmony_ci const s8 *rd; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (0 && op == BPF_MOV) 42862306a36Sopenharmony_ci rd = bpf_get_reg64_ref(dst, tmp1, false, ctx); 42962306a36Sopenharmony_ci else 43062306a36Sopenharmony_ci rd = bpf_get_reg64(dst, tmp1, ctx); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* dst = dst OP imm */ 43362306a36Sopenharmony_ci switch (op) { 43462306a36Sopenharmony_ci case BPF_MOV: 43562306a36Sopenharmony_ci emit_imm32(rd, imm, ctx); 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci case BPF_AND: 43862306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 43962306a36Sopenharmony_ci emit(hppa_and(lo(rd), HPPA_REG_T0, lo(rd)), ctx); 44062306a36Sopenharmony_ci if (imm >= 0) 44162306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci case BPF_OR: 44462306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 44562306a36Sopenharmony_ci emit(hppa_or(lo(rd), HPPA_REG_T0, lo(rd)), ctx); 44662306a36Sopenharmony_ci if (imm < 0) 44762306a36Sopenharmony_ci emit_imm(hi(rd), -1, ctx); 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case BPF_XOR: 45062306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 45162306a36Sopenharmony_ci emit_hppa_xor(lo(rd), HPPA_REG_T0, lo(rd), ctx); 45262306a36Sopenharmony_ci if (imm < 0) { 45362306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, -1, ctx); 45462306a36Sopenharmony_ci emit_hppa_xor(hi(rd), HPPA_REG_T0, hi(rd), ctx); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci case BPF_LSH: 45862306a36Sopenharmony_ci if (imm == 0) 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci if (imm > 32) { 46162306a36Sopenharmony_ci imm -= 32; 46262306a36Sopenharmony_ci emit(hppa_zdep(lo(rd), imm, imm, hi(rd)), ctx); 46362306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, lo(rd), ctx); 46462306a36Sopenharmony_ci } else if (imm == 32) { 46562306a36Sopenharmony_ci emit_hppa_copy(lo(rd), hi(rd), ctx); 46662306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, lo(rd), ctx); 46762306a36Sopenharmony_ci } else { 46862306a36Sopenharmony_ci emit(hppa_shd(hi(rd), lo(rd), 32 - imm, hi(rd)), ctx); 46962306a36Sopenharmony_ci emit(hppa_zdep(lo(rd), imm, imm, lo(rd)), ctx); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case BPF_RSH: 47362306a36Sopenharmony_ci if (imm == 0) 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci if (imm > 32) { 47662306a36Sopenharmony_ci imm -= 32; 47762306a36Sopenharmony_ci emit(hppa_shr(hi(rd), imm, lo(rd)), ctx); 47862306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 47962306a36Sopenharmony_ci } else if (imm == 32) { 48062306a36Sopenharmony_ci emit_hppa_copy(hi(rd), lo(rd), ctx); 48162306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci emit(hppa_shrpw(hi(rd), lo(rd), imm, lo(rd)), ctx); 48462306a36Sopenharmony_ci emit(hppa_shr(hi(rd), imm, hi(rd)), ctx); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case BPF_ARSH: 48862306a36Sopenharmony_ci if (imm == 0) 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci if (imm > 32) { 49162306a36Sopenharmony_ci imm -= 32; 49262306a36Sopenharmony_ci emit(hppa_extrws(hi(rd), 31 - imm, imm, lo(rd)), ctx); 49362306a36Sopenharmony_ci emit(hppa_extrws(hi(rd), 0, 31, hi(rd)), ctx); 49462306a36Sopenharmony_ci } else if (imm == 32) { 49562306a36Sopenharmony_ci emit_hppa_copy(hi(rd), lo(rd), ctx); 49662306a36Sopenharmony_ci emit(hppa_extrws(hi(rd), 0, 31, hi(rd)), ctx); 49762306a36Sopenharmony_ci } else { 49862306a36Sopenharmony_ci emit(hppa_shrpw(hi(rd), lo(rd), imm, lo(rd)), ctx); 49962306a36Sopenharmony_ci emit(hppa_extrws(hi(rd), 31 - imm, imm, hi(rd)), ctx); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci default: 50362306a36Sopenharmony_ci WARN_ON(1); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void emit_alu_i32(const s8 *dst, s32 imm, 51062306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 op) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 51362306a36Sopenharmony_ci const s8 *rd = bpf_get_reg32(dst, tmp1, ctx); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (op == BPF_MOV) 51662306a36Sopenharmony_ci rd = bpf_get_reg32_ref(dst, tmp1, ctx); 51762306a36Sopenharmony_ci else 51862306a36Sopenharmony_ci rd = bpf_get_reg32(dst, tmp1, ctx); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* dst = dst OP imm */ 52162306a36Sopenharmony_ci switch (op) { 52262306a36Sopenharmony_ci case BPF_MOV: 52362306a36Sopenharmony_ci emit_imm(lo(rd), imm, ctx); 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci case BPF_ADD: 52662306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 52762306a36Sopenharmony_ci emit(hppa_add(lo(rd), HPPA_REG_T0, lo(rd)), ctx); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci case BPF_SUB: 53062306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 53162306a36Sopenharmony_ci emit(hppa_sub(lo(rd), HPPA_REG_T0, lo(rd)), ctx); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci case BPF_AND: 53462306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 53562306a36Sopenharmony_ci emit(hppa_and(lo(rd), HPPA_REG_T0, lo(rd)), ctx); 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci case BPF_OR: 53862306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 53962306a36Sopenharmony_ci emit(hppa_or(lo(rd), HPPA_REG_T0, lo(rd)), ctx); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case BPF_XOR: 54262306a36Sopenharmony_ci emit_imm(HPPA_REG_T0, imm, ctx); 54362306a36Sopenharmony_ci emit_hppa_xor(lo(rd), HPPA_REG_T0, lo(rd), ctx); 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci case BPF_LSH: 54662306a36Sopenharmony_ci if (imm != 0) 54762306a36Sopenharmony_ci emit(hppa_zdep(lo(rd), imm, imm, lo(rd)), ctx); 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case BPF_RSH: 55062306a36Sopenharmony_ci if (imm != 0) 55162306a36Sopenharmony_ci emit(hppa_shr(lo(rd), imm, lo(rd)), ctx); 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case BPF_ARSH: 55462306a36Sopenharmony_ci if (imm != 0) 55562306a36Sopenharmony_ci emit(hppa_extrws(lo(rd), 31 - imm, imm, lo(rd)), ctx); 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci default: 55862306a36Sopenharmony_ci WARN_ON(1); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci bpf_put_reg32(dst, rd, ctx); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void emit_alu_r64(const s8 *dst, const s8 *src, 56562306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 op) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 56862306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 56962306a36Sopenharmony_ci const s8 *rd; 57062306a36Sopenharmony_ci const s8 *rs = bpf_get_reg64(src, tmp2, ctx); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (op == BPF_MOV) 57362306a36Sopenharmony_ci rd = bpf_get_reg64_ref(dst, tmp1, false, ctx); 57462306a36Sopenharmony_ci else 57562306a36Sopenharmony_ci rd = bpf_get_reg64(dst, tmp1, ctx); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* dst = dst OP src */ 57862306a36Sopenharmony_ci switch (op) { 57962306a36Sopenharmony_ci case BPF_MOV: 58062306a36Sopenharmony_ci emit_hppa_copy(lo(rs), lo(rd), ctx); 58162306a36Sopenharmony_ci emit_hppa_copy(hi(rs), hi(rd), ctx); 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci case BPF_ADD: 58462306a36Sopenharmony_ci emit(hppa_add(lo(rd), lo(rs), lo(rd)), ctx); 58562306a36Sopenharmony_ci emit(hppa_addc(hi(rd), hi(rs), hi(rd)), ctx); 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci case BPF_SUB: 58862306a36Sopenharmony_ci emit(hppa_sub(lo(rd), lo(rs), lo(rd)), ctx); 58962306a36Sopenharmony_ci emit(hppa_subb(hi(rd), hi(rs), hi(rd)), ctx); 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci case BPF_AND: 59262306a36Sopenharmony_ci emit(hppa_and(lo(rd), lo(rs), lo(rd)), ctx); 59362306a36Sopenharmony_ci emit(hppa_and(hi(rd), hi(rs), hi(rd)), ctx); 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci case BPF_OR: 59662306a36Sopenharmony_ci emit(hppa_or(lo(rd), lo(rs), lo(rd)), ctx); 59762306a36Sopenharmony_ci emit(hppa_or(hi(rd), hi(rs), hi(rd)), ctx); 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci case BPF_XOR: 60062306a36Sopenharmony_ci emit_hppa_xor(lo(rd), lo(rs), lo(rd), ctx); 60162306a36Sopenharmony_ci emit_hppa_xor(hi(rd), hi(rs), hi(rd), ctx); 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci case BPF_MUL: 60462306a36Sopenharmony_ci emit_call_libgcc_ll(__muldi3, rd, rs, op, ctx); 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case BPF_DIV: 60762306a36Sopenharmony_ci emit_call_libgcc_ll(&hppa_div64, rd, rs, op, ctx); 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case BPF_MOD: 61062306a36Sopenharmony_ci emit_call_libgcc_ll(&hppa_div64_rem, rd, rs, op, ctx); 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case BPF_LSH: 61362306a36Sopenharmony_ci emit_call_libgcc_ll(__ashldi3, rd, rs, op, ctx); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case BPF_RSH: 61662306a36Sopenharmony_ci emit_call_libgcc_ll(__lshrdi3, rd, rs, op, ctx); 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case BPF_ARSH: 61962306a36Sopenharmony_ci emit_call_libgcc_ll(__ashrdi3, rd, rs, op, ctx); 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci case BPF_NEG: 62262306a36Sopenharmony_ci emit(hppa_sub(HPPA_REG_ZERO, lo(rd), lo(rd)), ctx); 62362306a36Sopenharmony_ci emit(hppa_subb(HPPA_REG_ZERO, hi(rd), hi(rd)), ctx); 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci default: 62662306a36Sopenharmony_ci WARN_ON(1); 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic void emit_alu_r32(const s8 *dst, const s8 *src, 63362306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 op) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 63662306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 63762306a36Sopenharmony_ci const s8 *rd; 63862306a36Sopenharmony_ci const s8 *rs = bpf_get_reg32(src, tmp2, ctx); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (op == BPF_MOV) 64162306a36Sopenharmony_ci rd = bpf_get_reg32_ref(dst, tmp1, ctx); 64262306a36Sopenharmony_ci else 64362306a36Sopenharmony_ci rd = bpf_get_reg32(dst, tmp1, ctx); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* dst = dst OP src */ 64662306a36Sopenharmony_ci switch (op) { 64762306a36Sopenharmony_ci case BPF_MOV: 64862306a36Sopenharmony_ci emit_hppa_copy(lo(rs), lo(rd), ctx); 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci case BPF_ADD: 65162306a36Sopenharmony_ci emit(hppa_add(lo(rd), lo(rs), lo(rd)), ctx); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case BPF_SUB: 65462306a36Sopenharmony_ci emit(hppa_sub(lo(rd), lo(rs), lo(rd)), ctx); 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci case BPF_AND: 65762306a36Sopenharmony_ci emit(hppa_and(lo(rd), lo(rs), lo(rd)), ctx); 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci case BPF_OR: 66062306a36Sopenharmony_ci emit(hppa_or(lo(rd), lo(rs), lo(rd)), ctx); 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci case BPF_XOR: 66362306a36Sopenharmony_ci emit_hppa_xor(lo(rd), lo(rs), lo(rd), ctx); 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci case BPF_MUL: 66662306a36Sopenharmony_ci emit_call_millicode($$mulI, lo(rd), lo(rs), op, ctx); 66762306a36Sopenharmony_ci break; 66862306a36Sopenharmony_ci case BPF_DIV: 66962306a36Sopenharmony_ci emit_call_millicode($$divU, lo(rd), lo(rs), op, ctx); 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci case BPF_MOD: 67262306a36Sopenharmony_ci emit_call_millicode($$remU, lo(rd), lo(rs), op, ctx); 67362306a36Sopenharmony_ci break; 67462306a36Sopenharmony_ci case BPF_LSH: 67562306a36Sopenharmony_ci emit(hppa_subi(0x1f, lo(rs), HPPA_REG_T0), ctx); 67662306a36Sopenharmony_ci emit(hppa_mtsar(HPPA_REG_T0), ctx); 67762306a36Sopenharmony_ci emit(hppa_depwz_sar(lo(rd), lo(rd)), ctx); 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci case BPF_RSH: 68062306a36Sopenharmony_ci emit(hppa_mtsar(lo(rs)), ctx); 68162306a36Sopenharmony_ci emit(hppa_shrpw_sar(lo(rd), lo(rd)), ctx); 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci case BPF_ARSH: /* sign extending arithmetic shift right */ 68462306a36Sopenharmony_ci // emit(hppa_beq(lo(rs), HPPA_REG_ZERO, 2), ctx); 68562306a36Sopenharmony_ci emit(hppa_subi(0x1f, lo(rs), HPPA_REG_T0), ctx); 68662306a36Sopenharmony_ci emit(hppa_mtsar(HPPA_REG_T0), ctx); 68762306a36Sopenharmony_ci emit(hppa_extrws_sar(lo(rd), lo(rd)), ctx); 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci case BPF_NEG: 69062306a36Sopenharmony_ci emit(hppa_sub(HPPA_REG_ZERO, lo(rd), lo(rd)), ctx); // sub r0,rd,rd 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci default: 69362306a36Sopenharmony_ci WARN_ON(1); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci bpf_put_reg32(dst, rd, ctx); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int emit_branch_r64(const s8 *src1, const s8 *src2, s32 paoff, 70062306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 op) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci int e, s = ctx->ninsns; 70362306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 70462306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci const s8 *rs1 = bpf_get_reg64(src1, tmp1, ctx); 70762306a36Sopenharmony_ci const s8 *rs2 = bpf_get_reg64(src2, tmp2, ctx); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* 71062306a36Sopenharmony_ci * NO_JUMP skips over the rest of the instructions and the 71162306a36Sopenharmony_ci * emit_jump, meaning the BPF branch is not taken. 71262306a36Sopenharmony_ci * JUMP skips directly to the emit_jump, meaning 71362306a36Sopenharmony_ci * the BPF branch is taken. 71462306a36Sopenharmony_ci * 71562306a36Sopenharmony_ci * The fallthrough case results in the BPF branch being taken. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci#define NO_JUMP(idx) (2 + (idx) - 1) 71862306a36Sopenharmony_ci#define JUMP(idx) (0 + (idx) - 1) 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci switch (op) { 72162306a36Sopenharmony_ci case BPF_JEQ: 72262306a36Sopenharmony_ci emit(hppa_bne(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 72362306a36Sopenharmony_ci emit(hppa_bne(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 72462306a36Sopenharmony_ci break; 72562306a36Sopenharmony_ci case BPF_JGT: 72662306a36Sopenharmony_ci emit(hppa_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx); 72762306a36Sopenharmony_ci emit(hppa_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 72862306a36Sopenharmony_ci emit(hppa_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci case BPF_JLT: 73162306a36Sopenharmony_ci emit(hppa_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx); 73262306a36Sopenharmony_ci emit(hppa_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 73362306a36Sopenharmony_ci emit(hppa_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 73462306a36Sopenharmony_ci break; 73562306a36Sopenharmony_ci case BPF_JGE: 73662306a36Sopenharmony_ci emit(hppa_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx); 73762306a36Sopenharmony_ci emit(hppa_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 73862306a36Sopenharmony_ci emit(hppa_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci case BPF_JLE: 74162306a36Sopenharmony_ci emit(hppa_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx); 74262306a36Sopenharmony_ci emit(hppa_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 74362306a36Sopenharmony_ci emit(hppa_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case BPF_JNE: 74662306a36Sopenharmony_ci emit(hppa_bne(hi(rs1), hi(rs2), JUMP(1)), ctx); 74762306a36Sopenharmony_ci emit(hppa_beq(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci case BPF_JSGT: 75062306a36Sopenharmony_ci emit(hppa_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx); 75162306a36Sopenharmony_ci emit(hppa_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 75262306a36Sopenharmony_ci emit(hppa_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci case BPF_JSLT: 75562306a36Sopenharmony_ci emit(hppa_blt(hi(rs1), hi(rs2), JUMP(2)), ctx); 75662306a36Sopenharmony_ci emit(hppa_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 75762306a36Sopenharmony_ci emit(hppa_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case BPF_JSGE: 76062306a36Sopenharmony_ci emit(hppa_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx); 76162306a36Sopenharmony_ci emit(hppa_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 76262306a36Sopenharmony_ci emit(hppa_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci case BPF_JSLE: 76562306a36Sopenharmony_ci emit(hppa_blt(hi(rs1), hi(rs2), JUMP(2)), ctx); 76662306a36Sopenharmony_ci emit(hppa_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx); 76762306a36Sopenharmony_ci emit(hppa_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx); 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci case BPF_JSET: 77062306a36Sopenharmony_ci emit(hppa_and(hi(rs1), hi(rs2), HPPA_REG_T0), ctx); 77162306a36Sopenharmony_ci emit(hppa_and(lo(rs1), lo(rs2), HPPA_REG_T1), ctx); 77262306a36Sopenharmony_ci emit(hppa_bne(HPPA_REG_T0, HPPA_REG_ZERO, JUMP(1)), ctx); 77362306a36Sopenharmony_ci emit(hppa_beq(HPPA_REG_T1, HPPA_REG_ZERO, NO_JUMP(0)), ctx); 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci default: 77662306a36Sopenharmony_ci WARN_ON(1); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci#undef NO_JUMP 78062306a36Sopenharmony_ci#undef JUMP 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci e = ctx->ninsns; 78362306a36Sopenharmony_ci /* Adjust for extra insns. */ 78462306a36Sopenharmony_ci paoff -= (e - s); 78562306a36Sopenharmony_ci emit_jump(paoff, true, ctx); 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int emit_bcc(u8 op, u8 rd, u8 rs, int paoff, struct hppa_jit_context *ctx) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci int e, s; 79262306a36Sopenharmony_ci bool far = false; 79362306a36Sopenharmony_ci int off; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (op == BPF_JSET) { 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * BPF_JSET is a special case: it has no inverse so we always 79862306a36Sopenharmony_ci * treat it as a far branch. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci emit(hppa_and(rd, rs, HPPA_REG_T0), ctx); 80162306a36Sopenharmony_ci paoff -= 1; /* reduce offset due to hppa_and() above */ 80262306a36Sopenharmony_ci rd = HPPA_REG_T0; 80362306a36Sopenharmony_ci rs = HPPA_REG_ZERO; 80462306a36Sopenharmony_ci op = BPF_JNE; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci s = ctx->ninsns; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (!relative_bits_ok(paoff - HPPA_BRANCH_DISPLACEMENT, 12)) { 81062306a36Sopenharmony_ci op = invert_bpf_cond(op); 81162306a36Sopenharmony_ci far = true; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* 81562306a36Sopenharmony_ci * For a far branch, the condition is negated and we jump over the 81662306a36Sopenharmony_ci * branch itself, and the three instructions from emit_jump. 81762306a36Sopenharmony_ci * For a near branch, just use paoff. 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci off = far ? (HPPA_BRANCH_DISPLACEMENT - 1) : paoff - HPPA_BRANCH_DISPLACEMENT; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci switch (op) { 82262306a36Sopenharmony_ci /* IF (dst COND src) JUMP off */ 82362306a36Sopenharmony_ci case BPF_JEQ: 82462306a36Sopenharmony_ci emit(hppa_beq(rd, rs, off), ctx); 82562306a36Sopenharmony_ci break; 82662306a36Sopenharmony_ci case BPF_JGT: 82762306a36Sopenharmony_ci emit(hppa_bgtu(rd, rs, off), ctx); 82862306a36Sopenharmony_ci break; 82962306a36Sopenharmony_ci case BPF_JLT: 83062306a36Sopenharmony_ci emit(hppa_bltu(rd, rs, off), ctx); 83162306a36Sopenharmony_ci break; 83262306a36Sopenharmony_ci case BPF_JGE: 83362306a36Sopenharmony_ci emit(hppa_bgeu(rd, rs, off), ctx); 83462306a36Sopenharmony_ci break; 83562306a36Sopenharmony_ci case BPF_JLE: 83662306a36Sopenharmony_ci emit(hppa_bleu(rd, rs, off), ctx); 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci case BPF_JNE: 83962306a36Sopenharmony_ci emit(hppa_bne(rd, rs, off), ctx); 84062306a36Sopenharmony_ci break; 84162306a36Sopenharmony_ci case BPF_JSGT: 84262306a36Sopenharmony_ci emit(hppa_bgt(rd, rs, off), ctx); 84362306a36Sopenharmony_ci break; 84462306a36Sopenharmony_ci case BPF_JSLT: 84562306a36Sopenharmony_ci emit(hppa_blt(rd, rs, off), ctx); 84662306a36Sopenharmony_ci break; 84762306a36Sopenharmony_ci case BPF_JSGE: 84862306a36Sopenharmony_ci emit(hppa_bge(rd, rs, off), ctx); 84962306a36Sopenharmony_ci break; 85062306a36Sopenharmony_ci case BPF_JSLE: 85162306a36Sopenharmony_ci emit(hppa_ble(rd, rs, off), ctx); 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci default: 85462306a36Sopenharmony_ci WARN_ON(1); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (far) { 85862306a36Sopenharmony_ci e = ctx->ninsns; 85962306a36Sopenharmony_ci /* Adjust for extra insns. */ 86062306a36Sopenharmony_ci paoff -= (e - s); 86162306a36Sopenharmony_ci emit_jump(paoff, true, ctx); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic int emit_branch_r32(const s8 *src1, const s8 *src2, s32 paoff, 86762306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 op) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci int e, s = ctx->ninsns; 87062306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 87162306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci const s8 *rs1 = bpf_get_reg32(src1, tmp1, ctx); 87462306a36Sopenharmony_ci const s8 *rs2 = bpf_get_reg32(src2, tmp2, ctx); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci e = ctx->ninsns; 87762306a36Sopenharmony_ci /* Adjust for extra insns. */ 87862306a36Sopenharmony_ci paoff -= (e - s); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (emit_bcc(op, lo(rs1), lo(rs2), paoff, ctx)) 88162306a36Sopenharmony_ci return -1; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic void emit_call(bool fixed, u64 addr, struct hppa_jit_context *ctx) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci const s8 *tmp = regmap[TMP_REG_1]; 88962306a36Sopenharmony_ci const s8 *r0 = regmap[BPF_REG_0]; 89062306a36Sopenharmony_ci const s8 *reg; 89162306a36Sopenharmony_ci const int offset_sp = 2 * STACK_ALIGN; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* prepare stack */ 89462306a36Sopenharmony_ci emit(hppa_ldo(offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* load R1 & R2 in registers, R3-R5 to stack. */ 89762306a36Sopenharmony_ci reg = bpf_get_reg64_offset(regmap[BPF_REG_5], tmp, offset_sp, ctx); 89862306a36Sopenharmony_ci emit(hppa_stw(hi(reg), -0x48, HPPA_REG_SP), ctx); 89962306a36Sopenharmony_ci emit(hppa_stw(lo(reg), -0x44, HPPA_REG_SP), ctx); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci reg = bpf_get_reg64_offset(regmap[BPF_REG_4], tmp, offset_sp, ctx); 90262306a36Sopenharmony_ci emit(hppa_stw(hi(reg), -0x40, HPPA_REG_SP), ctx); 90362306a36Sopenharmony_ci emit(hppa_stw(lo(reg), -0x3c, HPPA_REG_SP), ctx); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci reg = bpf_get_reg64_offset(regmap[BPF_REG_3], tmp, offset_sp, ctx); 90662306a36Sopenharmony_ci emit(hppa_stw(hi(reg), -0x38, HPPA_REG_SP), ctx); 90762306a36Sopenharmony_ci emit(hppa_stw(lo(reg), -0x34, HPPA_REG_SP), ctx); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci reg = bpf_get_reg64_offset(regmap[BPF_REG_2], tmp, offset_sp, ctx); 91062306a36Sopenharmony_ci emit_hppa_copy(hi(reg), HPPA_REG_ARG3, ctx); 91162306a36Sopenharmony_ci emit_hppa_copy(lo(reg), HPPA_REG_ARG2, ctx); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci reg = bpf_get_reg64_offset(regmap[BPF_REG_1], tmp, offset_sp, ctx); 91462306a36Sopenharmony_ci emit_hppa_copy(hi(reg), HPPA_REG_ARG1, ctx); 91562306a36Sopenharmony_ci emit_hppa_copy(lo(reg), HPPA_REG_ARG0, ctx); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* backup TCC */ 91862306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, HPPA_REG_TCC)) 91962306a36Sopenharmony_ci emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_SAVED), ctx); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* 92262306a36Sopenharmony_ci * Use ldil() to load absolute address. Don't use emit_imm as the 92362306a36Sopenharmony_ci * number of emitted instructions should not depend on the value of 92462306a36Sopenharmony_ci * addr. 92562306a36Sopenharmony_ci */ 92662306a36Sopenharmony_ci emit(hppa_ldil(addr, HPPA_REG_R31), ctx); 92762306a36Sopenharmony_ci emit(hppa_be_l(im11(addr) >> 2, HPPA_REG_R31, EXEC_NEXT_INSTR), ctx); 92862306a36Sopenharmony_ci /* set return address in delay slot */ 92962306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_R31, HPPA_REG_RP, ctx); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* restore TCC */ 93262306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, HPPA_REG_TCC)) 93362306a36Sopenharmony_ci emit(hppa_copy(HPPA_REG_TCC_SAVED, HPPA_REG_TCC), ctx); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* restore stack */ 93662306a36Sopenharmony_ci emit(hppa_ldo(-offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* set return value. */ 93962306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_RET0, hi(r0), ctx); 94062306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_RET1, lo(r0), ctx); 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic int emit_bpf_tail_call(int insn, struct hppa_jit_context *ctx) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci /* 94662306a36Sopenharmony_ci * R1 -> &ctx 94762306a36Sopenharmony_ci * R2 -> &array 94862306a36Sopenharmony_ci * R3 -> index 94962306a36Sopenharmony_ci */ 95062306a36Sopenharmony_ci int off; 95162306a36Sopenharmony_ci const s8 *arr_reg = regmap[BPF_REG_2]; 95262306a36Sopenharmony_ci const s8 *idx_reg = regmap[BPF_REG_3]; 95362306a36Sopenharmony_ci struct bpf_array bpfa; 95462306a36Sopenharmony_ci struct bpf_prog bpfp; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* get address of TCC main exit function for error case into rp */ 95762306a36Sopenharmony_ci emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* max_entries = array->map.max_entries; */ 96062306a36Sopenharmony_ci off = offsetof(struct bpf_array, map.max_entries); 96162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(bpfa.map.max_entries) != 4); 96262306a36Sopenharmony_ci emit(hppa_ldw(off, lo(arr_reg), HPPA_REG_T1), ctx); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* 96562306a36Sopenharmony_ci * if (index >= max_entries) 96662306a36Sopenharmony_ci * goto out; 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci emit(hppa_bltu(lo(idx_reg), HPPA_REG_T1, 2 - HPPA_BRANCH_DISPLACEMENT), ctx); 96962306a36Sopenharmony_ci emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* 97262306a36Sopenharmony_ci * if (--tcc < 0) 97362306a36Sopenharmony_ci * goto out; 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_TCC); 97662306a36Sopenharmony_ci emit(hppa_ldo(-1, HPPA_REG_TCC, HPPA_REG_TCC), ctx); 97762306a36Sopenharmony_ci emit(hppa_bge(HPPA_REG_TCC, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx); 97862306a36Sopenharmony_ci emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* 98162306a36Sopenharmony_ci * prog = array->ptrs[index]; 98262306a36Sopenharmony_ci * if (!prog) 98362306a36Sopenharmony_ci * goto out; 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(bpfa.ptrs[0]) != 4); 98662306a36Sopenharmony_ci emit(hppa_sh2add(lo(idx_reg), lo(arr_reg), HPPA_REG_T0), ctx); 98762306a36Sopenharmony_ci off = offsetof(struct bpf_array, ptrs); 98862306a36Sopenharmony_ci BUILD_BUG_ON(!relative_bits_ok(off, 11)); 98962306a36Sopenharmony_ci emit(hppa_ldw(off, HPPA_REG_T0, HPPA_REG_T0), ctx); 99062306a36Sopenharmony_ci emit(hppa_bne(HPPA_REG_T0, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx); 99162306a36Sopenharmony_ci emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* 99462306a36Sopenharmony_ci * tcc = temp_tcc; 99562306a36Sopenharmony_ci * goto *(prog->bpf_func + 4); 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_ci off = offsetof(struct bpf_prog, bpf_func); 99862306a36Sopenharmony_ci BUILD_BUG_ON(!relative_bits_ok(off, 11)); 99962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(bpfp.bpf_func) != 4); 100062306a36Sopenharmony_ci emit(hppa_ldw(off, HPPA_REG_T0, HPPA_REG_T0), ctx); 100162306a36Sopenharmony_ci /* Epilogue jumps to *(t0 + 4). */ 100262306a36Sopenharmony_ci __build_epilogue(true, ctx); 100362306a36Sopenharmony_ci return 0; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic int emit_load_r64(const s8 *dst, const s8 *src, s16 off, 100762306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 size) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 101062306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 101162306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64_ref(dst, tmp1, ctx->prog->aux->verifier_zext, ctx); 101262306a36Sopenharmony_ci const s8 *rs = bpf_get_reg64(src, tmp2, ctx); 101362306a36Sopenharmony_ci s8 srcreg; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* need to calculate address since offset does not fit in 14 bits? */ 101662306a36Sopenharmony_ci if (relative_bits_ok(off, 14)) 101762306a36Sopenharmony_ci srcreg = lo(rs); 101862306a36Sopenharmony_ci else { 101962306a36Sopenharmony_ci /* need to use R1 here, since addil puts result into R1 */ 102062306a36Sopenharmony_ci srcreg = HPPA_REG_R1; 102162306a36Sopenharmony_ci emit(hppa_addil(off, lo(rs)), ctx); 102262306a36Sopenharmony_ci off = im11(off); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* LDX: dst = *(size *)(src + off) */ 102662306a36Sopenharmony_ci switch (size) { 102762306a36Sopenharmony_ci case BPF_B: 102862306a36Sopenharmony_ci emit(hppa_ldb(off + 0, srcreg, lo(rd)), ctx); 102962306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 103062306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci case BPF_H: 103362306a36Sopenharmony_ci emit(hppa_ldh(off + 0, srcreg, lo(rd)), ctx); 103462306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 103562306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 103662306a36Sopenharmony_ci break; 103762306a36Sopenharmony_ci case BPF_W: 103862306a36Sopenharmony_ci emit(hppa_ldw(off + 0, srcreg, lo(rd)), ctx); 103962306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 104062306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case BPF_DW: 104362306a36Sopenharmony_ci emit(hppa_ldw(off + 0, srcreg, hi(rd)), ctx); 104462306a36Sopenharmony_ci emit(hppa_ldw(off + 4, srcreg, lo(rd)), ctx); 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic int emit_store_r64(const s8 *dst, const s8 *src, s16 off, 105362306a36Sopenharmony_ci struct hppa_jit_context *ctx, const u8 size, 105462306a36Sopenharmony_ci const u8 mode) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 105762306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 105862306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 105962306a36Sopenharmony_ci const s8 *rs = bpf_get_reg64(src, tmp2, ctx); 106062306a36Sopenharmony_ci s8 dstreg; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* need to calculate address since offset does not fit in 14 bits? */ 106362306a36Sopenharmony_ci if (relative_bits_ok(off, 14)) 106462306a36Sopenharmony_ci dstreg = lo(rd); 106562306a36Sopenharmony_ci else { 106662306a36Sopenharmony_ci /* need to use R1 here, since addil puts result into R1 */ 106762306a36Sopenharmony_ci dstreg = HPPA_REG_R1; 106862306a36Sopenharmony_ci emit(hppa_addil(off, lo(rd)), ctx); 106962306a36Sopenharmony_ci off = im11(off); 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* ST: *(size *)(dst + off) = imm */ 107362306a36Sopenharmony_ci switch (size) { 107462306a36Sopenharmony_ci case BPF_B: 107562306a36Sopenharmony_ci emit(hppa_stb(lo(rs), off + 0, dstreg), ctx); 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci case BPF_H: 107862306a36Sopenharmony_ci emit(hppa_sth(lo(rs), off + 0, dstreg), ctx); 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci case BPF_W: 108162306a36Sopenharmony_ci emit(hppa_stw(lo(rs), off + 0, dstreg), ctx); 108262306a36Sopenharmony_ci break; 108362306a36Sopenharmony_ci case BPF_DW: 108462306a36Sopenharmony_ci emit(hppa_stw(hi(rs), off + 0, dstreg), ctx); 108562306a36Sopenharmony_ci emit(hppa_stw(lo(rs), off + 4, dstreg), ctx); 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci return 0; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic void emit_rev16(const s8 rd, struct hppa_jit_context *ctx) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci emit(hppa_extru(rd, 23, 8, HPPA_REG_T1), ctx); 109562306a36Sopenharmony_ci emit(hppa_depwz(rd, 23, 8, HPPA_REG_T1), ctx); 109662306a36Sopenharmony_ci emit(hppa_extru(HPPA_REG_T1, 31, 16, rd), ctx); 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic void emit_rev32(const s8 rs, const s8 rd, struct hppa_jit_context *ctx) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci emit(hppa_shrpw(rs, rs, 16, HPPA_REG_T1), ctx); 110262306a36Sopenharmony_ci emit(hppa_depwz(HPPA_REG_T1, 15, 8, HPPA_REG_T1), ctx); 110362306a36Sopenharmony_ci emit(hppa_shrpw(rs, HPPA_REG_T1, 8, rd), ctx); 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic void emit_zext64(const s8 *dst, struct hppa_jit_context *ctx) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci const s8 *rd; 110962306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci rd = bpf_get_reg64(dst, tmp1, ctx); 111262306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 111362306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ciint bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx, 111762306a36Sopenharmony_ci bool extra_pass) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 || 112062306a36Sopenharmony_ci BPF_CLASS(insn->code) == BPF_JMP; 112162306a36Sopenharmony_ci int s, e, paoff, i = insn - ctx->prog->insnsi; 112262306a36Sopenharmony_ci u8 code = insn->code; 112362306a36Sopenharmony_ci s16 off = insn->off; 112462306a36Sopenharmony_ci s32 imm = insn->imm; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci const s8 *dst = regmap[insn->dst_reg]; 112762306a36Sopenharmony_ci const s8 *src = regmap[insn->src_reg]; 112862306a36Sopenharmony_ci const s8 *tmp1 = regmap[TMP_REG_1]; 112962306a36Sopenharmony_ci const s8 *tmp2 = regmap[TMP_REG_2]; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (0) printk("CLASS %03d CODE %#02x ALU64:%d BPF_SIZE %#02x " 113262306a36Sopenharmony_ci "BPF_CODE %#02x src_reg %d dst_reg %d\n", 113362306a36Sopenharmony_ci BPF_CLASS(code), code, (code & BPF_ALU64) ? 1:0, BPF_SIZE(code), 113462306a36Sopenharmony_ci BPF_OP(code), insn->src_reg, insn->dst_reg); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci switch (code) { 113762306a36Sopenharmony_ci /* dst = src */ 113862306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_X: 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_X: 114162306a36Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_K: 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_X: 114462306a36Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_K: 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_X: 114762306a36Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_X: 114862306a36Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_X: 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_X: 115162306a36Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_K: 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_X: 115462306a36Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_K: 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_X: 115762306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_K: 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_X: 116062306a36Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_X: 116162306a36Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_X: 116262306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_K) { 116362306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 116462306a36Sopenharmony_ci src = tmp2; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci emit_alu_r64(dst, src, ctx, BPF_OP(code)); 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* dst = -dst */ 117062306a36Sopenharmony_ci case BPF_ALU64 | BPF_NEG: 117162306a36Sopenharmony_ci emit_alu_r64(dst, tmp2, ctx, BPF_OP(code)); 117262306a36Sopenharmony_ci break; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_K: 117562306a36Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_K: 117662306a36Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_K: 117762306a36Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_K: 117862306a36Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_K: 117962306a36Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_K: 118062306a36Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_K: 118162306a36Sopenharmony_ci emit_alu_i64(dst, imm, ctx, BPF_OP(code)); 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_X: 118562306a36Sopenharmony_ci if (imm == 1) { 118662306a36Sopenharmony_ci /* Special mov32 for zext. */ 118762306a36Sopenharmony_ci emit_zext64(dst, ctx); 118862306a36Sopenharmony_ci break; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci fallthrough; 119162306a36Sopenharmony_ci /* dst = dst OP src */ 119262306a36Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_X: 119362306a36Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_X: 119462306a36Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_X: 119562306a36Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_X: 119662306a36Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_X: 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_X: 119962306a36Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_K: 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_X: 120262306a36Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_K: 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_X: 120562306a36Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_K: 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_X: 120862306a36Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_X: 120962306a36Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_X: 121062306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_K) { 121162306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 121262306a36Sopenharmony_ci src = tmp2; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci emit_alu_r32(dst, src, ctx, BPF_OP(code)); 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci /* dst = dst OP imm */ 121862306a36Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_K: 121962306a36Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_K: 122062306a36Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_K: 122162306a36Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_K: 122262306a36Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_K: 122362306a36Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_K: 122462306a36Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_K: 122562306a36Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_K: 122662306a36Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_K: 122762306a36Sopenharmony_ci /* 122862306a36Sopenharmony_ci * mul,div,mod are handled in the BPF_X case. 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci emit_alu_i32(dst, imm, ctx, BPF_OP(code)); 123162306a36Sopenharmony_ci break; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* dst = -dst */ 123462306a36Sopenharmony_ci case BPF_ALU | BPF_NEG: 123562306a36Sopenharmony_ci /* 123662306a36Sopenharmony_ci * src is ignored---choose tmp2 as a dummy register since it 123762306a36Sopenharmony_ci * is not on the stack. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci emit_alu_r32(dst, tmp2, ctx, BPF_OP(code)); 124062306a36Sopenharmony_ci break; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* dst = BSWAP##imm(dst) */ 124362306a36Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_BE: 124462306a36Sopenharmony_ci { 124562306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci switch (imm) { 124862306a36Sopenharmony_ci case 16: 124962306a36Sopenharmony_ci /* zero-extend 16 bits into 64 bits */ 125062306a36Sopenharmony_ci emit(hppa_extru(lo(rd), 31, 16, lo(rd)), ctx); 125162306a36Sopenharmony_ci fallthrough; 125262306a36Sopenharmony_ci case 32: 125362306a36Sopenharmony_ci /* zero-extend 32 bits into 64 bits */ 125462306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 125562306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 125662306a36Sopenharmony_ci break; 125762306a36Sopenharmony_ci case 64: 125862306a36Sopenharmony_ci /* Do nothing. */ 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci default: 126162306a36Sopenharmony_ci pr_err("bpf-jit: BPF_END imm %d invalid\n", imm); 126262306a36Sopenharmony_ci return -1; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 126662306a36Sopenharmony_ci break; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_LE: 127062306a36Sopenharmony_ci { 127162306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64(dst, tmp1, ctx); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci switch (imm) { 127462306a36Sopenharmony_ci case 16: 127562306a36Sopenharmony_ci emit_rev16(lo(rd), ctx); 127662306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 127762306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci case 32: 128062306a36Sopenharmony_ci emit_rev32(lo(rd), lo(rd), ctx); 128162306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 128262306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx); 128362306a36Sopenharmony_ci break; 128462306a36Sopenharmony_ci case 64: 128562306a36Sopenharmony_ci /* Swap upper and lower halves, then each half. */ 128662306a36Sopenharmony_ci emit_hppa_copy(hi(rd), HPPA_REG_T0, ctx); 128762306a36Sopenharmony_ci emit_rev32(lo(rd), hi(rd), ctx); 128862306a36Sopenharmony_ci emit_rev32(HPPA_REG_T0, lo(rd), ctx); 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci default: 129162306a36Sopenharmony_ci pr_err("bpf-jit: BPF_END imm %d invalid\n", imm); 129262306a36Sopenharmony_ci return -1; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 129662306a36Sopenharmony_ci break; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci /* JUMP off */ 129962306a36Sopenharmony_ci case BPF_JMP | BPF_JA: 130062306a36Sopenharmony_ci paoff = hppa_offset(i, off, ctx); 130162306a36Sopenharmony_ci emit_jump(paoff, false, ctx); 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci /* function call */ 130462306a36Sopenharmony_ci case BPF_JMP | BPF_CALL: 130562306a36Sopenharmony_ci { 130662306a36Sopenharmony_ci bool fixed; 130762306a36Sopenharmony_ci int ret; 130862306a36Sopenharmony_ci u64 addr; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, &addr, 131162306a36Sopenharmony_ci &fixed); 131262306a36Sopenharmony_ci if (ret < 0) 131362306a36Sopenharmony_ci return ret; 131462306a36Sopenharmony_ci emit_call(fixed, addr, ctx); 131562306a36Sopenharmony_ci break; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci /* tail call */ 131862306a36Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: 131962306a36Sopenharmony_ci REG_SET_SEEN_ALL(ctx); 132062306a36Sopenharmony_ci if (emit_bpf_tail_call(i, ctx)) 132162306a36Sopenharmony_ci return -1; 132262306a36Sopenharmony_ci break; 132362306a36Sopenharmony_ci /* IF (dst COND imm) JUMP off */ 132462306a36Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: 132562306a36Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: 132662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: 132762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: 133062306a36Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: 133162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: 133262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: 133562306a36Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: 133662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: 133762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: 134062306a36Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: 134162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: 134262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: 134562306a36Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: 134662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: 134762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: 135062306a36Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: 135162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: 135262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: 135562306a36Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: 135662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: 135762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: 136062306a36Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: 136162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: 136262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: 136562306a36Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: 136662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: 136762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: 137062306a36Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: 137162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: 137262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: 137562306a36Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: 137662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: 137762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: 137862306a36Sopenharmony_ci paoff = hppa_offset(i, off, ctx); 137962306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_K) { 138062306a36Sopenharmony_ci s = ctx->ninsns; 138162306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 138262306a36Sopenharmony_ci src = tmp2; 138362306a36Sopenharmony_ci e = ctx->ninsns; 138462306a36Sopenharmony_ci paoff -= (e - s); 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci if (is64) 138762306a36Sopenharmony_ci emit_branch_r64(dst, src, paoff, ctx, BPF_OP(code)); 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci emit_branch_r32(dst, src, paoff, ctx, BPF_OP(code)); 139062306a36Sopenharmony_ci break; 139162306a36Sopenharmony_ci /* function return */ 139262306a36Sopenharmony_ci case BPF_JMP | BPF_EXIT: 139362306a36Sopenharmony_ci if (i == ctx->prog->len - 1) 139462306a36Sopenharmony_ci break; 139562306a36Sopenharmony_ci /* load epilogue function pointer and jump to it. */ 139662306a36Sopenharmony_ci emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx); 139762306a36Sopenharmony_ci emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx); 139862306a36Sopenharmony_ci break; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* dst = imm64 */ 140162306a36Sopenharmony_ci case BPF_LD | BPF_IMM | BPF_DW: 140262306a36Sopenharmony_ci { 140362306a36Sopenharmony_ci struct bpf_insn insn1 = insn[1]; 140462306a36Sopenharmony_ci u32 upper = insn1.imm; 140562306a36Sopenharmony_ci u32 lower = imm; 140662306a36Sopenharmony_ci const s8 *rd = bpf_get_reg64_ref(dst, tmp1, false, ctx); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (0 && bpf_pseudo_func(insn)) { 140962306a36Sopenharmony_ci WARN_ON(upper); /* we are 32-bit! */ 141062306a36Sopenharmony_ci upper = 0; 141162306a36Sopenharmony_ci lower = (uintptr_t) dereference_function_descriptor(lower); 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci emit_imm64(rd, upper, lower, ctx); 141562306a36Sopenharmony_ci bpf_put_reg64(dst, rd, ctx); 141662306a36Sopenharmony_ci return 1; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* LDX: dst = *(size *)(src + off) */ 142062306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_B: 142162306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_H: 142262306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_W: 142362306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_DW: 142462306a36Sopenharmony_ci if (emit_load_r64(dst, src, off, ctx, BPF_SIZE(code))) 142562306a36Sopenharmony_ci return -1; 142662306a36Sopenharmony_ci break; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* speculation barrier */ 142962306a36Sopenharmony_ci case BPF_ST | BPF_NOSPEC: 143062306a36Sopenharmony_ci break; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* ST: *(size *)(dst + off) = imm */ 143362306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_B: 143462306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_H: 143562306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_W: 143662306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_DW: 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_B: 143962306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_H: 144062306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_W: 144162306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_DW: 144262306a36Sopenharmony_ci if (BPF_CLASS(code) == BPF_ST) { 144362306a36Sopenharmony_ci emit_imm32(tmp2, imm, ctx); 144462306a36Sopenharmony_ci src = tmp2; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code), 144862306a36Sopenharmony_ci BPF_MODE(code))) 144962306a36Sopenharmony_ci return -1; 145062306a36Sopenharmony_ci break; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci case BPF_STX | BPF_ATOMIC | BPF_W: 145362306a36Sopenharmony_ci case BPF_STX | BPF_ATOMIC | BPF_DW: 145462306a36Sopenharmony_ci pr_info_once( 145562306a36Sopenharmony_ci "bpf-jit: not supported: atomic operation %02x ***\n", 145662306a36Sopenharmony_ci insn->imm); 145762306a36Sopenharmony_ci return -EFAULT; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci default: 146062306a36Sopenharmony_ci pr_err("bpf-jit: unknown opcode %02x\n", code); 146162306a36Sopenharmony_ci return -EINVAL; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci return 0; 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_civoid bpf_jit_build_prologue(struct hppa_jit_context *ctx) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci const s8 *tmp = regmap[TMP_REG_1]; 147062306a36Sopenharmony_ci const s8 *dst, *reg; 147162306a36Sopenharmony_ci int stack_adjust = 0; 147262306a36Sopenharmony_ci int i; 147362306a36Sopenharmony_ci unsigned long addr; 147462306a36Sopenharmony_ci int bpf_stack_adjust; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* 147762306a36Sopenharmony_ci * stack on hppa grows up, so if tail calls are used we need to 147862306a36Sopenharmony_ci * allocate the maximum stack size 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci if (REG_ALL_SEEN(ctx)) 148162306a36Sopenharmony_ci bpf_stack_adjust = MAX_BPF_STACK; 148262306a36Sopenharmony_ci else 148362306a36Sopenharmony_ci bpf_stack_adjust = ctx->prog->aux->stack_depth; 148462306a36Sopenharmony_ci bpf_stack_adjust = round_up(bpf_stack_adjust, STACK_ALIGN); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci /* make space for callee-saved registers. */ 148762306a36Sopenharmony_ci stack_adjust += NR_SAVED_REGISTERS * REG_SIZE; 148862306a36Sopenharmony_ci /* make space for BPF registers on stack. */ 148962306a36Sopenharmony_ci stack_adjust += BPF_JIT_SCRATCH_REGS * REG_SIZE; 149062306a36Sopenharmony_ci /* make space for BPF stack. */ 149162306a36Sopenharmony_ci stack_adjust += bpf_stack_adjust; 149262306a36Sopenharmony_ci /* round up for stack alignment. */ 149362306a36Sopenharmony_ci stack_adjust = round_up(stack_adjust, STACK_ALIGN); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci /* 149662306a36Sopenharmony_ci * The first instruction sets the tail-call-counter (TCC) register. 149762306a36Sopenharmony_ci * This instruction is skipped by tail calls. 149862306a36Sopenharmony_ci * Use a temporary register instead of a caller-saved register initially. 149962306a36Sopenharmony_ci */ 150062306a36Sopenharmony_ci emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC_IN_INIT), ctx); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci /* 150362306a36Sopenharmony_ci * skip all initializations when called as BPF TAIL call. 150462306a36Sopenharmony_ci */ 150562306a36Sopenharmony_ci emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_R1), ctx); 150662306a36Sopenharmony_ci emit(hppa_bne(HPPA_REG_TCC_IN_INIT, HPPA_REG_R1, ctx->prologue_len - 2 - HPPA_BRANCH_DISPLACEMENT), ctx); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* set up hppa stack frame. */ 150962306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_SP, HPPA_REG_R1, ctx); // copy sp,r1 (=prev_sp) 151062306a36Sopenharmony_ci emit(hppa_ldo(stack_adjust, HPPA_REG_SP, HPPA_REG_SP), ctx); // ldo stack_adjust(sp),sp (increase stack) 151162306a36Sopenharmony_ci emit(hppa_stw(HPPA_REG_R1, -REG_SIZE, HPPA_REG_SP), ctx); // stw prev_sp,-0x04(sp) 151262306a36Sopenharmony_ci emit(hppa_stw(HPPA_REG_RP, -0x14, HPPA_REG_SP), ctx); // stw rp,-0x14(sp) 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_T0); 151562306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_T1); 151662306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_T2); 151762306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_T3); 151862306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_T4); 151962306a36Sopenharmony_ci REG_FORCE_SEEN(ctx, HPPA_REG_T5); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* save callee-save registers. */ 152262306a36Sopenharmony_ci for (i = 3; i <= 18; i++) { 152362306a36Sopenharmony_ci if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i))) 152462306a36Sopenharmony_ci continue; 152562306a36Sopenharmony_ci emit(hppa_stw(HPPA_R(i), -REG_SIZE * (8 + (i-3)), HPPA_REG_SP), ctx); // stw ri,-save_area(sp) 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* 152962306a36Sopenharmony_ci * now really set the tail call counter (TCC) register. 153062306a36Sopenharmony_ci */ 153162306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, HPPA_REG_TCC)) 153262306a36Sopenharmony_ci emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC), ctx); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * save epilogue function pointer for outer TCC call chain. 153662306a36Sopenharmony_ci * The main TCC call stores the final RP on stack. 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_ci addr = (uintptr_t) &ctx->insns[ctx->epilogue_offset]; 153962306a36Sopenharmony_ci /* skip first two instructions of exit function, which jump to exit */ 154062306a36Sopenharmony_ci addr += 2 * HPPA_INSN_SIZE; 154162306a36Sopenharmony_ci emit(hppa_ldil(addr, HPPA_REG_T2), ctx); 154262306a36Sopenharmony_ci emit(hppa_ldo(im11(addr), HPPA_REG_T2, HPPA_REG_T2), ctx); 154362306a36Sopenharmony_ci emit(EXIT_PTR_STORE(HPPA_REG_T2), ctx); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci /* load R1 & R2 from registers, R3-R5 from stack. */ 154662306a36Sopenharmony_ci /* use HPPA_REG_R1 which holds the old stack value */ 154762306a36Sopenharmony_ci dst = regmap[BPF_REG_5]; 154862306a36Sopenharmony_ci reg = bpf_get_reg64_ref(dst, tmp, false, ctx); 154962306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) { 155062306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, hi(reg))) 155162306a36Sopenharmony_ci emit(hppa_ldw(-0x48, HPPA_REG_R1, hi(reg)), ctx); 155262306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg))) 155362306a36Sopenharmony_ci emit(hppa_ldw(-0x44, HPPA_REG_R1, lo(reg)), ctx); 155462306a36Sopenharmony_ci bpf_put_reg64(dst, tmp, ctx); 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci dst = regmap[BPF_REG_4]; 155862306a36Sopenharmony_ci reg = bpf_get_reg64_ref(dst, tmp, false, ctx); 155962306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) { 156062306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, hi(reg))) 156162306a36Sopenharmony_ci emit(hppa_ldw(-0x40, HPPA_REG_R1, hi(reg)), ctx); 156262306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg))) 156362306a36Sopenharmony_ci emit(hppa_ldw(-0x3c, HPPA_REG_R1, lo(reg)), ctx); 156462306a36Sopenharmony_ci bpf_put_reg64(dst, tmp, ctx); 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci dst = regmap[BPF_REG_3]; 156862306a36Sopenharmony_ci reg = bpf_get_reg64_ref(dst, tmp, false, ctx); 156962306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) { 157062306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, hi(reg))) 157162306a36Sopenharmony_ci emit(hppa_ldw(-0x38, HPPA_REG_R1, hi(reg)), ctx); 157262306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg))) 157362306a36Sopenharmony_ci emit(hppa_ldw(-0x34, HPPA_REG_R1, lo(reg)), ctx); 157462306a36Sopenharmony_ci bpf_put_reg64(dst, tmp, ctx); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci dst = regmap[BPF_REG_2]; 157862306a36Sopenharmony_ci reg = bpf_get_reg64_ref(dst, tmp, false, ctx); 157962306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) { 158062306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, hi(reg))) 158162306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ARG3, hi(reg), ctx); 158262306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg))) 158362306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ARG2, lo(reg), ctx); 158462306a36Sopenharmony_ci bpf_put_reg64(dst, tmp, ctx); 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci dst = regmap[BPF_REG_1]; 158862306a36Sopenharmony_ci reg = bpf_get_reg64_ref(dst, tmp, false, ctx); 158962306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) { 159062306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, hi(reg))) 159162306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ARG1, hi(reg), ctx); 159262306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg))) 159362306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ARG0, lo(reg), ctx); 159462306a36Sopenharmony_ci bpf_put_reg64(dst, tmp, ctx); 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* Set up BPF frame pointer. */ 159862306a36Sopenharmony_ci dst = regmap[BPF_REG_FP]; 159962306a36Sopenharmony_ci reg = bpf_get_reg64_ref(dst, tmp, false, ctx); 160062306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) { 160162306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, lo(reg))) 160262306a36Sopenharmony_ci emit(hppa_ldo(-REG_SIZE * (NR_SAVED_REGISTERS + BPF_JIT_SCRATCH_REGS), 160362306a36Sopenharmony_ci HPPA_REG_SP, lo(reg)), ctx); 160462306a36Sopenharmony_ci if (REG_WAS_SEEN(ctx, hi(reg))) 160562306a36Sopenharmony_ci emit_hppa_copy(HPPA_REG_ZERO, hi(reg), ctx); 160662306a36Sopenharmony_ci bpf_put_reg64(dst, tmp, ctx); 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci emit(hppa_nop(), ctx); 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_civoid bpf_jit_build_epilogue(struct hppa_jit_context *ctx) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci __build_epilogue(false, ctx); 161562306a36Sopenharmony_ci} 1616