162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common functionality for PARISC32 and PARISC64 BPF JIT compilers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2023 Helge Deller <deller@gmx.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef _BPF_JIT_H 1062306a36Sopenharmony_ci#define _BPF_JIT_H 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/bpf.h> 1362306a36Sopenharmony_ci#include <linux/filter.h> 1462306a36Sopenharmony_ci#include <asm/cacheflush.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define HPPA_JIT_DEBUG 0 1762306a36Sopenharmony_ci#define HPPA_JIT_REBOOT 0 1862306a36Sopenharmony_ci#define HPPA_JIT_DUMP 0 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define OPTIMIZE_HPPA 1 /* enable some asm optimizations */ 2162306a36Sopenharmony_ci// echo 1 > /proc/sys/net/core/bpf_jit_enable 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define HPPA_R(nr) nr /* use HPPA register #nr */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cienum { 2662306a36Sopenharmony_ci HPPA_REG_ZERO = 0, /* The constant value 0 */ 2762306a36Sopenharmony_ci HPPA_REG_R1 = 1, /* used for addil */ 2862306a36Sopenharmony_ci HPPA_REG_RP = 2, /* Return address */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci HPPA_REG_ARG7 = 19, /* ARG4-7 used in 64-bit ABI */ 3162306a36Sopenharmony_ci HPPA_REG_ARG6 = 20, 3262306a36Sopenharmony_ci HPPA_REG_ARG5 = 21, 3362306a36Sopenharmony_ci HPPA_REG_ARG4 = 22, 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci HPPA_REG_ARG3 = 23, /* ARG0-3 in 32- and 64-bit ABI */ 3662306a36Sopenharmony_ci HPPA_REG_ARG2 = 24, 3762306a36Sopenharmony_ci HPPA_REG_ARG1 = 25, 3862306a36Sopenharmony_ci HPPA_REG_ARG0 = 26, 3962306a36Sopenharmony_ci HPPA_REG_GP = 27, /* Global pointer */ 4062306a36Sopenharmony_ci HPPA_REG_RET0 = 28, /* Return value, HI in 32-bit */ 4162306a36Sopenharmony_ci HPPA_REG_RET1 = 29, /* Return value, LOW in 32-bit */ 4262306a36Sopenharmony_ci HPPA_REG_SP = 30, /* Stack pointer */ 4362306a36Sopenharmony_ci HPPA_REG_R31 = 31, 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#ifdef CONFIG_64BIT 4662306a36Sopenharmony_ci HPPA_REG_TCC = 3, 4762306a36Sopenharmony_ci HPPA_REG_TCC_SAVED = 4, 4862306a36Sopenharmony_ci HPPA_REG_TCC_IN_INIT = HPPA_REG_R31, 4962306a36Sopenharmony_ci#else 5062306a36Sopenharmony_ci HPPA_REG_TCC = 18, 5162306a36Sopenharmony_ci HPPA_REG_TCC_SAVED = 17, 5262306a36Sopenharmony_ci HPPA_REG_TCC_IN_INIT = HPPA_REG_R31, 5362306a36Sopenharmony_ci#endif 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci HPPA_REG_T0 = HPPA_REG_R1, /* Temporaries */ 5662306a36Sopenharmony_ci HPPA_REG_T1 = HPPA_REG_R31, 5762306a36Sopenharmony_ci HPPA_REG_T2 = HPPA_REG_ARG4, 5862306a36Sopenharmony_ci#ifndef CONFIG_64BIT 5962306a36Sopenharmony_ci HPPA_REG_T3 = HPPA_REG_ARG5, /* not used in 64-bit */ 6062306a36Sopenharmony_ci HPPA_REG_T4 = HPPA_REG_ARG6, 6162306a36Sopenharmony_ci HPPA_REG_T5 = HPPA_REG_ARG7, 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistruct hppa_jit_context { 6662306a36Sopenharmony_ci struct bpf_prog *prog; 6762306a36Sopenharmony_ci u32 *insns; /* HPPA insns */ 6862306a36Sopenharmony_ci int ninsns; 6962306a36Sopenharmony_ci int reg_seen_collect; 7062306a36Sopenharmony_ci int reg_seen; 7162306a36Sopenharmony_ci int body_len; 7262306a36Sopenharmony_ci int epilogue_offset; 7362306a36Sopenharmony_ci int prologue_len; 7462306a36Sopenharmony_ci int *offset; /* BPF to HPPA */ 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define REG_SET_SEEN(ctx, nr) { if (ctx->reg_seen_collect) ctx->reg_seen |= BIT(nr); } 7862306a36Sopenharmony_ci#define REG_SET_SEEN_ALL(ctx) { if (ctx->reg_seen_collect) ctx->reg_seen = -1; } 7962306a36Sopenharmony_ci#define REG_FORCE_SEEN(ctx, nr) { ctx->reg_seen |= BIT(nr); } 8062306a36Sopenharmony_ci#define REG_WAS_SEEN(ctx, nr) (ctx->reg_seen & BIT(nr)) 8162306a36Sopenharmony_ci#define REG_ALL_SEEN(ctx) (ctx->reg_seen == -1) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define HPPA_INSN_SIZE 4 /* bytes per HPPA asm instruction */ 8462306a36Sopenharmony_ci#define REG_SIZE REG_SZ /* bytes per native "long" word */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* subtract hppa displacement on branches which is .+8 */ 8762306a36Sopenharmony_ci#define HPPA_BRANCH_DISPLACEMENT 2 /* instructions */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* asm statement indicator to execute delay slot */ 9062306a36Sopenharmony_ci#define EXEC_NEXT_INSTR 0 9162306a36Sopenharmony_ci#define NOP_NEXT_INSTR 1 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define im11(val) (((u32)(val)) & 0x07ff) 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define hppa_ldil(addr, reg) \ 9662306a36Sopenharmony_ci hppa_t5_insn(0x08, reg, ((u32)(addr)) >> 11) /* ldil im21,reg */ 9762306a36Sopenharmony_ci#define hppa_addil(addr, reg) \ 9862306a36Sopenharmony_ci hppa_t5_insn(0x0a, reg, ((u32)(addr)) >> 11) /* addil im21,reg -> result in gr1 */ 9962306a36Sopenharmony_ci#define hppa_ldo(im14, reg, target) \ 10062306a36Sopenharmony_ci hppa_t1_insn(0x0d, reg, target, im14) /* ldo val14(reg),target */ 10162306a36Sopenharmony_ci#define hppa_ldi(im14, reg) \ 10262306a36Sopenharmony_ci hppa_ldo(im14, HPPA_REG_ZERO, reg) /* ldi val14,reg */ 10362306a36Sopenharmony_ci#define hppa_or(reg1, reg2, target) \ 10462306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x09, target) /* or reg1,reg2,target */ 10562306a36Sopenharmony_ci#define hppa_or_cond(reg1, reg2, cond, f, target) \ 10662306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, cond, f, 0x09, target) 10762306a36Sopenharmony_ci#define hppa_and(reg1, reg2, target) \ 10862306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x08, target) /* and reg1,reg2,target */ 10962306a36Sopenharmony_ci#define hppa_and_cond(reg1, reg2, cond, f, target) \ 11062306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, cond, f, 0x08, target) 11162306a36Sopenharmony_ci#define hppa_xor(reg1, reg2, target) \ 11262306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x0a, target) /* xor reg1,reg2,target */ 11362306a36Sopenharmony_ci#define hppa_add(reg1, reg2, target) \ 11462306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x18, target) /* add reg1,reg2,target */ 11562306a36Sopenharmony_ci#define hppa_addc(reg1, reg2, target) \ 11662306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x1c, target) /* add,c reg1,reg2,target */ 11762306a36Sopenharmony_ci#define hppa_sub(reg1, reg2, target) \ 11862306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x10, target) /* sub reg1,reg2,target */ 11962306a36Sopenharmony_ci#define hppa_subb(reg1, reg2, target) \ 12062306a36Sopenharmony_ci hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x14, target) /* sub,b reg1,reg2,target */ 12162306a36Sopenharmony_ci#define hppa_nop() \ 12262306a36Sopenharmony_ci hppa_or(0,0,0) /* nop: or 0,0,0 */ 12362306a36Sopenharmony_ci#define hppa_addi(val11, reg, target) \ 12462306a36Sopenharmony_ci hppa_t7_insn(0x2d, reg, target, val11) /* addi im11,reg,target */ 12562306a36Sopenharmony_ci#define hppa_subi(val11, reg, target) \ 12662306a36Sopenharmony_ci hppa_t7_insn(0x25, reg, target, val11) /* subi im11,reg,target */ 12762306a36Sopenharmony_ci#define hppa_copy(reg, target) \ 12862306a36Sopenharmony_ci hppa_or(reg, HPPA_REG_ZERO, target) /* copy reg,target */ 12962306a36Sopenharmony_ci#define hppa_ldw(val14, reg, target) \ 13062306a36Sopenharmony_ci hppa_t1_insn(0x12, reg, target, val14) /* ldw im14(reg),target */ 13162306a36Sopenharmony_ci#define hppa_ldb(val14, reg, target) \ 13262306a36Sopenharmony_ci hppa_t1_insn(0x10, reg, target, val14) /* ldb im14(reg),target */ 13362306a36Sopenharmony_ci#define hppa_ldh(val14, reg, target) \ 13462306a36Sopenharmony_ci hppa_t1_insn(0x11, reg, target, val14) /* ldh im14(reg),target */ 13562306a36Sopenharmony_ci#define hppa_stw(reg, val14, base) \ 13662306a36Sopenharmony_ci hppa_t1_insn(0x1a, base, reg, val14) /* stw reg,im14(base) */ 13762306a36Sopenharmony_ci#define hppa_stb(reg, val14, base) \ 13862306a36Sopenharmony_ci hppa_t1_insn(0x18, base, reg, val14) /* stb reg,im14(base) */ 13962306a36Sopenharmony_ci#define hppa_sth(reg, val14, base) \ 14062306a36Sopenharmony_ci hppa_t1_insn(0x19, base, reg, val14) /* sth reg,im14(base) */ 14162306a36Sopenharmony_ci#define hppa_stwma(reg, val14, base) \ 14262306a36Sopenharmony_ci hppa_t1_insn(0x1b, base, reg, val14) /* stw,ma reg,im14(base) */ 14362306a36Sopenharmony_ci#define hppa_bv(reg, base, nop) \ 14462306a36Sopenharmony_ci hppa_t11_insn(0x3a, base, reg, 0x06, 0, nop) /* bv(,n) reg(base) */ 14562306a36Sopenharmony_ci#define hppa_be(offset, base) \ 14662306a36Sopenharmony_ci hppa_t12_insn(0x38, base, offset, 0x00, 1) /* be,n offset(0,base) */ 14762306a36Sopenharmony_ci#define hppa_be_l(offset, base, nop) \ 14862306a36Sopenharmony_ci hppa_t12_insn(0x39, base, offset, 0x00, nop) /* ble(,nop) offset(0,base) */ 14962306a36Sopenharmony_ci#define hppa_mtctl(reg, cr) \ 15062306a36Sopenharmony_ci hppa_t21_insn(0x00, cr, reg, 0xc2, 0) /* mtctl reg,cr */ 15162306a36Sopenharmony_ci#define hppa_mtsar(reg) \ 15262306a36Sopenharmony_ci hppa_mtctl(reg, 11) /* mtsar reg */ 15362306a36Sopenharmony_ci#define hppa_zdep(r, p, len, target) \ 15462306a36Sopenharmony_ci hppa_t10_insn(0x35, target, r, 0, 2, p, len) /* zdep r,a,b,t */ 15562306a36Sopenharmony_ci#define hppa_shl(r, len, target) \ 15662306a36Sopenharmony_ci hppa_zdep(r, len, len, lo(rd)) 15762306a36Sopenharmony_ci#define hppa_depwz(r, p, len, target) \ 15862306a36Sopenharmony_ci hppa_t10_insn(0x35, target, r, 0, 3, 31-(p), 32-(len)) /* depw,z r,p,len,ret1 */ 15962306a36Sopenharmony_ci#define hppa_depwz_sar(reg, target) \ 16062306a36Sopenharmony_ci hppa_t1_insn(0x35, target, reg, 0) /* depw,z reg,sar,32,target */ 16162306a36Sopenharmony_ci#define hppa_shrpw_sar(reg, target) \ 16262306a36Sopenharmony_ci hppa_t10_insn(0x34, reg, 0, 0, 0, 0, target) /* shrpw r0,reg,sar,target */ 16362306a36Sopenharmony_ci#define hppa_shrpw(r1, r2, p, target) \ 16462306a36Sopenharmony_ci hppa_t10_insn(0x34, r2, r1, 0, 2, 31-(p), target) /* shrpw r1,r2,p,target */ 16562306a36Sopenharmony_ci#define hppa_shd(r1, r2, p, target) \ 16662306a36Sopenharmony_ci hppa_t10_insn(0x34, r2, r1, 0, 2, 31-(p), target) /* shrpw r1,r2,p,tarfer */ 16762306a36Sopenharmony_ci#define hppa_extrws_sar(reg, target) \ 16862306a36Sopenharmony_ci hppa_t10_insn(0x34, reg, target, 0, 5, 0, 0) /* extrw,s reg,sar,32,ret0 */ 16962306a36Sopenharmony_ci#define hppa_extrws(reg, p, len, target) \ 17062306a36Sopenharmony_ci hppa_t10_insn(0x34, reg, target, 0, 7, p, len) /* extrw,s reg,p,len,target */ 17162306a36Sopenharmony_ci#define hppa_extru(r, p, len, target) \ 17262306a36Sopenharmony_ci hppa_t10_insn(0x34, r, target, 0, 6, p, 32-(len)) 17362306a36Sopenharmony_ci#define hppa_shr(r, len, target) \ 17462306a36Sopenharmony_ci hppa_extru(r, 31-(len), 32-(len), target) 17562306a36Sopenharmony_ci#define hppa_bl(imm17, rp) \ 17662306a36Sopenharmony_ci hppa_t12_insn(0x3a, rp, imm17, 0x00, 1) /* bl,n target_addr,rp */ 17762306a36Sopenharmony_ci#define hppa_sh2add(r1, r2, target) \ 17862306a36Sopenharmony_ci hppa_t6_insn(0x02, r2, r1, 0, 0, 0x1a, target) /* sh2add r1,r2,target */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#define hppa_combt(r1, r2, target_addr, condition, nop) \ 18162306a36Sopenharmony_ci hppa_t11_insn(IS_ENABLED(CONFIG_64BIT) ? 0x27 : 0x20, \ 18262306a36Sopenharmony_ci r2, r1, condition, target_addr, nop) /* combt,cond,n r1,r2,addr */ 18362306a36Sopenharmony_ci#define hppa_beq(r1, r2, target_addr) \ 18462306a36Sopenharmony_ci hppa_combt(r1, r2, target_addr, 1, NOP_NEXT_INSTR) 18562306a36Sopenharmony_ci#define hppa_blt(r1, r2, target_addr) \ 18662306a36Sopenharmony_ci hppa_combt(r1, r2, target_addr, 2, NOP_NEXT_INSTR) 18762306a36Sopenharmony_ci#define hppa_ble(r1, r2, target_addr) \ 18862306a36Sopenharmony_ci hppa_combt(r1, r2, target_addr, 3, NOP_NEXT_INSTR) 18962306a36Sopenharmony_ci#define hppa_bltu(r1, r2, target_addr) \ 19062306a36Sopenharmony_ci hppa_combt(r1, r2, target_addr, 4, NOP_NEXT_INSTR) 19162306a36Sopenharmony_ci#define hppa_bleu(r1, r2, target_addr) \ 19262306a36Sopenharmony_ci hppa_combt(r1, r2, target_addr, 5, NOP_NEXT_INSTR) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define hppa_combf(r1, r2, target_addr, condition, nop) \ 19562306a36Sopenharmony_ci hppa_t11_insn(IS_ENABLED(CONFIG_64BIT) ? 0x2f : 0x22, \ 19662306a36Sopenharmony_ci r2, r1, condition, target_addr, nop) /* combf,cond,n r1,r2,addr */ 19762306a36Sopenharmony_ci#define hppa_bne(r1, r2, target_addr) \ 19862306a36Sopenharmony_ci hppa_combf(r1, r2, target_addr, 1, NOP_NEXT_INSTR) 19962306a36Sopenharmony_ci#define hppa_bge(r1, r2, target_addr) \ 20062306a36Sopenharmony_ci hppa_combf(r1, r2, target_addr, 2, NOP_NEXT_INSTR) 20162306a36Sopenharmony_ci#define hppa_bgt(r1, r2, target_addr) \ 20262306a36Sopenharmony_ci hppa_combf(r1, r2, target_addr, 3, NOP_NEXT_INSTR) 20362306a36Sopenharmony_ci#define hppa_bgeu(r1, r2, target_addr) \ 20462306a36Sopenharmony_ci hppa_combf(r1, r2, target_addr, 4, NOP_NEXT_INSTR) 20562306a36Sopenharmony_ci#define hppa_bgtu(r1, r2, target_addr) \ 20662306a36Sopenharmony_ci hppa_combf(r1, r2, target_addr, 5, NOP_NEXT_INSTR) 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* 64-bit instructions */ 20962306a36Sopenharmony_ci#ifdef CONFIG_64BIT 21062306a36Sopenharmony_ci#define hppa64_ldd_reg(reg, b, target) \ 21162306a36Sopenharmony_ci hppa_t10_insn(0x03, b, reg, 0, 0, 3<<1, target) 21262306a36Sopenharmony_ci#define hppa64_ldd_im5(im5, b, target) \ 21362306a36Sopenharmony_ci hppa_t10_insn(0x03, b, low_sign_unext(im5,5), 0, 1<<2, 3<<1, target) 21462306a36Sopenharmony_ci#define hppa64_ldd_im16(im16, b, target) \ 21562306a36Sopenharmony_ci hppa_t10_insn(0x14, b, target, 0, 0, 0, 0) | re_assemble_16(im16) 21662306a36Sopenharmony_ci#define hppa64_std_im5(src, im5, b) \ 21762306a36Sopenharmony_ci hppa_t10_insn(0x03, b, src, 0, 1<<2, 0xB<<1, low_sign_unext(im5,5)) 21862306a36Sopenharmony_ci#define hppa64_std_im16(src, im16, b) \ 21962306a36Sopenharmony_ci hppa_t10_insn(0x1c, b, src, 0, 0, 0, 0) | re_assemble_16(im16) 22062306a36Sopenharmony_ci#define hppa64_bl_long(offs22) \ 22162306a36Sopenharmony_ci hppa_t12_L_insn(0x3a, offs22, 1) 22262306a36Sopenharmony_ci#define hppa64_mtsarcm(reg) \ 22362306a36Sopenharmony_ci hppa_t21_insn(0x00, 11, reg, 0xc6, 0) 22462306a36Sopenharmony_ci#define hppa64_shrpd_sar(reg, target) \ 22562306a36Sopenharmony_ci hppa_t10_insn(0x34, reg, 0, 0, 0, 1<<4, target) 22662306a36Sopenharmony_ci#define hppa64_shladd(r1, sa, r2, target) \ 22762306a36Sopenharmony_ci hppa_t6_insn(0x02, r2, r1, 0, 0, 1<<4|1<<3|sa, target) 22862306a36Sopenharmony_ci#define hppa64_depdz_sar(reg, target) \ 22962306a36Sopenharmony_ci hppa_t21_insn(0x35, target, reg, 3<<3, 0) 23062306a36Sopenharmony_ci#define hppa_extrd_sar(reg, target, se) \ 23162306a36Sopenharmony_ci hppa_t10_insn(0x34, reg, target, 0, 0, 0, 0) | 2<<11 | (se&1)<<10 | 1<<9 | 1<<8 23262306a36Sopenharmony_ci#define hppa64_bve_l_rp(base) \ 23362306a36Sopenharmony_ci (0x3a << 26) | (base << 21) | 0xf000 23462306a36Sopenharmony_ci#define hppa64_permh_3210(r, target) \ 23562306a36Sopenharmony_ci (0x3e << 26) | (r << 21) | (r << 16) | (target) | 0x00006900 23662306a36Sopenharmony_ci#define hppa64_hshl(r, sa, target) \ 23762306a36Sopenharmony_ci (0x3e << 26) | (0 << 21) | (r << 16) | (sa << 6) | (target) | 0x00008800 23862306a36Sopenharmony_ci#define hppa64_hshr_u(r, sa, target) \ 23962306a36Sopenharmony_ci (0x3e << 26) | (r << 21) | (0 << 16) | (sa << 6) | (target) | 0x0000c800 24062306a36Sopenharmony_ci#endif 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistruct hppa_jit_data { 24362306a36Sopenharmony_ci struct bpf_binary_header *header; 24462306a36Sopenharmony_ci u8 *image; 24562306a36Sopenharmony_ci struct hppa_jit_context ctx; 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic inline void bpf_fill_ill_insns(void *area, unsigned int size) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci memset(area, 0, size); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic inline void bpf_flush_icache(void *start, void *end) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci flush_icache_range((unsigned long)start, (unsigned long)end); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* Emit a 4-byte HPPA instruction. */ 25962306a36Sopenharmony_cistatic inline void emit(const u32 insn, struct hppa_jit_context *ctx) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci if (ctx->insns) { 26262306a36Sopenharmony_ci ctx->insns[ctx->ninsns] = insn; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci ctx->ninsns++; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic inline int epilogue_offset(struct hppa_jit_context *ctx) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int to = ctx->epilogue_offset, from = ctx->ninsns; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return (to - from); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* Return -1 or inverted cond. */ 27662306a36Sopenharmony_cistatic inline int invert_bpf_cond(u8 cond) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci switch (cond) { 27962306a36Sopenharmony_ci case BPF_JEQ: 28062306a36Sopenharmony_ci return BPF_JNE; 28162306a36Sopenharmony_ci case BPF_JGT: 28262306a36Sopenharmony_ci return BPF_JLE; 28362306a36Sopenharmony_ci case BPF_JLT: 28462306a36Sopenharmony_ci return BPF_JGE; 28562306a36Sopenharmony_ci case BPF_JGE: 28662306a36Sopenharmony_ci return BPF_JLT; 28762306a36Sopenharmony_ci case BPF_JLE: 28862306a36Sopenharmony_ci return BPF_JGT; 28962306a36Sopenharmony_ci case BPF_JNE: 29062306a36Sopenharmony_ci return BPF_JEQ; 29162306a36Sopenharmony_ci case BPF_JSGT: 29262306a36Sopenharmony_ci return BPF_JSLE; 29362306a36Sopenharmony_ci case BPF_JSLT: 29462306a36Sopenharmony_ci return BPF_JSGE; 29562306a36Sopenharmony_ci case BPF_JSGE: 29662306a36Sopenharmony_ci return BPF_JSLT; 29762306a36Sopenharmony_ci case BPF_JSLE: 29862306a36Sopenharmony_ci return BPF_JSGT; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci return -1; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic inline signed long hppa_offset(int insn, int off, struct hppa_jit_context *ctx) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci signed long from, to; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci off++; /* BPF branch is from PC+1 */ 30962306a36Sopenharmony_ci from = (insn > 0) ? ctx->offset[insn - 1] : 0; 31062306a36Sopenharmony_ci to = (insn + off > 0) ? ctx->offset[insn + off - 1] : 0; 31162306a36Sopenharmony_ci return (to - from); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* does the signed value fits into a given number of bits ? */ 31562306a36Sopenharmony_cistatic inline int check_bits_int(signed long val, int bits) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci return ((val >= 0) && ((val >> bits) == 0)) || 31862306a36Sopenharmony_ci ((val < 0) && (((~((u32)val)) >> (bits-1)) == 0)); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/* can the signed value be used in relative code ? */ 32262306a36Sopenharmony_cistatic inline int relative_bits_ok(signed long val, int bits) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci return ((val >= 0) && (val < (1UL << (bits-1)))) || /* XXX */ 32562306a36Sopenharmony_ci ((val < 0) && (((~((unsigned long)val)) >> (bits-1)) == 0) 32662306a36Sopenharmony_ci && (val & (1UL << (bits-1)))); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* can the signed value be used in relative branches ? */ 33062306a36Sopenharmony_cistatic inline int relative_branch_ok(signed long val, int bits) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci return ((val >= 0) && (val < (1UL << (bits-2)))) || /* XXX */ 33362306a36Sopenharmony_ci ((val < 0) && (((~((unsigned long)val)) < (1UL << (bits-2)))) 33462306a36Sopenharmony_ci && (val & (1UL << (bits-1)))); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci#define is_5b_int(val) check_bits_int(val, 5) 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline unsigned sign_unext(unsigned x, unsigned len) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci unsigned len_ones; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci len_ones = (1 << len) - 1; 34562306a36Sopenharmony_ci return x & len_ones; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic inline unsigned low_sign_unext(unsigned x, unsigned len) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci unsigned temp; 35162306a36Sopenharmony_ci unsigned sign; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci sign = (x >> (len-1)) & 1; 35462306a36Sopenharmony_ci temp = sign_unext (x, len-1); 35562306a36Sopenharmony_ci return (temp << 1) | sign; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic inline unsigned re_assemble_12(unsigned as12) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return (( (as12 & 0x800) >> 11) 36162306a36Sopenharmony_ci | ((as12 & 0x400) >> (10 - 2)) 36262306a36Sopenharmony_ci | ((as12 & 0x3ff) << (1 + 2))); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic inline unsigned re_assemble_14(unsigned as14) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci return (( (as14 & 0x1fff) << 1) 36862306a36Sopenharmony_ci | ((as14 & 0x2000) >> 13)); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci#ifdef CONFIG_64BIT 37262306a36Sopenharmony_cistatic inline unsigned re_assemble_16(unsigned as16) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci unsigned s, t; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Unusual 16-bit encoding, for wide mode only. */ 37762306a36Sopenharmony_ci t = (as16 << 1) & 0xffff; 37862306a36Sopenharmony_ci s = (as16 & 0x8000); 37962306a36Sopenharmony_ci return (t ^ s ^ (s >> 1)) | (s >> 15); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci#endif 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic inline unsigned re_assemble_17(unsigned as17) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci return (( (as17 & 0x10000) >> 16) 38662306a36Sopenharmony_ci | ((as17 & 0x0f800) << (16 - 11)) 38762306a36Sopenharmony_ci | ((as17 & 0x00400) >> (10 - 2)) 38862306a36Sopenharmony_ci | ((as17 & 0x003ff) << (1 + 2))); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic inline unsigned re_assemble_21(unsigned as21) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci return (( (as21 & 0x100000) >> 20) 39462306a36Sopenharmony_ci | ((as21 & 0x0ffe00) >> 8) 39562306a36Sopenharmony_ci | ((as21 & 0x000180) << 7) 39662306a36Sopenharmony_ci | ((as21 & 0x00007c) << 14) 39762306a36Sopenharmony_ci | ((as21 & 0x000003) << 12)); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic inline unsigned re_assemble_22(unsigned as22) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci return (( (as22 & 0x200000) >> 21) 40362306a36Sopenharmony_ci | ((as22 & 0x1f0000) << (21 - 16)) 40462306a36Sopenharmony_ci | ((as22 & 0x00f800) << (16 - 11)) 40562306a36Sopenharmony_ci | ((as22 & 0x000400) >> (10 - 2)) 40662306a36Sopenharmony_ci | ((as22 & 0x0003ff) << (1 + 2))); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* Various HPPA instruction formats. */ 41062306a36Sopenharmony_ci/* see https://parisc.wiki.kernel.org/images-parisc/6/68/Pa11_acd.pdf, appendix C */ 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic inline u32 hppa_t1_insn(u8 opcode, u8 b, u8 r, s16 im14) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci return ((opcode << 26) | (b << 21) | (r << 16) | re_assemble_14(im14)); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic inline u32 hppa_t5_insn(u8 opcode, u8 tr, u32 val21) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci return ((opcode << 26) | (tr << 21) | re_assemble_21(val21)); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic inline u32 hppa_t6_insn(u8 opcode, u8 r2, u8 r1, u8 c, u8 f, u8 ext6, u16 t) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (c << 13) | (f << 12) | 42562306a36Sopenharmony_ci (ext6 << 6) | t); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* 7. Arithmetic immediate */ 42962306a36Sopenharmony_cistatic inline u32 hppa_t7_insn(u8 opcode, u8 r, u8 t, u32 im11) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci return ((opcode << 26) | (r << 21) | (t << 16) | low_sign_unext(im11, 11)); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/* 10. Shift instructions */ 43562306a36Sopenharmony_cistatic inline u32 hppa_t10_insn(u8 opcode, u8 r2, u8 r1, u8 c, u8 ext3, u8 cp, u8 t) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (c << 13) | 43862306a36Sopenharmony_ci (ext3 << 10) | (cp << 5) | t); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* 11. Conditional branch instructions */ 44262306a36Sopenharmony_cistatic inline u32 hppa_t11_insn(u8 opcode, u8 r2, u8 r1, u8 c, u32 w, u8 nop) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci u32 ra = re_assemble_12(w); 44562306a36Sopenharmony_ci // ra = low_sign_unext(w,11) | (w & (1<<10) 44662306a36Sopenharmony_ci return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (c << 13) | (nop << 1) | ra); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci/* 12. Branch instructions */ 45062306a36Sopenharmony_cistatic inline u32 hppa_t12_insn(u8 opcode, u8 rp, u32 w, u8 ext3, u8 nop) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci return ((opcode << 26) | (rp << 21) | (ext3 << 13) | (nop << 1) | re_assemble_17(w)); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic inline u32 hppa_t12_L_insn(u8 opcode, u32 w, u8 nop) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci return ((opcode << 26) | (0x05 << 13) | (nop << 1) | re_assemble_22(w)); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* 21. Move to control register */ 46162306a36Sopenharmony_cistatic inline u32 hppa_t21_insn(u8 opcode, u8 r2, u8 r1, u8 ext8, u8 t) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (ext8 << 5) | t); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/* Helper functions called by jit code on HPPA32 and HPPA64. */ 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ciu64 hppa_div64(u64 div, u64 divisor); 46962306a36Sopenharmony_ciu64 hppa_div64_rem(u64 div, u64 divisor); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* Helper functions that emit HPPA instructions when possible. */ 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_civoid bpf_jit_build_prologue(struct hppa_jit_context *ctx); 47462306a36Sopenharmony_civoid bpf_jit_build_epilogue(struct hppa_jit_context *ctx); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciint bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx, 47762306a36Sopenharmony_ci bool extra_pass); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci#endif /* _BPF_JIT_H */ 480