162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * BPF JIT compiler for PA-RISC (64-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.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * TODO:
1062306a36Sopenharmony_ci * - check if bpf_jit_needs_zext() is needed (currently enabled)
1162306a36Sopenharmony_ci * - implement arch_prepare_bpf_trampoline(), poke(), ...
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/bitfield.h>
1562306a36Sopenharmony_ci#include <linux/bpf.h>
1662306a36Sopenharmony_ci#include <linux/filter.h>
1762306a36Sopenharmony_ci#include <linux/libgcc.h>
1862306a36Sopenharmony_ci#include "bpf_jit.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic const int regmap[] = {
2162306a36Sopenharmony_ci	[BPF_REG_0] =	HPPA_REG_RET0,
2262306a36Sopenharmony_ci	[BPF_REG_1] =	HPPA_R(5),
2362306a36Sopenharmony_ci	[BPF_REG_2] =	HPPA_R(6),
2462306a36Sopenharmony_ci	[BPF_REG_3] =	HPPA_R(7),
2562306a36Sopenharmony_ci	[BPF_REG_4] =	HPPA_R(8),
2662306a36Sopenharmony_ci	[BPF_REG_5] =	HPPA_R(9),
2762306a36Sopenharmony_ci	[BPF_REG_6] =	HPPA_R(10),
2862306a36Sopenharmony_ci	[BPF_REG_7] =	HPPA_R(11),
2962306a36Sopenharmony_ci	[BPF_REG_8] =	HPPA_R(12),
3062306a36Sopenharmony_ci	[BPF_REG_9] =	HPPA_R(13),
3162306a36Sopenharmony_ci	[BPF_REG_FP] =	HPPA_R(14),
3262306a36Sopenharmony_ci	[BPF_REG_AX] =	HPPA_R(15),
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Stack layout during BPF program execution (note: stack grows up):
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci *                     high
3962306a36Sopenharmony_ci *   HPPA64 sp =>  +----------+ <= HPPA64 fp
4062306a36Sopenharmony_ci *                 | saved sp |
4162306a36Sopenharmony_ci *                 | saved rp |
4262306a36Sopenharmony_ci *                 |   ...    | HPPA64 callee-saved registers
4362306a36Sopenharmony_ci *                 | curr args|
4462306a36Sopenharmony_ci *                 | local var|
4562306a36Sopenharmony_ci *                 +----------+ <= (BPF FP)
4662306a36Sopenharmony_ci *                 |          |
4762306a36Sopenharmony_ci *                 |   ...    | BPF program stack
4862306a36Sopenharmony_ci *                 |          |
4962306a36Sopenharmony_ci *                 |   ...    | Function call stack
5062306a36Sopenharmony_ci *                 |          |
5162306a36Sopenharmony_ci *                 +----------+
5262306a36Sopenharmony_ci *                     low
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Offset from fp for BPF registers stored on stack. */
5662306a36Sopenharmony_ci#define STACK_ALIGN	FRAME_SIZE
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define EXIT_PTR_LOAD(reg)	hppa64_ldd_im16(-FRAME_SIZE, HPPA_REG_SP, reg)
5962306a36Sopenharmony_ci#define EXIT_PTR_STORE(reg)	hppa64_std_im16(reg, -FRAME_SIZE, HPPA_REG_SP)
6062306a36Sopenharmony_ci#define EXIT_PTR_JUMP(reg, nop)	hppa_bv(HPPA_REG_ZERO, reg, nop)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic u8 bpf_to_hppa_reg(int bpf_reg, struct hppa_jit_context *ctx)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	u8 reg = regmap[bpf_reg];
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	REG_SET_SEEN(ctx, reg);
6762306a36Sopenharmony_ci	return reg;
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void emit_hppa_copy(const s8 rs, const s8 rd, struct hppa_jit_context *ctx)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	REG_SET_SEEN(ctx, rd);
7362306a36Sopenharmony_ci	if (OPTIMIZE_HPPA && (rs == rd))
7462306a36Sopenharmony_ci		return;
7562306a36Sopenharmony_ci	REG_SET_SEEN(ctx, rs);
7662306a36Sopenharmony_ci	emit(hppa_copy(rs, rd), ctx);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic void emit_hppa64_depd(u8 src, u8 pos, u8 len, u8 target, bool no_zero, struct hppa_jit_context *ctx)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	int c;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	pos &= (BITS_PER_LONG - 1);
8462306a36Sopenharmony_ci	pos = 63 - pos;
8562306a36Sopenharmony_ci	len = 64 - len;
8662306a36Sopenharmony_ci	c =  (len < 32)  ? 0x4 : 0;
8762306a36Sopenharmony_ci	c |= (pos >= 32) ? 0x2 : 0;
8862306a36Sopenharmony_ci	c |= (no_zero)   ? 0x1 : 0;
8962306a36Sopenharmony_ci	emit(hppa_t10_insn(0x3c, target, src, 0, c, pos & 0x1f, len & 0x1f), ctx);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic void emit_hppa64_shld(u8 src, int num, u8 target, struct hppa_jit_context *ctx)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	emit_hppa64_depd(src, 63-num, 64-num, target, 0, ctx);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void emit_hppa64_extrd(u8 src, u8 pos, u8 len, u8 target, bool signed_op, struct hppa_jit_context *ctx)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int c;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	pos &= (BITS_PER_LONG - 1);
10262306a36Sopenharmony_ci	len = 64 - len;
10362306a36Sopenharmony_ci	c =  (len <  32) ? 0x4 : 0;
10462306a36Sopenharmony_ci	c |= (pos >= 32) ? 0x2 : 0;
10562306a36Sopenharmony_ci	c |= signed_op   ? 0x1 : 0;
10662306a36Sopenharmony_ci	emit(hppa_t10_insn(0x36, src, target, 0, c, pos & 0x1f, len & 0x1f), ctx);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void emit_hppa64_extrw(u8 src, u8 pos, u8 len, u8 target, bool signed_op, struct hppa_jit_context *ctx)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	int c;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	pos &= (32 - 1);
11462306a36Sopenharmony_ci	len = 32 - len;
11562306a36Sopenharmony_ci	c = 0x06 | (signed_op ? 1 : 0);
11662306a36Sopenharmony_ci	emit(hppa_t10_insn(0x34, src, target, 0, c, pos, len), ctx);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define emit_hppa64_zext32(r, target, ctx) \
12062306a36Sopenharmony_ci	emit_hppa64_extrd(r, 63, 32, target, false, ctx)
12162306a36Sopenharmony_ci#define emit_hppa64_sext32(r, target, ctx) \
12262306a36Sopenharmony_ci	emit_hppa64_extrd(r, 63, 32, target, true, ctx)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void emit_hppa64_shrd(u8 src, int num, u8 target, bool signed_op, struct hppa_jit_context *ctx)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	emit_hppa64_extrd(src, 63-num, 64-num, target, signed_op, ctx);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void emit_hppa64_shrw(u8 src, int num, u8 target, bool signed_op, struct hppa_jit_context *ctx)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	emit_hppa64_extrw(src, 31-num, 32-num, target, signed_op, ctx);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* Emit variable-length instructions for 32-bit imm */
13562306a36Sopenharmony_cistatic void emit_imm32(u8 rd, s32 imm, struct hppa_jit_context *ctx)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	u32 lower = im11(imm);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	REG_SET_SEEN(ctx, rd);
14062306a36Sopenharmony_ci	if (OPTIMIZE_HPPA && relative_bits_ok(imm, 14)) {
14162306a36Sopenharmony_ci		emit(hppa_ldi(imm, rd), ctx);
14262306a36Sopenharmony_ci		return;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	if (OPTIMIZE_HPPA && lower == imm) {
14562306a36Sopenharmony_ci		emit(hppa_ldo(lower, HPPA_REG_ZERO, rd), ctx);
14662306a36Sopenharmony_ci		return;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci	emit(hppa_ldil(imm, rd), ctx);
14962306a36Sopenharmony_ci	if (OPTIMIZE_HPPA && (lower == 0))
15062306a36Sopenharmony_ci		return;
15162306a36Sopenharmony_ci	emit(hppa_ldo(lower, rd, rd), ctx);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic bool is_32b_int(s64 val)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	return val == (s32) val;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/* Emit variable-length instructions for 64-bit imm */
16062306a36Sopenharmony_cistatic void emit_imm(u8 rd, s64 imm, u8 tmpreg, struct hppa_jit_context *ctx)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	u32 upper32;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* get lower 32-bits into rd, sign extended */
16562306a36Sopenharmony_ci	emit_imm32(rd, imm, ctx);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* do we have upper 32-bits too ? */
16862306a36Sopenharmony_ci	if (OPTIMIZE_HPPA && is_32b_int(imm))
16962306a36Sopenharmony_ci		return;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* load upper 32-bits into lower tmpreg and deposit into rd */
17262306a36Sopenharmony_ci	upper32 = imm >> 32;
17362306a36Sopenharmony_ci	if (upper32 || !OPTIMIZE_HPPA) {
17462306a36Sopenharmony_ci		emit_imm32(tmpreg, upper32, ctx);
17562306a36Sopenharmony_ci		emit_hppa64_depd(tmpreg, 31, 32, rd, 1, ctx);
17662306a36Sopenharmony_ci	} else
17762306a36Sopenharmony_ci		emit_hppa64_depd(HPPA_REG_ZERO, 31, 32, rd, 1, ctx);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int emit_jump(signed long paoff, bool force_far,
18262306a36Sopenharmony_ci			       struct hppa_jit_context *ctx)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	unsigned long pc, addr;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* Note: Use 2 instructions for jumps if force_far is set. */
18762306a36Sopenharmony_ci	if (relative_bits_ok(paoff - HPPA_BRANCH_DISPLACEMENT, 22)) {
18862306a36Sopenharmony_ci		/* use BL,long branch followed by nop() */
18962306a36Sopenharmony_ci		emit(hppa64_bl_long(paoff - HPPA_BRANCH_DISPLACEMENT), ctx);
19062306a36Sopenharmony_ci		if (force_far)
19162306a36Sopenharmony_ci			emit(hppa_nop(), ctx);
19262306a36Sopenharmony_ci		return 0;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	pc = (uintptr_t) &ctx->insns[ctx->ninsns];
19662306a36Sopenharmony_ci	addr = pc + (paoff * HPPA_INSN_SIZE);
19762306a36Sopenharmony_ci	/* even the 64-bit kernel runs in memory below 4GB */
19862306a36Sopenharmony_ci	if (WARN_ON_ONCE(addr >> 32))
19962306a36Sopenharmony_ci		return -E2BIG;
20062306a36Sopenharmony_ci	emit(hppa_ldil(addr, HPPA_REG_R31), ctx);
20162306a36Sopenharmony_ci	emit(hppa_be_l(im11(addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx);
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic void __build_epilogue(bool is_tail_call, struct hppa_jit_context *ctx)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	int i;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (is_tail_call) {
21062306a36Sopenharmony_ci		/*
21162306a36Sopenharmony_ci		 * goto *(t0 + 4);
21262306a36Sopenharmony_ci		 * Skips first instruction of prologue which initializes tail
21362306a36Sopenharmony_ci		 * call counter. Assumes t0 contains address of target program,
21462306a36Sopenharmony_ci		 * see emit_bpf_tail_call.
21562306a36Sopenharmony_ci		 */
21662306a36Sopenharmony_ci		emit(hppa_ldo(1 * HPPA_INSN_SIZE, HPPA_REG_T0, HPPA_REG_T0), ctx);
21762306a36Sopenharmony_ci		emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_T0, EXEC_NEXT_INSTR), ctx);
21862306a36Sopenharmony_ci		/* in delay slot: */
21962306a36Sopenharmony_ci		emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_IN_INIT), ctx);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		return;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* load epilogue function pointer and jump to it. */
22562306a36Sopenharmony_ci	/* exit point is either at next instruction, or the outest TCC exit function */
22662306a36Sopenharmony_ci	emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
22762306a36Sopenharmony_ci	emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* NOTE: we are 64-bit and big-endian, so return lower sign-extended 32-bit value */
23062306a36Sopenharmony_ci	emit_hppa64_sext32(regmap[BPF_REG_0], HPPA_REG_RET0, ctx);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* Restore callee-saved registers. */
23362306a36Sopenharmony_ci	for (i = 3; i <= 15; i++) {
23462306a36Sopenharmony_ci		if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i)))
23562306a36Sopenharmony_ci			continue;
23662306a36Sopenharmony_ci		emit(hppa64_ldd_im16(-REG_SIZE * i, HPPA_REG_SP, HPPA_R(i)), ctx);
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* load original return pointer (stored by outest TCC function) */
24062306a36Sopenharmony_ci	emit(hppa64_ldd_im16(-2*REG_SIZE, HPPA_REG_SP, HPPA_REG_RP), ctx);
24162306a36Sopenharmony_ci	emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_RP, EXEC_NEXT_INSTR), ctx);
24262306a36Sopenharmony_ci	/* in delay slot: */
24362306a36Sopenharmony_ci	emit(hppa64_ldd_im5(-REG_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	emit(hppa_nop(), ctx); // XXX WARUM einer zu wenig ??
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int emit_branch(u8 op, u8 rd, u8 rs, signed long paoff,
24962306a36Sopenharmony_ci			struct hppa_jit_context *ctx)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	int e, s;
25262306a36Sopenharmony_ci	bool far = false;
25362306a36Sopenharmony_ci	int off;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (op == BPF_JSET) {
25662306a36Sopenharmony_ci		/*
25762306a36Sopenharmony_ci		 * BPF_JSET is a special case: it has no inverse so translate
25862306a36Sopenharmony_ci		 * to and() function and compare against zero
25962306a36Sopenharmony_ci		 */
26062306a36Sopenharmony_ci		emit(hppa_and(rd, rs, HPPA_REG_T0), ctx);
26162306a36Sopenharmony_ci		paoff -= 1; /* reduce offset due to hppa_and() above */
26262306a36Sopenharmony_ci		rd = HPPA_REG_T0;
26362306a36Sopenharmony_ci		rs = HPPA_REG_ZERO;
26462306a36Sopenharmony_ci		op = BPF_JNE;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* set start after BPF_JSET */
26862306a36Sopenharmony_ci	s = ctx->ninsns;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (!relative_branch_ok(paoff - HPPA_BRANCH_DISPLACEMENT + 1, 12)) {
27162306a36Sopenharmony_ci		op = invert_bpf_cond(op);
27262306a36Sopenharmony_ci		far = true;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/*
27662306a36Sopenharmony_ci	 * For a far branch, the condition is negated and we jump over the
27762306a36Sopenharmony_ci	 * branch itself, and the two instructions from emit_jump.
27862306a36Sopenharmony_ci	 * For a near branch, just use paoff.
27962306a36Sopenharmony_ci	 */
28062306a36Sopenharmony_ci	off = far ? (2 - HPPA_BRANCH_DISPLACEMENT) : paoff - HPPA_BRANCH_DISPLACEMENT;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	switch (op) {
28362306a36Sopenharmony_ci	/* IF (dst COND src) JUMP off */
28462306a36Sopenharmony_ci	case BPF_JEQ:
28562306a36Sopenharmony_ci		emit(hppa_beq(rd, rs, off), ctx);
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci	case BPF_JGT:
28862306a36Sopenharmony_ci		emit(hppa_bgtu(rd, rs, off), ctx);
28962306a36Sopenharmony_ci		break;
29062306a36Sopenharmony_ci	case BPF_JLT:
29162306a36Sopenharmony_ci		emit(hppa_bltu(rd, rs, off), ctx);
29262306a36Sopenharmony_ci		break;
29362306a36Sopenharmony_ci	case BPF_JGE:
29462306a36Sopenharmony_ci		emit(hppa_bgeu(rd, rs, off), ctx);
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	case BPF_JLE:
29762306a36Sopenharmony_ci		emit(hppa_bleu(rd, rs, off), ctx);
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	case BPF_JNE:
30062306a36Sopenharmony_ci		emit(hppa_bne(rd, rs, off), ctx);
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	case BPF_JSGT:
30362306a36Sopenharmony_ci		emit(hppa_bgt(rd, rs, off), ctx);
30462306a36Sopenharmony_ci		break;
30562306a36Sopenharmony_ci	case BPF_JSLT:
30662306a36Sopenharmony_ci		emit(hppa_blt(rd, rs, off), ctx);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	case BPF_JSGE:
30962306a36Sopenharmony_ci		emit(hppa_bge(rd, rs, off), ctx);
31062306a36Sopenharmony_ci		break;
31162306a36Sopenharmony_ci	case BPF_JSLE:
31262306a36Sopenharmony_ci		emit(hppa_ble(rd, rs, off), ctx);
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	default:
31562306a36Sopenharmony_ci		WARN_ON(1);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (far) {
31962306a36Sopenharmony_ci		int ret;
32062306a36Sopenharmony_ci		e = ctx->ninsns;
32162306a36Sopenharmony_ci		/* Adjust for extra insns. */
32262306a36Sopenharmony_ci		paoff -= (e - s);
32362306a36Sopenharmony_ci		ret = emit_jump(paoff, true, ctx);
32462306a36Sopenharmony_ci		if (ret)
32562306a36Sopenharmony_ci			return ret;
32662306a36Sopenharmony_ci	} else {
32762306a36Sopenharmony_ci		/*
32862306a36Sopenharmony_ci		 * always allocate 2 nops instead of the far branch to
32962306a36Sopenharmony_ci		 * reduce translation loops
33062306a36Sopenharmony_ci		 */
33162306a36Sopenharmony_ci		emit(hppa_nop(), ctx);
33262306a36Sopenharmony_ci		emit(hppa_nop(), ctx);
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	return 0;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic void emit_zext_32(u8 reg, struct hppa_jit_context *ctx)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	emit_hppa64_zext32(reg, reg, ctx);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic void emit_bpf_tail_call(int insn, struct hppa_jit_context *ctx)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	/*
34562306a36Sopenharmony_ci	 * R1 -> &ctx
34662306a36Sopenharmony_ci	 * R2 -> &array
34762306a36Sopenharmony_ci	 * R3 -> index
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	int off;
35062306a36Sopenharmony_ci	const s8 arr_reg = regmap[BPF_REG_2];
35162306a36Sopenharmony_ci	const s8 idx_reg = regmap[BPF_REG_3];
35262306a36Sopenharmony_ci	struct bpf_array bpfa;
35362306a36Sopenharmony_ci	struct bpf_prog bpfp;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* if there is any tail call, we need to save & restore all registers */
35662306a36Sopenharmony_ci	REG_SET_SEEN_ALL(ctx);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* get address of TCC main exit function for error case into rp */
35962306a36Sopenharmony_ci	emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* max_entries = array->map.max_entries; */
36262306a36Sopenharmony_ci	off = offsetof(struct bpf_array, map.max_entries);
36362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(bpfa.map.max_entries) != 4);
36462306a36Sopenharmony_ci	emit(hppa_ldw(off, arr_reg, HPPA_REG_T1), ctx);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/*
36762306a36Sopenharmony_ci	 * if (index >= max_entries)
36862306a36Sopenharmony_ci	 *   goto out;
36962306a36Sopenharmony_ci	 */
37062306a36Sopenharmony_ci	emit(hppa_bltu(idx_reg, HPPA_REG_T1, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
37162306a36Sopenharmony_ci	emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/*
37462306a36Sopenharmony_ci	 * if (--tcc < 0)
37562306a36Sopenharmony_ci	 *   goto out;
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	REG_FORCE_SEEN(ctx, HPPA_REG_TCC);
37862306a36Sopenharmony_ci	emit(hppa_ldo(-1, HPPA_REG_TCC, HPPA_REG_TCC), ctx);
37962306a36Sopenharmony_ci	emit(hppa_bge(HPPA_REG_TCC, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
38062306a36Sopenharmony_ci	emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/*
38362306a36Sopenharmony_ci	 * prog = array->ptrs[index];
38462306a36Sopenharmony_ci	 * if (!prog)
38562306a36Sopenharmony_ci	 *   goto out;
38662306a36Sopenharmony_ci	 */
38762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(bpfa.ptrs[0]) != 8);
38862306a36Sopenharmony_ci	emit(hppa64_shladd(idx_reg, 3, arr_reg, HPPA_REG_T0), ctx);
38962306a36Sopenharmony_ci	off = offsetof(struct bpf_array, ptrs);
39062306a36Sopenharmony_ci	BUILD_BUG_ON(off < 16);
39162306a36Sopenharmony_ci	emit(hppa64_ldd_im16(off, HPPA_REG_T0, HPPA_REG_T0), ctx);
39262306a36Sopenharmony_ci	emit(hppa_bne(HPPA_REG_T0, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
39362306a36Sopenharmony_ci	emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/*
39662306a36Sopenharmony_ci	 * tcc = temp_tcc;
39762306a36Sopenharmony_ci	 * goto *(prog->bpf_func + 4);
39862306a36Sopenharmony_ci	 */
39962306a36Sopenharmony_ci	off = offsetof(struct bpf_prog, bpf_func);
40062306a36Sopenharmony_ci	BUILD_BUG_ON(off < 16);
40162306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(bpfp.bpf_func) != 8);
40262306a36Sopenharmony_ci	emit(hppa64_ldd_im16(off, HPPA_REG_T0, HPPA_REG_T0), ctx);
40362306a36Sopenharmony_ci	/* Epilogue jumps to *(t0 + 4). */
40462306a36Sopenharmony_ci	__build_epilogue(true, ctx);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void init_regs(u8 *rd, u8 *rs, const struct bpf_insn *insn,
40862306a36Sopenharmony_ci		      struct hppa_jit_context *ctx)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	u8 code = insn->code;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	switch (code) {
41362306a36Sopenharmony_ci	case BPF_JMP | BPF_JA:
41462306a36Sopenharmony_ci	case BPF_JMP | BPF_CALL:
41562306a36Sopenharmony_ci	case BPF_JMP | BPF_EXIT:
41662306a36Sopenharmony_ci	case BPF_JMP | BPF_TAIL_CALL:
41762306a36Sopenharmony_ci		break;
41862306a36Sopenharmony_ci	default:
41962306a36Sopenharmony_ci		*rd = bpf_to_hppa_reg(insn->dst_reg, ctx);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (code & (BPF_ALU | BPF_X) || code & (BPF_ALU64 | BPF_X) ||
42362306a36Sopenharmony_ci	    code & (BPF_JMP | BPF_X) || code & (BPF_JMP32 | BPF_X) ||
42462306a36Sopenharmony_ci	    code & BPF_LDX || code & BPF_STX)
42562306a36Sopenharmony_ci		*rs = bpf_to_hppa_reg(insn->src_reg, ctx);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void emit_zext_32_rd_rs(u8 *rd, u8 *rs, struct hppa_jit_context *ctx)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	emit_hppa64_zext32(*rd, HPPA_REG_T2, ctx);
43162306a36Sopenharmony_ci	*rd = HPPA_REG_T2;
43262306a36Sopenharmony_ci	emit_hppa64_zext32(*rs, HPPA_REG_T1, ctx);
43362306a36Sopenharmony_ci	*rs = HPPA_REG_T1;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic void emit_sext_32_rd_rs(u8 *rd, u8 *rs, struct hppa_jit_context *ctx)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	emit_hppa64_sext32(*rd, HPPA_REG_T2, ctx);
43962306a36Sopenharmony_ci	*rd = HPPA_REG_T2;
44062306a36Sopenharmony_ci	emit_hppa64_sext32(*rs, HPPA_REG_T1, ctx);
44162306a36Sopenharmony_ci	*rs = HPPA_REG_T1;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic void emit_zext_32_rd_t1(u8 *rd, struct hppa_jit_context *ctx)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	emit_hppa64_zext32(*rd, HPPA_REG_T2, ctx);
44762306a36Sopenharmony_ci	*rd = HPPA_REG_T2;
44862306a36Sopenharmony_ci	emit_zext_32(HPPA_REG_T1, ctx);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void emit_sext_32_rd(u8 *rd, struct hppa_jit_context *ctx)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	emit_hppa64_sext32(*rd, HPPA_REG_T2, ctx);
45462306a36Sopenharmony_ci	*rd = HPPA_REG_T2;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic bool is_signed_bpf_cond(u8 cond)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	return cond == BPF_JSGT || cond == BPF_JSLT ||
46062306a36Sopenharmony_ci		cond == BPF_JSGE || cond == BPF_JSLE;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic void emit_call(u64 addr, bool fixed, struct hppa_jit_context *ctx)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	const int offset_sp = 2*FRAME_SIZE;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	emit(hppa_ldo(offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	emit_hppa_copy(regmap[BPF_REG_1], HPPA_REG_ARG0, ctx);
47062306a36Sopenharmony_ci	emit_hppa_copy(regmap[BPF_REG_2], HPPA_REG_ARG1, ctx);
47162306a36Sopenharmony_ci	emit_hppa_copy(regmap[BPF_REG_3], HPPA_REG_ARG2, ctx);
47262306a36Sopenharmony_ci	emit_hppa_copy(regmap[BPF_REG_4], HPPA_REG_ARG3, ctx);
47362306a36Sopenharmony_ci	emit_hppa_copy(regmap[BPF_REG_5], HPPA_REG_ARG4, ctx);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* Backup TCC. */
47662306a36Sopenharmony_ci	REG_FORCE_SEEN(ctx, HPPA_REG_TCC_SAVED);
47762306a36Sopenharmony_ci	if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
47862306a36Sopenharmony_ci		emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_SAVED), ctx);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/*
48162306a36Sopenharmony_ci	 * Use ldil() to load absolute address. Don't use emit_imm as the
48262306a36Sopenharmony_ci	 * number of emitted instructions should not depend on the value of
48362306a36Sopenharmony_ci	 * addr.
48462306a36Sopenharmony_ci	 */
48562306a36Sopenharmony_ci	WARN_ON(addr >> 32);
48662306a36Sopenharmony_ci	/* load function address and gp from Elf64_Fdesc descriptor */
48762306a36Sopenharmony_ci	emit(hppa_ldil(addr, HPPA_REG_R31), ctx);
48862306a36Sopenharmony_ci	emit(hppa_ldo(im11(addr), HPPA_REG_R31, HPPA_REG_R31), ctx);
48962306a36Sopenharmony_ci	emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, addr),
49062306a36Sopenharmony_ci			     HPPA_REG_R31, HPPA_REG_RP), ctx);
49162306a36Sopenharmony_ci	emit(hppa64_bve_l_rp(HPPA_REG_RP), ctx);
49262306a36Sopenharmony_ci	emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, gp),
49362306a36Sopenharmony_ci			     HPPA_REG_R31, HPPA_REG_GP), ctx);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Restore TCC. */
49662306a36Sopenharmony_ci	if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
49762306a36Sopenharmony_ci		emit(hppa_copy(HPPA_REG_TCC_SAVED, HPPA_REG_TCC), ctx);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	emit(hppa_ldo(-offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* Set return value. */
50262306a36Sopenharmony_ci	emit_hppa_copy(HPPA_REG_RET0, regmap[BPF_REG_0], ctx);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic void emit_call_libgcc_ll(void *func, const s8 arg0,
50662306a36Sopenharmony_ci		const s8 arg1, u8 opcode, struct hppa_jit_context *ctx)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	u64 func_addr;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (BPF_CLASS(opcode) == BPF_ALU) {
51162306a36Sopenharmony_ci		emit_hppa64_zext32(arg0, HPPA_REG_ARG0, ctx);
51262306a36Sopenharmony_ci		emit_hppa64_zext32(arg1, HPPA_REG_ARG1, ctx);
51362306a36Sopenharmony_ci	} else {
51462306a36Sopenharmony_ci		emit_hppa_copy(arg0, HPPA_REG_ARG0, ctx);
51562306a36Sopenharmony_ci		emit_hppa_copy(arg1, HPPA_REG_ARG1, ctx);
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* libcgcc overwrites HPPA_REG_RET0, so keep copy in HPPA_REG_TCC_SAVED */
51962306a36Sopenharmony_ci	if (arg0 != HPPA_REG_RET0) {
52062306a36Sopenharmony_ci		REG_SET_SEEN(ctx, HPPA_REG_TCC_SAVED);
52162306a36Sopenharmony_ci		emit(hppa_copy(HPPA_REG_RET0, HPPA_REG_TCC_SAVED), ctx);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* set up stack */
52562306a36Sopenharmony_ci	emit(hppa_ldo(FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	func_addr = (uintptr_t) func;
52862306a36Sopenharmony_ci	/* load function func_address and gp from Elf64_Fdesc descriptor */
52962306a36Sopenharmony_ci	emit_imm(HPPA_REG_R31, func_addr, arg0, ctx);
53062306a36Sopenharmony_ci	emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, addr),
53162306a36Sopenharmony_ci			     HPPA_REG_R31, HPPA_REG_RP), ctx);
53262306a36Sopenharmony_ci        /* skip the following bve_l instruction if divisor is 0. */
53362306a36Sopenharmony_ci        if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) {
53462306a36Sopenharmony_ci		if (BPF_OP(opcode) == BPF_DIV)
53562306a36Sopenharmony_ci			emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET0, ctx);
53662306a36Sopenharmony_ci		else {
53762306a36Sopenharmony_ci			emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET0, ctx);
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci		emit(hppa_beq(HPPA_REG_ARG1, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci	emit(hppa64_bve_l_rp(HPPA_REG_RP), ctx);
54262306a36Sopenharmony_ci	emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, gp),
54362306a36Sopenharmony_ci			     HPPA_REG_R31, HPPA_REG_GP), ctx);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	emit(hppa_ldo(-FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	emit_hppa_copy(HPPA_REG_RET0, arg0, ctx);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* restore HPPA_REG_RET0 */
55062306a36Sopenharmony_ci	if (arg0 != HPPA_REG_RET0)
55162306a36Sopenharmony_ci		emit(hppa_copy(HPPA_REG_TCC_SAVED, HPPA_REG_RET0), ctx);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic void emit_store(const s8 rd, const s8 rs, s16 off,
55562306a36Sopenharmony_ci			  struct hppa_jit_context *ctx, const u8 size,
55662306a36Sopenharmony_ci			  const u8 mode)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	s8 dstreg;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* need to calculate address since offset does not fit in 14 bits? */
56162306a36Sopenharmony_ci	if (relative_bits_ok(off, 14))
56262306a36Sopenharmony_ci		dstreg = rd;
56362306a36Sopenharmony_ci	else {
56462306a36Sopenharmony_ci		/* need to use R1 here, since addil puts result into R1 */
56562306a36Sopenharmony_ci		dstreg = HPPA_REG_R1;
56662306a36Sopenharmony_ci		emit(hppa_addil(off, rd), ctx);
56762306a36Sopenharmony_ci		off = im11(off);
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	switch (size) {
57162306a36Sopenharmony_ci	case BPF_B:
57262306a36Sopenharmony_ci		emit(hppa_stb(rs, off, dstreg), ctx);
57362306a36Sopenharmony_ci		break;
57462306a36Sopenharmony_ci	case BPF_H:
57562306a36Sopenharmony_ci		emit(hppa_sth(rs, off, dstreg), ctx);
57662306a36Sopenharmony_ci		break;
57762306a36Sopenharmony_ci	case BPF_W:
57862306a36Sopenharmony_ci		emit(hppa_stw(rs, off, dstreg), ctx);
57962306a36Sopenharmony_ci		break;
58062306a36Sopenharmony_ci	case BPF_DW:
58162306a36Sopenharmony_ci		if (off & 7) {
58262306a36Sopenharmony_ci			emit(hppa_ldo(off, dstreg, HPPA_REG_R1), ctx);
58362306a36Sopenharmony_ci			emit(hppa64_std_im5(rs, 0, HPPA_REG_R1), ctx);
58462306a36Sopenharmony_ci		} else if (off >= -16 && off <= 15)
58562306a36Sopenharmony_ci			emit(hppa64_std_im5(rs, off, dstreg), ctx);
58662306a36Sopenharmony_ci		else
58762306a36Sopenharmony_ci			emit(hppa64_std_im16(rs, off, dstreg), ctx);
58862306a36Sopenharmony_ci		break;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ciint bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
59362306a36Sopenharmony_ci		      bool extra_pass)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 ||
59662306a36Sopenharmony_ci		    BPF_CLASS(insn->code) == BPF_JMP;
59762306a36Sopenharmony_ci	int s, e, ret, i = insn - ctx->prog->insnsi;
59862306a36Sopenharmony_ci	s64 paoff;
59962306a36Sopenharmony_ci	struct bpf_prog_aux *aux = ctx->prog->aux;
60062306a36Sopenharmony_ci	u8 rd = -1, rs = -1, code = insn->code;
60162306a36Sopenharmony_ci	s16 off = insn->off;
60262306a36Sopenharmony_ci	s32 imm = insn->imm;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	init_regs(&rd, &rs, insn, ctx);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	switch (code) {
60762306a36Sopenharmony_ci	/* dst = src */
60862306a36Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_X:
60962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_X:
61062306a36Sopenharmony_ci		if (imm == 1) {
61162306a36Sopenharmony_ci			/* Special mov32 for zext */
61262306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
61662306a36Sopenharmony_ci			emit_hppa64_zext32(rs, rd, ctx);
61762306a36Sopenharmony_ci		else
61862306a36Sopenharmony_ci			emit_hppa_copy(rs, rd, ctx);
61962306a36Sopenharmony_ci		break;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* dst = dst OP src */
62262306a36Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_X:
62362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_X:
62462306a36Sopenharmony_ci                emit(hppa_add(rd, rs, rd), ctx);
62562306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
62662306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
62762306a36Sopenharmony_ci		break;
62862306a36Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_X:
62962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_X:
63062306a36Sopenharmony_ci                emit(hppa_sub(rd, rs, rd), ctx);
63162306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
63262306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
63362306a36Sopenharmony_ci		break;
63462306a36Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_X:
63562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_X:
63662306a36Sopenharmony_ci                emit(hppa_and(rd, rs, rd), ctx);
63762306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
63862306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_X:
64162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_X:
64262306a36Sopenharmony_ci                emit(hppa_or(rd, rs, rd), ctx);
64362306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
64462306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_X:
64762306a36Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_X:
64862306a36Sopenharmony_ci                emit(hppa_xor(rd, rs, rd), ctx);
64962306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext && rs != rd)
65062306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
65162306a36Sopenharmony_ci		break;
65262306a36Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_K:
65362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_K:
65462306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, is64 ? (s64)(s32)imm : (u32)imm, HPPA_REG_T2, ctx);
65562306a36Sopenharmony_ci		rs = HPPA_REG_T1;
65662306a36Sopenharmony_ci		fallthrough;
65762306a36Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_X:
65862306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_X:
65962306a36Sopenharmony_ci		emit_call_libgcc_ll(__muldi3, rd, rs, code, ctx);
66062306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
66162306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
66262306a36Sopenharmony_ci		break;
66362306a36Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_K:
66462306a36Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_K:
66562306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, is64 ? (s64)(s32)imm : (u32)imm, HPPA_REG_T2, ctx);
66662306a36Sopenharmony_ci		rs = HPPA_REG_T1;
66762306a36Sopenharmony_ci		fallthrough;
66862306a36Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_X:
66962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_X:
67062306a36Sopenharmony_ci		emit_call_libgcc_ll(&hppa_div64, rd, rs, code, ctx);
67162306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
67262306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
67362306a36Sopenharmony_ci		break;
67462306a36Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_K:
67562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_K:
67662306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, is64 ? (s64)(s32)imm : (u32)imm, HPPA_REG_T2, ctx);
67762306a36Sopenharmony_ci		rs = HPPA_REG_T1;
67862306a36Sopenharmony_ci		fallthrough;
67962306a36Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_X:
68062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_X:
68162306a36Sopenharmony_ci		emit_call_libgcc_ll(&hppa_div64_rem, rd, rs, code, ctx);
68262306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
68362306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
68462306a36Sopenharmony_ci		break;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_X:
68762306a36Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_X:
68862306a36Sopenharmony_ci		emit_hppa64_sext32(rs, HPPA_REG_T0, ctx);
68962306a36Sopenharmony_ci		emit(hppa64_mtsarcm(HPPA_REG_T0), ctx);
69062306a36Sopenharmony_ci		if (is64)
69162306a36Sopenharmony_ci			emit(hppa64_depdz_sar(rd, rd), ctx);
69262306a36Sopenharmony_ci		else
69362306a36Sopenharmony_ci			emit(hppa_depwz_sar(rd, rd), ctx);
69462306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
69562306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
69662306a36Sopenharmony_ci		break;
69762306a36Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_X:
69862306a36Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_X:
69962306a36Sopenharmony_ci		emit(hppa_mtsar(rs), ctx);
70062306a36Sopenharmony_ci		if (is64)
70162306a36Sopenharmony_ci			emit(hppa64_shrpd_sar(rd, rd), ctx);
70262306a36Sopenharmony_ci		else
70362306a36Sopenharmony_ci			emit(hppa_shrpw_sar(rd, rd), ctx);
70462306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
70562306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_X:
70862306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_X:
70962306a36Sopenharmony_ci		emit_hppa64_sext32(rs, HPPA_REG_T0, ctx);
71062306a36Sopenharmony_ci                emit(hppa64_mtsarcm(HPPA_REG_T0), ctx);
71162306a36Sopenharmony_ci		if (is64)
71262306a36Sopenharmony_ci			emit(hppa_extrd_sar(rd, rd, 1), ctx);
71362306a36Sopenharmony_ci		else
71462306a36Sopenharmony_ci			emit(hppa_extrws_sar(rd, rd), ctx);
71562306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
71662306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
71762306a36Sopenharmony_ci		break;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* dst = -dst */
72062306a36Sopenharmony_ci	case BPF_ALU | BPF_NEG:
72162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_NEG:
72262306a36Sopenharmony_ci		emit(hppa_sub(HPPA_REG_ZERO, rd, rd), ctx);
72362306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
72462306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
72562306a36Sopenharmony_ci		break;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* dst = BSWAP##imm(dst) */
72862306a36Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_BE:
72962306a36Sopenharmony_ci		switch (imm) {
73062306a36Sopenharmony_ci		case 16:
73162306a36Sopenharmony_ci			/* zero-extend 16 bits into 64 bits */
73262306a36Sopenharmony_ci			emit_hppa64_depd(HPPA_REG_ZERO, 63-16, 64-16, rd, 1, ctx);
73362306a36Sopenharmony_ci			break;
73462306a36Sopenharmony_ci		case 32:
73562306a36Sopenharmony_ci			if (!aux->verifier_zext)
73662306a36Sopenharmony_ci				emit_zext_32(rd, ctx);
73762306a36Sopenharmony_ci			break;
73862306a36Sopenharmony_ci		case 64:
73962306a36Sopenharmony_ci			/* Do nothing */
74062306a36Sopenharmony_ci			break;
74162306a36Sopenharmony_ci		}
74262306a36Sopenharmony_ci		break;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_LE:
74562306a36Sopenharmony_ci		switch (imm) {
74662306a36Sopenharmony_ci		case 16:
74762306a36Sopenharmony_ci			emit(hppa_extru(rd, 31 - 8, 8, HPPA_REG_T1), ctx);
74862306a36Sopenharmony_ci			emit(hppa_depwz(rd, 23, 8, HPPA_REG_T1), ctx);
74962306a36Sopenharmony_ci			emit(hppa_extru(HPPA_REG_T1, 31, 16, rd), ctx);
75062306a36Sopenharmony_ci			emit_hppa64_extrd(HPPA_REG_T1, 63, 16, rd, 0, ctx);
75162306a36Sopenharmony_ci			break;
75262306a36Sopenharmony_ci		case 32:
75362306a36Sopenharmony_ci			emit(hppa_shrpw(rd, rd, 16, HPPA_REG_T1), ctx);
75462306a36Sopenharmony_ci			emit_hppa64_depd(HPPA_REG_T1, 63-16, 8, HPPA_REG_T1, 1, ctx);
75562306a36Sopenharmony_ci			emit(hppa_shrpw(rd, HPPA_REG_T1, 8, HPPA_REG_T1), ctx);
75662306a36Sopenharmony_ci			emit_hppa64_extrd(HPPA_REG_T1, 63, 32, rd, 0, ctx);
75762306a36Sopenharmony_ci			break;
75862306a36Sopenharmony_ci		case 64:
75962306a36Sopenharmony_ci			emit(hppa64_permh_3210(rd, HPPA_REG_T1), ctx);
76062306a36Sopenharmony_ci			emit(hppa64_hshl(HPPA_REG_T1, 8, HPPA_REG_T2), ctx);
76162306a36Sopenharmony_ci			emit(hppa64_hshr_u(HPPA_REG_T1, 8, HPPA_REG_T1), ctx);
76262306a36Sopenharmony_ci			emit(hppa_or(HPPA_REG_T2, HPPA_REG_T1, rd), ctx);
76362306a36Sopenharmony_ci			break;
76462306a36Sopenharmony_ci		default:
76562306a36Sopenharmony_ci			pr_err("bpf-jit: BPF_END imm %d invalid\n", imm);
76662306a36Sopenharmony_ci			return -1;
76762306a36Sopenharmony_ci		}
76862306a36Sopenharmony_ci		break;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/* dst = imm */
77162306a36Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_K:
77262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_K:
77362306a36Sopenharmony_ci		emit_imm(rd, imm, HPPA_REG_T2, ctx);
77462306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
77562306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
77662306a36Sopenharmony_ci		break;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/* dst = dst OP imm */
77962306a36Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_K:
78062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_K:
78162306a36Sopenharmony_ci		if (relative_bits_ok(imm, 14)) {
78262306a36Sopenharmony_ci			emit(hppa_ldo(imm, rd, rd), ctx);
78362306a36Sopenharmony_ci		} else {
78462306a36Sopenharmony_ci			emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
78562306a36Sopenharmony_ci			emit(hppa_add(rd, HPPA_REG_T1, rd), ctx);
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
78862306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
78962306a36Sopenharmony_ci		break;
79062306a36Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_K:
79162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_K:
79262306a36Sopenharmony_ci		if (relative_bits_ok(-imm, 14)) {
79362306a36Sopenharmony_ci			emit(hppa_ldo(-imm, rd, rd), ctx);
79462306a36Sopenharmony_ci		} else {
79562306a36Sopenharmony_ci			emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
79662306a36Sopenharmony_ci			emit(hppa_sub(rd, HPPA_REG_T1, rd), ctx);
79762306a36Sopenharmony_ci		}
79862306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
79962306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_K:
80262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_K:
80362306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
80462306a36Sopenharmony_ci                emit(hppa_and(rd, HPPA_REG_T1, rd), ctx);
80562306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
80662306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_K:
80962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_K:
81062306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
81162306a36Sopenharmony_ci                emit(hppa_or(rd, HPPA_REG_T1, rd), ctx);
81262306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
81362306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
81462306a36Sopenharmony_ci		break;
81562306a36Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_K:
81662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_K:
81762306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
81862306a36Sopenharmony_ci                emit(hppa_xor(rd, HPPA_REG_T1, rd), ctx);
81962306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
82062306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
82162306a36Sopenharmony_ci		break;
82262306a36Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_K:
82362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_K:
82462306a36Sopenharmony_ci		if (imm != 0) {
82562306a36Sopenharmony_ci			emit_hppa64_shld(rd, imm, rd, ctx);
82662306a36Sopenharmony_ci		}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
82962306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
83062306a36Sopenharmony_ci		break;
83162306a36Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_K:
83262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_K:
83362306a36Sopenharmony_ci		if (imm != 0) {
83462306a36Sopenharmony_ci			if (is64)
83562306a36Sopenharmony_ci				emit_hppa64_shrd(rd, imm, rd, false, ctx);
83662306a36Sopenharmony_ci			else
83762306a36Sopenharmony_ci				emit_hppa64_shrw(rd, imm, rd, false, ctx);
83862306a36Sopenharmony_ci		}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
84162306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
84262306a36Sopenharmony_ci		break;
84362306a36Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_K:
84462306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_K:
84562306a36Sopenharmony_ci		if (imm != 0) {
84662306a36Sopenharmony_ci			if (is64)
84762306a36Sopenharmony_ci				emit_hppa64_shrd(rd, imm, rd, true, ctx);
84862306a36Sopenharmony_ci			else
84962306a36Sopenharmony_ci				emit_hppa64_shrw(rd, imm, rd, true, ctx);
85062306a36Sopenharmony_ci		}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		if (!is64 && !aux->verifier_zext)
85362306a36Sopenharmony_ci			emit_zext_32(rd, ctx);
85462306a36Sopenharmony_ci		break;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	/* JUMP off */
85762306a36Sopenharmony_ci	case BPF_JMP | BPF_JA:
85862306a36Sopenharmony_ci		paoff = hppa_offset(i, off, ctx);
85962306a36Sopenharmony_ci		ret = emit_jump(paoff, false, ctx);
86062306a36Sopenharmony_ci		if (ret)
86162306a36Sopenharmony_ci			return ret;
86262306a36Sopenharmony_ci		break;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	/* IF (dst COND src) JUMP off */
86562306a36Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_X:
86662306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JEQ | BPF_X:
86762306a36Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_X:
86862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGT | BPF_X:
86962306a36Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_X:
87062306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLT | BPF_X:
87162306a36Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_X:
87262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGE | BPF_X:
87362306a36Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_X:
87462306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLE | BPF_X:
87562306a36Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_X:
87662306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JNE | BPF_X:
87762306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_X:
87862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGT | BPF_X:
87962306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_X:
88062306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLT | BPF_X:
88162306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_X:
88262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGE | BPF_X:
88362306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_X:
88462306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLE | BPF_X:
88562306a36Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_X:
88662306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSET | BPF_X:
88762306a36Sopenharmony_ci		paoff = hppa_offset(i, off, ctx);
88862306a36Sopenharmony_ci		if (!is64) {
88962306a36Sopenharmony_ci			s = ctx->ninsns;
89062306a36Sopenharmony_ci			if (is_signed_bpf_cond(BPF_OP(code)))
89162306a36Sopenharmony_ci				emit_sext_32_rd_rs(&rd, &rs, ctx);
89262306a36Sopenharmony_ci			else
89362306a36Sopenharmony_ci				emit_zext_32_rd_rs(&rd, &rs, ctx);
89462306a36Sopenharmony_ci			e = ctx->ninsns;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci			/* Adjust for extra insns */
89762306a36Sopenharmony_ci			paoff -= (e - s);
89862306a36Sopenharmony_ci		}
89962306a36Sopenharmony_ci		if (BPF_OP(code) == BPF_JSET) {
90062306a36Sopenharmony_ci			/* Adjust for and */
90162306a36Sopenharmony_ci			paoff -= 1;
90262306a36Sopenharmony_ci			emit(hppa_and(rs, rd, HPPA_REG_T1), ctx);
90362306a36Sopenharmony_ci			emit_branch(BPF_JNE, HPPA_REG_T1, HPPA_REG_ZERO, paoff,
90462306a36Sopenharmony_ci				    ctx);
90562306a36Sopenharmony_ci		} else {
90662306a36Sopenharmony_ci			emit_branch(BPF_OP(code), rd, rs, paoff, ctx);
90762306a36Sopenharmony_ci		}
90862306a36Sopenharmony_ci		break;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* IF (dst COND imm) JUMP off */
91162306a36Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_K:
91262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JEQ | BPF_K:
91362306a36Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_K:
91462306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGT | BPF_K:
91562306a36Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_K:
91662306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLT | BPF_K:
91762306a36Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_K:
91862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGE | BPF_K:
91962306a36Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_K:
92062306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLE | BPF_K:
92162306a36Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_K:
92262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JNE | BPF_K:
92362306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_K:
92462306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGT | BPF_K:
92562306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_K:
92662306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLT | BPF_K:
92762306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_K:
92862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGE | BPF_K:
92962306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_K:
93062306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLE | BPF_K:
93162306a36Sopenharmony_ci		paoff = hppa_offset(i, off, ctx);
93262306a36Sopenharmony_ci		s = ctx->ninsns;
93362306a36Sopenharmony_ci		if (imm) {
93462306a36Sopenharmony_ci			emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
93562306a36Sopenharmony_ci			rs = HPPA_REG_T1;
93662306a36Sopenharmony_ci		} else {
93762306a36Sopenharmony_ci			rs = HPPA_REG_ZERO;
93862306a36Sopenharmony_ci		}
93962306a36Sopenharmony_ci		if (!is64) {
94062306a36Sopenharmony_ci			if (is_signed_bpf_cond(BPF_OP(code)))
94162306a36Sopenharmony_ci				emit_sext_32_rd(&rd, ctx);
94262306a36Sopenharmony_ci			else
94362306a36Sopenharmony_ci				emit_zext_32_rd_t1(&rd, ctx);
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci		e = ctx->ninsns;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		/* Adjust for extra insns */
94862306a36Sopenharmony_ci		paoff -= (e - s);
94962306a36Sopenharmony_ci		emit_branch(BPF_OP(code), rd, rs, paoff, ctx);
95062306a36Sopenharmony_ci		break;
95162306a36Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_K:
95262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSET | BPF_K:
95362306a36Sopenharmony_ci		paoff = hppa_offset(i, off, ctx);
95462306a36Sopenharmony_ci		s = ctx->ninsns;
95562306a36Sopenharmony_ci		emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
95662306a36Sopenharmony_ci		emit(hppa_and(HPPA_REG_T1, rd, HPPA_REG_T1), ctx);
95762306a36Sopenharmony_ci		/* For jset32, we should clear the upper 32 bits of t1, but
95862306a36Sopenharmony_ci		 * sign-extension is sufficient here and saves one instruction,
95962306a36Sopenharmony_ci		 * as t1 is used only in comparison against zero.
96062306a36Sopenharmony_ci		 */
96162306a36Sopenharmony_ci		if (!is64 && imm < 0)
96262306a36Sopenharmony_ci			emit_hppa64_sext32(HPPA_REG_T1, HPPA_REG_T1, ctx);
96362306a36Sopenharmony_ci		e = ctx->ninsns;
96462306a36Sopenharmony_ci		paoff -= (e - s);
96562306a36Sopenharmony_ci		emit_branch(BPF_JNE, HPPA_REG_T1, HPPA_REG_ZERO, paoff, ctx);
96662306a36Sopenharmony_ci		break;
96762306a36Sopenharmony_ci	/* function call */
96862306a36Sopenharmony_ci	case BPF_JMP | BPF_CALL:
96962306a36Sopenharmony_ci	{
97062306a36Sopenharmony_ci		bool fixed_addr;
97162306a36Sopenharmony_ci		u64 addr;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
97462306a36Sopenharmony_ci					    &addr, &fixed_addr);
97562306a36Sopenharmony_ci		if (ret < 0)
97662306a36Sopenharmony_ci			return ret;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		REG_SET_SEEN_ALL(ctx);
97962306a36Sopenharmony_ci		emit_call(addr, fixed_addr, ctx);
98062306a36Sopenharmony_ci		break;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci	/* tail call */
98362306a36Sopenharmony_ci	case BPF_JMP | BPF_TAIL_CALL:
98462306a36Sopenharmony_ci		emit_bpf_tail_call(i, ctx);
98562306a36Sopenharmony_ci		break;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* function return */
98862306a36Sopenharmony_ci	case BPF_JMP | BPF_EXIT:
98962306a36Sopenharmony_ci		if (i == ctx->prog->len - 1)
99062306a36Sopenharmony_ci			break;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		paoff = epilogue_offset(ctx);
99362306a36Sopenharmony_ci		ret = emit_jump(paoff, false, ctx);
99462306a36Sopenharmony_ci		if (ret)
99562306a36Sopenharmony_ci			return ret;
99662306a36Sopenharmony_ci		break;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	/* dst = imm64 */
99962306a36Sopenharmony_ci	case BPF_LD | BPF_IMM | BPF_DW:
100062306a36Sopenharmony_ci	{
100162306a36Sopenharmony_ci		struct bpf_insn insn1 = insn[1];
100262306a36Sopenharmony_ci		u64 imm64 = (u64)insn1.imm << 32 | (u32)imm;
100362306a36Sopenharmony_ci		if (bpf_pseudo_func(insn))
100462306a36Sopenharmony_ci			imm64 = (uintptr_t)dereference_function_descriptor((void*)imm64);
100562306a36Sopenharmony_ci		emit_imm(rd, imm64, HPPA_REG_T2, ctx);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		return 1;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* LDX: dst = *(size *)(src + off) */
101162306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_B:
101262306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_H:
101362306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_W:
101462306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_DW:
101562306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_B:
101662306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_H:
101762306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_W:
101862306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
101962306a36Sopenharmony_ci	{
102062306a36Sopenharmony_ci		u8 srcreg;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci		/* need to calculate address since offset does not fit in 14 bits? */
102362306a36Sopenharmony_ci		if (relative_bits_ok(off, 14))
102462306a36Sopenharmony_ci			srcreg = rs;
102562306a36Sopenharmony_ci		else {
102662306a36Sopenharmony_ci			/* need to use R1 here, since addil puts result into R1 */
102762306a36Sopenharmony_ci			srcreg = HPPA_REG_R1;
102862306a36Sopenharmony_ci			BUG_ON(rs == HPPA_REG_R1);
102962306a36Sopenharmony_ci			BUG_ON(rd == HPPA_REG_R1);
103062306a36Sopenharmony_ci			emit(hppa_addil(off, rs), ctx);
103162306a36Sopenharmony_ci			off = im11(off);
103262306a36Sopenharmony_ci		}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci		switch (BPF_SIZE(code)) {
103562306a36Sopenharmony_ci		case BPF_B:
103662306a36Sopenharmony_ci			emit(hppa_ldb(off, srcreg, rd), ctx);
103762306a36Sopenharmony_ci			if (insn_is_zext(&insn[1]))
103862306a36Sopenharmony_ci				return 1;
103962306a36Sopenharmony_ci			break;
104062306a36Sopenharmony_ci		case BPF_H:
104162306a36Sopenharmony_ci			emit(hppa_ldh(off, srcreg, rd), ctx);
104262306a36Sopenharmony_ci			if (insn_is_zext(&insn[1]))
104362306a36Sopenharmony_ci				return 1;
104462306a36Sopenharmony_ci			break;
104562306a36Sopenharmony_ci		case BPF_W:
104662306a36Sopenharmony_ci			emit(hppa_ldw(off, srcreg, rd), ctx);
104762306a36Sopenharmony_ci			if (insn_is_zext(&insn[1]))
104862306a36Sopenharmony_ci				return 1;
104962306a36Sopenharmony_ci			break;
105062306a36Sopenharmony_ci		case BPF_DW:
105162306a36Sopenharmony_ci			if (off & 7) {
105262306a36Sopenharmony_ci				emit(hppa_ldo(off, srcreg, HPPA_REG_R1), ctx);
105362306a36Sopenharmony_ci				emit(hppa64_ldd_reg(HPPA_REG_ZERO, HPPA_REG_R1, rd), ctx);
105462306a36Sopenharmony_ci			} else if (off >= -16 && off <= 15)
105562306a36Sopenharmony_ci				emit(hppa64_ldd_im5(off, srcreg, rd), ctx);
105662306a36Sopenharmony_ci			else
105762306a36Sopenharmony_ci				emit(hppa64_ldd_im16(off, srcreg, rd), ctx);
105862306a36Sopenharmony_ci			break;
105962306a36Sopenharmony_ci		}
106062306a36Sopenharmony_ci		break;
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci	/* speculation barrier */
106362306a36Sopenharmony_ci	case BPF_ST | BPF_NOSPEC:
106462306a36Sopenharmony_ci		break;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/* ST: *(size *)(dst + off) = imm */
106762306a36Sopenharmony_ci	/* STX: *(size *)(dst + off) = src */
106862306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_B:
106962306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_H:
107062306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_W:
107162306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_DW:
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_B:
107462306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_H:
107562306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_W:
107662306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_DW:
107762306a36Sopenharmony_ci		if (BPF_CLASS(code) == BPF_ST) {
107862306a36Sopenharmony_ci			emit_imm(HPPA_REG_T2, imm, HPPA_REG_T1, ctx);
107962306a36Sopenharmony_ci			rs = HPPA_REG_T2;
108062306a36Sopenharmony_ci		}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci		emit_store(rd, rs, off, ctx, BPF_SIZE(code), BPF_MODE(code));
108362306a36Sopenharmony_ci		break;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	case BPF_STX | BPF_ATOMIC | BPF_W:
108662306a36Sopenharmony_ci	case BPF_STX | BPF_ATOMIC | BPF_DW:
108762306a36Sopenharmony_ci		pr_info_once(
108862306a36Sopenharmony_ci			"bpf-jit: not supported: atomic operation %02x ***\n",
108962306a36Sopenharmony_ci			insn->imm);
109062306a36Sopenharmony_ci		return -EFAULT;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	default:
109362306a36Sopenharmony_ci		pr_err("bpf-jit: unknown opcode %02x\n", code);
109462306a36Sopenharmony_ci		return -EINVAL;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	return 0;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_civoid bpf_jit_build_prologue(struct hppa_jit_context *ctx)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	int bpf_stack_adjust, stack_adjust, i;
110362306a36Sopenharmony_ci	unsigned long addr;
110462306a36Sopenharmony_ci	s8 reg;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	/*
110762306a36Sopenharmony_ci	 * stack on hppa grows up, so if tail calls are used we need to
110862306a36Sopenharmony_ci	 * allocate the maximum stack size
110962306a36Sopenharmony_ci	 */
111062306a36Sopenharmony_ci	if (REG_ALL_SEEN(ctx))
111162306a36Sopenharmony_ci		bpf_stack_adjust = MAX_BPF_STACK;
111262306a36Sopenharmony_ci	else
111362306a36Sopenharmony_ci		bpf_stack_adjust = ctx->prog->aux->stack_depth;
111462306a36Sopenharmony_ci	bpf_stack_adjust = round_up(bpf_stack_adjust, STACK_ALIGN);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	stack_adjust = FRAME_SIZE + bpf_stack_adjust;
111762306a36Sopenharmony_ci	stack_adjust = round_up(stack_adjust, STACK_ALIGN);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	/*
112062306a36Sopenharmony_ci	 * NOTE: We construct an Elf64_Fdesc descriptor here.
112162306a36Sopenharmony_ci	 * The first 4 words initialize the TCC and compares them.
112262306a36Sopenharmony_ci	 * Then follows the virtual address of the eBPF function,
112362306a36Sopenharmony_ci	 * and the gp for this function.
112462306a36Sopenharmony_ci	 *
112562306a36Sopenharmony_ci	 * The first instruction sets the tail-call-counter (TCC) register.
112662306a36Sopenharmony_ci	 * This instruction is skipped by tail calls.
112762306a36Sopenharmony_ci	 * Use a temporary register instead of a caller-saved register initially.
112862306a36Sopenharmony_ci	 */
112962306a36Sopenharmony_ci	REG_FORCE_SEEN(ctx, HPPA_REG_TCC_IN_INIT);
113062306a36Sopenharmony_ci	emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC_IN_INIT), ctx);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	/*
113362306a36Sopenharmony_ci	 * Skip all initializations when called as BPF TAIL call.
113462306a36Sopenharmony_ci	 */
113562306a36Sopenharmony_ci	emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_R1), ctx);
113662306a36Sopenharmony_ci	emit(hppa_beq(HPPA_REG_TCC_IN_INIT, HPPA_REG_R1, 6 - HPPA_BRANCH_DISPLACEMENT), ctx);
113762306a36Sopenharmony_ci	emit(hppa64_bl_long(ctx->prologue_len - 3 - HPPA_BRANCH_DISPLACEMENT), ctx);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/* store entry address of this eBPF function */
114062306a36Sopenharmony_ci	addr = (uintptr_t) &ctx->insns[0];
114162306a36Sopenharmony_ci	emit(addr >> 32, ctx);
114262306a36Sopenharmony_ci	emit(addr & 0xffffffff, ctx);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	/* store gp of this eBPF function */
114562306a36Sopenharmony_ci	asm("copy %%r27,%0" : "=r" (addr) );
114662306a36Sopenharmony_ci	emit(addr >> 32, ctx);
114762306a36Sopenharmony_ci	emit(addr & 0xffffffff, ctx);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	/* Set up hppa stack frame. */
115062306a36Sopenharmony_ci	emit_hppa_copy(HPPA_REG_SP, HPPA_REG_R1, ctx);
115162306a36Sopenharmony_ci	emit(hppa_ldo(stack_adjust, HPPA_REG_SP, HPPA_REG_SP), ctx);
115262306a36Sopenharmony_ci	emit(hppa64_std_im5 (HPPA_REG_R1, -REG_SIZE, HPPA_REG_SP), ctx);
115362306a36Sopenharmony_ci	emit(hppa64_std_im16(HPPA_REG_RP, -2*REG_SIZE, HPPA_REG_SP), ctx);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/* Save callee-save registers. */
115662306a36Sopenharmony_ci	for (i = 3; i <= 15; i++) {
115762306a36Sopenharmony_ci		if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i)))
115862306a36Sopenharmony_ci			continue;
115962306a36Sopenharmony_ci		emit(hppa64_std_im16(HPPA_R(i), -REG_SIZE * i, HPPA_REG_SP), ctx);
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	/* load function parameters; load all if we use tail functions */
116362306a36Sopenharmony_ci	#define LOAD_PARAM(arg, dst) \
116462306a36Sopenharmony_ci		if (REG_WAS_SEEN(ctx, regmap[dst]) ||	\
116562306a36Sopenharmony_ci		    REG_WAS_SEEN(ctx, HPPA_REG_TCC))	\
116662306a36Sopenharmony_ci			emit_hppa_copy(arg, regmap[dst], ctx)
116762306a36Sopenharmony_ci	LOAD_PARAM(HPPA_REG_ARG0, BPF_REG_1);
116862306a36Sopenharmony_ci	LOAD_PARAM(HPPA_REG_ARG1, BPF_REG_2);
116962306a36Sopenharmony_ci	LOAD_PARAM(HPPA_REG_ARG2, BPF_REG_3);
117062306a36Sopenharmony_ci	LOAD_PARAM(HPPA_REG_ARG3, BPF_REG_4);
117162306a36Sopenharmony_ci	LOAD_PARAM(HPPA_REG_ARG4, BPF_REG_5);
117262306a36Sopenharmony_ci	#undef LOAD_PARAM
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	REG_FORCE_SEEN(ctx, HPPA_REG_T0);
117562306a36Sopenharmony_ci	REG_FORCE_SEEN(ctx, HPPA_REG_T1);
117662306a36Sopenharmony_ci	REG_FORCE_SEEN(ctx, HPPA_REG_T2);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	/*
117962306a36Sopenharmony_ci	 * Now really set the tail call counter (TCC) register.
118062306a36Sopenharmony_ci	 */
118162306a36Sopenharmony_ci	if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
118262306a36Sopenharmony_ci		emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC), ctx);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	/*
118562306a36Sopenharmony_ci	 * Save epilogue function pointer for outer TCC call chain.
118662306a36Sopenharmony_ci	 * The main TCC call stores the final RP on stack.
118762306a36Sopenharmony_ci	 */
118862306a36Sopenharmony_ci	addr = (uintptr_t) &ctx->insns[ctx->epilogue_offset];
118962306a36Sopenharmony_ci	/* skip first two instructions which jump to exit */
119062306a36Sopenharmony_ci	addr += 2 * HPPA_INSN_SIZE;
119162306a36Sopenharmony_ci	emit_imm(HPPA_REG_T2, addr, HPPA_REG_T1, ctx);
119262306a36Sopenharmony_ci	emit(EXIT_PTR_STORE(HPPA_REG_T2), ctx);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/* Set up BPF frame pointer. */
119562306a36Sopenharmony_ci	reg = regmap[BPF_REG_FP];	/* -> HPPA_REG_FP */
119662306a36Sopenharmony_ci	if (REG_WAS_SEEN(ctx, reg)) {
119762306a36Sopenharmony_ci		emit(hppa_ldo(-FRAME_SIZE, HPPA_REG_SP, reg), ctx);
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_civoid bpf_jit_build_epilogue(struct hppa_jit_context *ctx)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	__build_epilogue(false, ctx);
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cibool bpf_jit_supports_kfunc_call(void)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	return true;
120962306a36Sopenharmony_ci}
1210