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