18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * BPF JIT compiler for LoongArch
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2021 Loongson Technology Corporation Limited
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include "ebpf_jit.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define TMP_REG_1       (MAX_BPF_JIT_REG + 0)
108c2ecf20Sopenharmony_ci#define TMP_REG_2       (MAX_BPF_JIT_REG + 1)
118c2ecf20Sopenharmony_ci#define TMP_REG_3       (MAX_BPF_JIT_REG + 2)
128c2ecf20Sopenharmony_ci#define REG_TCC         (MAX_BPF_JIT_REG + 3)
138c2ecf20Sopenharmony_ci#define TCC_SAVED       (MAX_BPF_JIT_REG + 4)
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define SAVE_RA         BIT(0)
168c2ecf20Sopenharmony_ci#define SAVE_TCC        BIT(1)
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic const int regmap[] = {
198c2ecf20Sopenharmony_ci	/* return value from in-kernel function, and exit value for eBPF program */
208c2ecf20Sopenharmony_ci	[BPF_REG_0] = LOONGARCH_GPR_A5,
218c2ecf20Sopenharmony_ci	/* arguments from eBPF program to in-kernel function */
228c2ecf20Sopenharmony_ci	[BPF_REG_1] = LOONGARCH_GPR_A0,
238c2ecf20Sopenharmony_ci	[BPF_REG_2] = LOONGARCH_GPR_A1,
248c2ecf20Sopenharmony_ci	[BPF_REG_3] = LOONGARCH_GPR_A2,
258c2ecf20Sopenharmony_ci	[BPF_REG_4] = LOONGARCH_GPR_A3,
268c2ecf20Sopenharmony_ci	[BPF_REG_5] = LOONGARCH_GPR_A4,
278c2ecf20Sopenharmony_ci	/* callee saved registers that in-kernel function will preserve */
288c2ecf20Sopenharmony_ci	[BPF_REG_6] = LOONGARCH_GPR_S0,
298c2ecf20Sopenharmony_ci	[BPF_REG_7] = LOONGARCH_GPR_S1,
308c2ecf20Sopenharmony_ci	[BPF_REG_8] = LOONGARCH_GPR_S2,
318c2ecf20Sopenharmony_ci	[BPF_REG_9] = LOONGARCH_GPR_S3,
328c2ecf20Sopenharmony_ci	/* read-only frame pointer to access stack */
338c2ecf20Sopenharmony_ci	[BPF_REG_FP] = LOONGARCH_GPR_S4,
348c2ecf20Sopenharmony_ci	/* temporary register for blinding constants */
358c2ecf20Sopenharmony_ci	[BPF_REG_AX] = LOONGARCH_GPR_T0,
368c2ecf20Sopenharmony_ci	/* temporary register for internal BPF JIT */
378c2ecf20Sopenharmony_ci	[TMP_REG_1] = LOONGARCH_GPR_T1,
388c2ecf20Sopenharmony_ci	[TMP_REG_2] = LOONGARCH_GPR_T2,
398c2ecf20Sopenharmony_ci	[TMP_REG_3] = LOONGARCH_GPR_T3,
408c2ecf20Sopenharmony_ci	/* tail call */
418c2ecf20Sopenharmony_ci	[REG_TCC] = LOONGARCH_GPR_A6,
428c2ecf20Sopenharmony_ci	/* store A6 in S5 if program do calls */
438c2ecf20Sopenharmony_ci	[TCC_SAVED] = LOONGARCH_GPR_S5,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void mark_call(struct jit_ctx *ctx)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	ctx->flags |= SAVE_RA;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void mark_tail_call(struct jit_ctx *ctx)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	ctx->flags |= SAVE_TCC;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic bool seen_call(struct jit_ctx *ctx)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	return (ctx->flags & SAVE_RA);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic bool seen_tail_call(struct jit_ctx *ctx)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return (ctx->flags & SAVE_TCC);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic u8 tail_call_reg(struct jit_ctx *ctx)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	if (seen_call(ctx))
698c2ecf20Sopenharmony_ci		return regmap[TCC_SAVED];
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return regmap[REG_TCC];
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/*
758c2ecf20Sopenharmony_ci * eBPF prog stack layout:
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci *                                        high
788c2ecf20Sopenharmony_ci * original $sp ------------> +-------------------------+ <--LOONGARCH_GPR_FP
798c2ecf20Sopenharmony_ci *                            |           $ra           |
808c2ecf20Sopenharmony_ci *                            +-------------------------+
818c2ecf20Sopenharmony_ci *                            |           $fp           |
828c2ecf20Sopenharmony_ci *                            +-------------------------+
838c2ecf20Sopenharmony_ci *                            |           $s0           |
848c2ecf20Sopenharmony_ci *                            +-------------------------+
858c2ecf20Sopenharmony_ci *                            |           $s1           |
868c2ecf20Sopenharmony_ci *                            +-------------------------+
878c2ecf20Sopenharmony_ci *                            |           $s2           |
888c2ecf20Sopenharmony_ci *                            +-------------------------+
898c2ecf20Sopenharmony_ci *                            |           $s3           |
908c2ecf20Sopenharmony_ci *                            +-------------------------+
918c2ecf20Sopenharmony_ci *                            |           $s4           |
928c2ecf20Sopenharmony_ci *                            +-------------------------+
938c2ecf20Sopenharmony_ci *                            |           $s5           |
948c2ecf20Sopenharmony_ci *                            +-------------------------+ <--BPF_REG_FP
958c2ecf20Sopenharmony_ci *                            |  prog->aux->stack_depth |
968c2ecf20Sopenharmony_ci *                            |        (optional)       |
978c2ecf20Sopenharmony_ci * current $sp -------------> +-------------------------+
988c2ecf20Sopenharmony_ci *                                        low
998c2ecf20Sopenharmony_ci */
1008c2ecf20Sopenharmony_cistatic void build_prologue(struct jit_ctx *ctx)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int stack_adjust = 0, store_offset, bpf_stack_adjust;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_RA */
1078c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_FP */
1088c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_S0 */
1098c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_S1 */
1108c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_S2 */
1118c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_S3 */
1128c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_S4 */
1138c2ecf20Sopenharmony_ci	stack_adjust += sizeof(long); /* LOONGARCH_GPR_S5 */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	stack_adjust = round_up(stack_adjust, 16);
1168c2ecf20Sopenharmony_ci	stack_adjust += bpf_stack_adjust;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * First instruction initializes the tail call count (TCC).
1208c2ecf20Sopenharmony_ci	 * On tail call we skip this instruction, and the TCC is
1218c2ecf20Sopenharmony_ci	 * passed in REG_TCC from the caller.
1228c2ecf20Sopenharmony_ci	 */
1238c2ecf20Sopenharmony_ci	emit_insn(ctx, addid, regmap[REG_TCC], LOONGARCH_GPR_ZERO, MAX_TAIL_CALL_CNT);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, -stack_adjust);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	store_offset = stack_adjust - sizeof(long);
1288c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_RA, LOONGARCH_GPR_SP, store_offset);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1318c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_FP, LOONGARCH_GPR_SP, store_offset);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1348c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_S0, LOONGARCH_GPR_SP, store_offset);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1378c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_S1, LOONGARCH_GPR_SP, store_offset);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1408c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_S2, LOONGARCH_GPR_SP, store_offset);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1438c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_S3, LOONGARCH_GPR_SP, store_offset);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1468c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_S4, LOONGARCH_GPR_SP, store_offset);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	store_offset -= sizeof(long);
1498c2ecf20Sopenharmony_ci	emit_insn(ctx, std, LOONGARCH_GPR_S5, LOONGARCH_GPR_SP, store_offset);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	emit_insn(ctx, addid, LOONGARCH_GPR_FP, LOONGARCH_GPR_SP, stack_adjust);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (bpf_stack_adjust)
1548c2ecf20Sopenharmony_ci		emit_insn(ctx, addid, regmap[BPF_REG_FP], LOONGARCH_GPR_SP, bpf_stack_adjust);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/*
1578c2ecf20Sopenharmony_ci	 * Program contains calls and tail calls, so REG_TCC need
1588c2ecf20Sopenharmony_ci	 * to be saved across calls.
1598c2ecf20Sopenharmony_ci	 */
1608c2ecf20Sopenharmony_ci	if (seen_tail_call(ctx) && seen_call(ctx))
1618c2ecf20Sopenharmony_ci		move_reg(ctx, regmap[TCC_SAVED], regmap[REG_TCC]);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	ctx->stack_size = stack_adjust;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	int stack_adjust = ctx->stack_size;
1698c2ecf20Sopenharmony_ci	int load_offset;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	load_offset = stack_adjust - sizeof(long);
1728c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_RA, LOONGARCH_GPR_SP, load_offset);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1758c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_FP, LOONGARCH_GPR_SP, load_offset);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1788c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_S0, LOONGARCH_GPR_SP, load_offset);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1818c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_S1, LOONGARCH_GPR_SP, load_offset);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1848c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_S2, LOONGARCH_GPR_SP, load_offset);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1878c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_S3, LOONGARCH_GPR_SP, load_offset);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1908c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_S4, LOONGARCH_GPR_SP, load_offset);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	load_offset -= sizeof(long);
1938c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, LOONGARCH_GPR_S5, LOONGARCH_GPR_SP, load_offset);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, stack_adjust);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (!is_tail_call) {
1988c2ecf20Sopenharmony_ci		/* Set return value */
1998c2ecf20Sopenharmony_ci		move_reg(ctx, LOONGARCH_GPR_A0, regmap[BPF_REG_0]);
2008c2ecf20Sopenharmony_ci		/* Return to the caller */
2018c2ecf20Sopenharmony_ci		emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_RA, 0);
2028c2ecf20Sopenharmony_ci	} else {
2038c2ecf20Sopenharmony_ci		/*
2048c2ecf20Sopenharmony_ci		 * Call the next bpf prog and skip the first instruction
2058c2ecf20Sopenharmony_ci		 * of TCC initialization.
2068c2ecf20Sopenharmony_ci		 */
2078c2ecf20Sopenharmony_ci		emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, regmap[TMP_REG_3], 1);
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_civoid build_epilogue(struct jit_ctx *ctx)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	__build_epilogue(ctx, false);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/* initialized on the first pass of build_body() */
2178c2ecf20Sopenharmony_cistatic int out_offset = -1;
2188c2ecf20Sopenharmony_cistatic int emit_bpf_tail_call(struct jit_ctx *ctx)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	int off;
2218c2ecf20Sopenharmony_ci	u8 tcc = tail_call_reg(ctx);
2228c2ecf20Sopenharmony_ci	u8 a1 = LOONGARCH_GPR_A1;
2238c2ecf20Sopenharmony_ci	u8 a2 = LOONGARCH_GPR_A2;
2248c2ecf20Sopenharmony_ci	u8 tmp1 = regmap[TMP_REG_1];
2258c2ecf20Sopenharmony_ci	u8 tmp2 = regmap[TMP_REG_2];
2268c2ecf20Sopenharmony_ci	u8 tmp3 = regmap[TMP_REG_3];
2278c2ecf20Sopenharmony_ci	const int idx0 = ctx->idx;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci#define cur_offset (ctx->idx - idx0)
2308c2ecf20Sopenharmony_ci#define jmp_offset (out_offset - (cur_offset))
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/*
2338c2ecf20Sopenharmony_ci	 * a0: &ctx
2348c2ecf20Sopenharmony_ci	 * a1: &array
2358c2ecf20Sopenharmony_ci	 * a2: index
2368c2ecf20Sopenharmony_ci	 *
2378c2ecf20Sopenharmony_ci	 * if (index >= array->map.max_entries)
2388c2ecf20Sopenharmony_ci	 *	 goto out;
2398c2ecf20Sopenharmony_ci	 */
2408c2ecf20Sopenharmony_ci	off = offsetof(struct bpf_array, map.max_entries);
2418c2ecf20Sopenharmony_ci	emit_insn(ctx, ldwu, tmp1, a1, off);
2428c2ecf20Sopenharmony_ci	/* bgeu $a2, $t1, jmp_offset */
2438c2ecf20Sopenharmony_ci	emit_tailcall_jump(ctx, BPF_JGE, a2, tmp1, jmp_offset);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/*
2468c2ecf20Sopenharmony_ci	 * if (TCC-- < 0)
2478c2ecf20Sopenharmony_ci	 *	 goto out;
2488c2ecf20Sopenharmony_ci	 */
2498c2ecf20Sopenharmony_ci	emit_insn(ctx, addid, tmp1, tcc, -1);
2508c2ecf20Sopenharmony_ci	emit_tailcall_jump(ctx, BPF_JSLT, tcc, LOONGARCH_GPR_ZERO, jmp_offset);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/*
2538c2ecf20Sopenharmony_ci	 * prog = array->ptrs[index];
2548c2ecf20Sopenharmony_ci	 * if (!prog)
2558c2ecf20Sopenharmony_ci	 *	 goto out;
2568c2ecf20Sopenharmony_ci	 */
2578c2ecf20Sopenharmony_ci	emit_insn(ctx, sllid, tmp2, a2, 3);
2588c2ecf20Sopenharmony_ci	emit_insn(ctx, addd, tmp2, tmp2, a1);
2598c2ecf20Sopenharmony_ci	off = offsetof(struct bpf_array, ptrs);
2608c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, tmp2, tmp2, off);
2618c2ecf20Sopenharmony_ci	/* beq $t2, $zero, jmp_offset */
2628c2ecf20Sopenharmony_ci	emit_tailcall_jump(ctx, BPF_JEQ, tmp2, LOONGARCH_GPR_ZERO, jmp_offset);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/* goto *(prog->bpf_func + 4); */
2658c2ecf20Sopenharmony_ci	off = offsetof(struct bpf_prog, bpf_func);
2668c2ecf20Sopenharmony_ci	emit_insn(ctx, ldd, tmp3, tmp2, off);
2678c2ecf20Sopenharmony_ci	move_reg(ctx, tcc, tmp1);
2688c2ecf20Sopenharmony_ci	__build_epilogue(ctx, true);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/* out: */
2718c2ecf20Sopenharmony_ci	if (out_offset == -1)
2728c2ecf20Sopenharmony_ci		out_offset = cur_offset;
2738c2ecf20Sopenharmony_ci	if (cur_offset != out_offset) {
2748c2ecf20Sopenharmony_ci		pr_err_once("tail_call out_offset = %d, expected %d!\n",
2758c2ecf20Sopenharmony_ci			     cur_offset, out_offset);
2768c2ecf20Sopenharmony_ci		return -1;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	return 0;
2808c2ecf20Sopenharmony_ci#undef cur_offset
2818c2ecf20Sopenharmony_ci#undef jmp_offset
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool extra_pass)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	bool is32 = (BPF_CLASS(insn->code) == BPF_ALU);
2878c2ecf20Sopenharmony_ci	const u8 code = insn->code;
2888c2ecf20Sopenharmony_ci	const u8 cond = BPF_OP(code);
2898c2ecf20Sopenharmony_ci	const u8 dst = regmap[insn->dst_reg];
2908c2ecf20Sopenharmony_ci	const u8 src = regmap[insn->src_reg];
2918c2ecf20Sopenharmony_ci	const u8 tmp = regmap[TMP_REG_1];
2928c2ecf20Sopenharmony_ci	const u8 tmp2 = regmap[TMP_REG_2];
2938c2ecf20Sopenharmony_ci	const s16 off = insn->off;
2948c2ecf20Sopenharmony_ci	const s32 imm = insn->imm;
2958c2ecf20Sopenharmony_ci	int i = insn - ctx->prog->insnsi;
2968c2ecf20Sopenharmony_ci	int jmp_offset;
2978c2ecf20Sopenharmony_ci	bool func_addr_fixed;
2988c2ecf20Sopenharmony_ci	u64 func_addr;
2998c2ecf20Sopenharmony_ci	u64 imm64;
3008c2ecf20Sopenharmony_ci	int ret;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	switch (code) {
3038c2ecf20Sopenharmony_ci	/* dst = src */
3048c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_X:
3058c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_X:
3068c2ecf20Sopenharmony_ci		move_reg(ctx, dst, src);
3078c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3088c2ecf20Sopenharmony_ci		break;
3098c2ecf20Sopenharmony_ci	/* dst = imm */
3108c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_K:
3118c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_K:
3128c2ecf20Sopenharmony_ci		move_imm32(ctx, dst, imm, is32);
3138c2ecf20Sopenharmony_ci		break;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/* dst = dst + src */
3168c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_X:
3178c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_X:
3188c2ecf20Sopenharmony_ci		emit_insn(ctx, addd, dst, dst, src);
3198c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	/* dst = dst + imm */
3228c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_K:
3238c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_K:
3248c2ecf20Sopenharmony_ci		if (is_signed_imm12(imm)) {
3258c2ecf20Sopenharmony_ci			emit_insn(ctx, addid, dst, dst, imm);
3268c2ecf20Sopenharmony_ci		} else {
3278c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, imm, is32);
3288c2ecf20Sopenharmony_ci			emit_insn(ctx, addd, dst, dst, tmp);
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3318c2ecf20Sopenharmony_ci		break;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* dst = dst - src */
3348c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_X:
3358c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_X:
3368c2ecf20Sopenharmony_ci		emit_insn(ctx, subd, dst, dst, src);
3378c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	/* dst = dst - imm */
3408c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_K:
3418c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_K:
3428c2ecf20Sopenharmony_ci		if (is_signed_imm12(-imm)) {
3438c2ecf20Sopenharmony_ci			emit_insn(ctx, addid, dst, dst, -imm);
3448c2ecf20Sopenharmony_ci		} else {
3458c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, imm, is32);
3468c2ecf20Sopenharmony_ci			emit_insn(ctx, subd, dst, dst, tmp);
3478c2ecf20Sopenharmony_ci		}
3488c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3498c2ecf20Sopenharmony_ci		break;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* dst = dst * src */
3528c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_X:
3538c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_X:
3548c2ecf20Sopenharmony_ci		emit_insn(ctx, muld, dst, dst, src);
3558c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3568c2ecf20Sopenharmony_ci		break;
3578c2ecf20Sopenharmony_ci	/* dst = dst * imm */
3588c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_K:
3598c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_K:
3608c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
3618c2ecf20Sopenharmony_ci		emit_insn(ctx, muld, dst, dst, tmp);
3628c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3638c2ecf20Sopenharmony_ci		break;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* dst = dst / src */
3668c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_X:
3678c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_X:
3688c2ecf20Sopenharmony_ci		emit_insn(ctx, divdu, dst, dst, src);
3698c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3708c2ecf20Sopenharmony_ci		break;
3718c2ecf20Sopenharmony_ci	/* dst = dst / imm */
3728c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_K:
3738c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_K:
3748c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
3758c2ecf20Sopenharmony_ci		emit_insn(ctx, divdu, dst, dst, tmp);
3768c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3778c2ecf20Sopenharmony_ci		break;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	/* dst = dst % src */
3808c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_X:
3818c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_X:
3828c2ecf20Sopenharmony_ci		emit_insn(ctx, moddu, dst, dst, src);
3838c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3848c2ecf20Sopenharmony_ci		break;
3858c2ecf20Sopenharmony_ci	/* dst = dst % imm */
3868c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_K:
3878c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_K:
3888c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
3898c2ecf20Sopenharmony_ci		emit_insn(ctx, moddu, dst, dst, tmp);
3908c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* dst = -dst */
3948c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_NEG:
3958c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_NEG:
3968c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
3978c2ecf20Sopenharmony_ci		emit_insn(ctx, subd, dst, LOONGARCH_GPR_ZERO, dst);
3988c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
3998c2ecf20Sopenharmony_ci		break;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/* dst = dst & src */
4028c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_X:
4038c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_X:
4048c2ecf20Sopenharmony_ci		emit_insn(ctx, and, dst, dst, src);
4058c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	/* dst = dst & imm */
4088c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_K:
4098c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_K:
4108c2ecf20Sopenharmony_ci		if (is_unsigned_imm12(imm)) {
4118c2ecf20Sopenharmony_ci			emit_insn(ctx, andi, dst, dst, imm);
4128c2ecf20Sopenharmony_ci		} else {
4138c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, imm, is32);
4148c2ecf20Sopenharmony_ci			emit_insn(ctx, and, dst, dst, tmp);
4158c2ecf20Sopenharmony_ci		}
4168c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4178c2ecf20Sopenharmony_ci		break;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* dst = dst | src */
4208c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_X:
4218c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_X:
4228c2ecf20Sopenharmony_ci		emit_insn(ctx, or, dst, dst, src);
4238c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4248c2ecf20Sopenharmony_ci		break;
4258c2ecf20Sopenharmony_ci	/* dst = dst | imm */
4268c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_K:
4278c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_K:
4288c2ecf20Sopenharmony_ci		if (is_unsigned_imm12(imm)) {
4298c2ecf20Sopenharmony_ci			emit_insn(ctx, ori, dst, dst, imm);
4308c2ecf20Sopenharmony_ci		} else {
4318c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, imm, is32);
4328c2ecf20Sopenharmony_ci			emit_insn(ctx, or, dst, dst, tmp);
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4358c2ecf20Sopenharmony_ci		break;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* dst = dst ^ src */
4388c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_X:
4398c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_X:
4408c2ecf20Sopenharmony_ci		emit_insn(ctx, xor, dst, dst, src);
4418c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4428c2ecf20Sopenharmony_ci		break;
4438c2ecf20Sopenharmony_ci	/* dst = dst ^ imm */
4448c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_K:
4458c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_K:
4468c2ecf20Sopenharmony_ci		if (is_unsigned_imm12(imm)) {
4478c2ecf20Sopenharmony_ci			emit_insn(ctx, xori, dst, dst, imm);
4488c2ecf20Sopenharmony_ci		} else {
4498c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, imm, is32);
4508c2ecf20Sopenharmony_ci			emit_insn(ctx, xor, dst, dst, tmp);
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4538c2ecf20Sopenharmony_ci		break;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* dst = dst << src (logical) */
4568c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_X:
4578c2ecf20Sopenharmony_ci		emit_insn(ctx, sllw, dst, dst, src);
4588c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4598c2ecf20Sopenharmony_ci		break;
4608c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_X:
4618c2ecf20Sopenharmony_ci		emit_insn(ctx, slld, dst, dst, src);
4628c2ecf20Sopenharmony_ci		break;
4638c2ecf20Sopenharmony_ci	/* dst = dst << imm (logical) */
4648c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_K:
4658c2ecf20Sopenharmony_ci		emit_insn(ctx, slliw, dst, dst, imm);
4668c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4678c2ecf20Sopenharmony_ci		break;
4688c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_K:
4698c2ecf20Sopenharmony_ci		emit_insn(ctx, sllid, dst, dst, imm);
4708c2ecf20Sopenharmony_ci		break;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/* dst = dst >> src (logical) */
4738c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_X:
4748c2ecf20Sopenharmony_ci		emit_insn(ctx, srlw, dst, dst, src);
4758c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4768c2ecf20Sopenharmony_ci		break;
4778c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_X:
4788c2ecf20Sopenharmony_ci		emit_insn(ctx, srld, dst, dst, src);
4798c2ecf20Sopenharmony_ci		break;
4808c2ecf20Sopenharmony_ci	/* dst = dst >> imm (logical) */
4818c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_K:
4828c2ecf20Sopenharmony_ci		emit_insn(ctx, srliw, dst, dst, imm);
4838c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4848c2ecf20Sopenharmony_ci		break;
4858c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_K:
4868c2ecf20Sopenharmony_ci		emit_insn(ctx, srlid, dst, dst, imm);
4878c2ecf20Sopenharmony_ci		break;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* dst = dst >> src (arithmetic) */
4908c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_X:
4918c2ecf20Sopenharmony_ci		emit_insn(ctx, sraw, dst, dst, src);
4928c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
4938c2ecf20Sopenharmony_ci		break;
4948c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_X:
4958c2ecf20Sopenharmony_ci		emit_insn(ctx, srad, dst, dst, src);
4968c2ecf20Sopenharmony_ci		break;
4978c2ecf20Sopenharmony_ci	/* dst = dst >> imm (arithmetic) */
4988c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_K:
4998c2ecf20Sopenharmony_ci		emit_insn(ctx, sraiw, dst, dst, imm);
5008c2ecf20Sopenharmony_ci		emit_zext_32(ctx, dst, is32);
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_K:
5038c2ecf20Sopenharmony_ci		emit_insn(ctx, sraid, dst, dst, imm);
5048c2ecf20Sopenharmony_ci		break;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	/* dst = BSWAP##imm(dst) */
5078c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_LE:
5088c2ecf20Sopenharmony_ci		switch (imm) {
5098c2ecf20Sopenharmony_ci		case 16:
5108c2ecf20Sopenharmony_ci			/* zero-extend 16 bits into 64 bits */
5118c2ecf20Sopenharmony_ci			emit_insn(ctx, sllid, dst, dst, 48);
5128c2ecf20Sopenharmony_ci			emit_insn(ctx, srlid, dst, dst, 48);
5138c2ecf20Sopenharmony_ci			break;
5148c2ecf20Sopenharmony_ci		case 32:
5158c2ecf20Sopenharmony_ci			/* zero-extend 32 bits into 64 bits */
5168c2ecf20Sopenharmony_ci			emit_zext_32(ctx, dst, is32);
5178c2ecf20Sopenharmony_ci			break;
5188c2ecf20Sopenharmony_ci		case 64:
5198c2ecf20Sopenharmony_ci			/* do nothing */
5208c2ecf20Sopenharmony_ci			break;
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_BE:
5248c2ecf20Sopenharmony_ci		switch (imm) {
5258c2ecf20Sopenharmony_ci		case 16:
5268c2ecf20Sopenharmony_ci			emit_insn(ctx, revb2h, dst, dst);
5278c2ecf20Sopenharmony_ci			/* zero-extend 16 bits into 64 bits */
5288c2ecf20Sopenharmony_ci			emit_insn(ctx, sllid, dst, dst, 48);
5298c2ecf20Sopenharmony_ci			emit_insn(ctx, srlid, dst, dst, 48);
5308c2ecf20Sopenharmony_ci			break;
5318c2ecf20Sopenharmony_ci		case 32:
5328c2ecf20Sopenharmony_ci			emit_insn(ctx, revb2w, dst, dst);
5338c2ecf20Sopenharmony_ci			/* zero-extend 32 bits into 64 bits */
5348c2ecf20Sopenharmony_ci			emit_zext_32(ctx, dst, is32);
5358c2ecf20Sopenharmony_ci			break;
5368c2ecf20Sopenharmony_ci		case 64:
5378c2ecf20Sopenharmony_ci			emit_insn(ctx, revbd, dst, dst);
5388c2ecf20Sopenharmony_ci			break;
5398c2ecf20Sopenharmony_ci		}
5408c2ecf20Sopenharmony_ci		break;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	/* PC += off if dst cond src */
5438c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_X:
5448c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_X:
5458c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_X:
5468c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_X:
5478c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_X:
5488c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_X:
5498c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_X:
5508c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_X:
5518c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_X:
5528c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_X:
5538c2ecf20Sopenharmony_ci		jmp_offset = bpf2la_offset(i, off, ctx);
5548c2ecf20Sopenharmony_ci		emit_cond_jump(ctx, cond, dst, src, jmp_offset);
5558c2ecf20Sopenharmony_ci		break;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/* PC += off if dst cond imm */
5588c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_K:
5598c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_K:
5608c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_K:
5618c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_K:
5628c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_K:
5638c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_K:
5648c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_K:
5658c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_K:
5668c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_K:
5678c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_K:
5688c2ecf20Sopenharmony_ci		jmp_offset = bpf2la_offset(i, off, ctx);
5698c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
5708c2ecf20Sopenharmony_ci		emit_cond_jump(ctx, cond, dst, tmp, jmp_offset);
5718c2ecf20Sopenharmony_ci		break;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* PC += off if dst & src */
5748c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_X:
5758c2ecf20Sopenharmony_ci		jmp_offset = bpf2la_offset(i, off, ctx);
5768c2ecf20Sopenharmony_ci		emit_insn(ctx, and, tmp, dst, src);
5778c2ecf20Sopenharmony_ci		emit_cond_jump(ctx, cond, tmp, LOONGARCH_GPR_ZERO, jmp_offset);
5788c2ecf20Sopenharmony_ci		break;
5798c2ecf20Sopenharmony_ci	/* PC += off if dst & imm */
5808c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_K:
5818c2ecf20Sopenharmony_ci		jmp_offset = bpf2la_offset(i, off, ctx);
5828c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
5838c2ecf20Sopenharmony_ci		emit_insn(ctx, and, tmp, dst, tmp);
5848c2ecf20Sopenharmony_ci		emit_cond_jump(ctx, cond, tmp, LOONGARCH_GPR_ZERO, jmp_offset);
5858c2ecf20Sopenharmony_ci		break;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/* PC += off */
5888c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_JA:
5898c2ecf20Sopenharmony_ci		jmp_offset = bpf2la_offset(i, off, ctx);
5908c2ecf20Sopenharmony_ci		emit_uncond_jump(ctx, jmp_offset, false);
5918c2ecf20Sopenharmony_ci		break;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* function call */
5948c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_CALL:
5958c2ecf20Sopenharmony_ci		mark_call(ctx);
5968c2ecf20Sopenharmony_ci		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
5978c2ecf20Sopenharmony_ci					    &func_addr, &func_addr_fixed);
5988c2ecf20Sopenharmony_ci		if (ret < 0)
5998c2ecf20Sopenharmony_ci			return ret;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		move_imm64(ctx, tmp, func_addr, is32);
6028c2ecf20Sopenharmony_ci		emit_insn(ctx, jirl, LOONGARCH_GPR_RA, tmp, 0);
6038c2ecf20Sopenharmony_ci		move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_A0);
6048c2ecf20Sopenharmony_ci		break;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* tail call */
6078c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_TAIL_CALL:
6088c2ecf20Sopenharmony_ci		mark_tail_call(ctx);
6098c2ecf20Sopenharmony_ci		if (emit_bpf_tail_call(ctx))
6108c2ecf20Sopenharmony_ci			return -EINVAL;
6118c2ecf20Sopenharmony_ci		break;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	/* function return */
6148c2ecf20Sopenharmony_ci	case BPF_JMP | BPF_EXIT:
6158c2ecf20Sopenharmony_ci		emit_sext_32(ctx, regmap[BPF_REG_0]);
6168c2ecf20Sopenharmony_ci		/*
6178c2ecf20Sopenharmony_ci		 * Optimization: when last instruction is EXIT,
6188c2ecf20Sopenharmony_ci		 * simply fallthrough to epilogue.
6198c2ecf20Sopenharmony_ci		 */
6208c2ecf20Sopenharmony_ci		if (i == ctx->prog->len - 1)
6218c2ecf20Sopenharmony_ci			break;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		jmp_offset = epilogue_offset(ctx);
6248c2ecf20Sopenharmony_ci		emit_uncond_jump(ctx, jmp_offset, true);
6258c2ecf20Sopenharmony_ci		break;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/* dst = imm64 */
6288c2ecf20Sopenharmony_ci	case BPF_LD | BPF_IMM | BPF_DW:
6298c2ecf20Sopenharmony_ci		imm64 = (u64)(insn + 1)->imm << 32 | (u32)insn->imm;
6308c2ecf20Sopenharmony_ci		move_imm64(ctx, dst, imm64, is32);
6318c2ecf20Sopenharmony_ci		return 1;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	/* dst = *(size *)(src + off) */
6348c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_B:
6358c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_H:
6368c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_W:
6378c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_DW:
6388c2ecf20Sopenharmony_ci		if (is_signed_imm12(off)) {
6398c2ecf20Sopenharmony_ci			switch (BPF_SIZE(code)) {
6408c2ecf20Sopenharmony_ci			case BPF_B:
6418c2ecf20Sopenharmony_ci				emit_insn(ctx, ldbu, dst, src, off);
6428c2ecf20Sopenharmony_ci				break;
6438c2ecf20Sopenharmony_ci			case BPF_H:
6448c2ecf20Sopenharmony_ci				emit_insn(ctx, ldhu, dst, src, off);
6458c2ecf20Sopenharmony_ci				break;
6468c2ecf20Sopenharmony_ci			case BPF_W:
6478c2ecf20Sopenharmony_ci				emit_insn(ctx, ldwu, dst, src, off);
6488c2ecf20Sopenharmony_ci				break;
6498c2ecf20Sopenharmony_ci			case BPF_DW:
6508c2ecf20Sopenharmony_ci				emit_insn(ctx, ldd, dst, src, off);
6518c2ecf20Sopenharmony_ci				break;
6528c2ecf20Sopenharmony_ci			}
6538c2ecf20Sopenharmony_ci		} else {
6548c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, off, is32);
6558c2ecf20Sopenharmony_ci			switch (BPF_SIZE(code)) {
6568c2ecf20Sopenharmony_ci			case BPF_B:
6578c2ecf20Sopenharmony_ci				emit_insn(ctx, ldxbu, dst, src, tmp);
6588c2ecf20Sopenharmony_ci				break;
6598c2ecf20Sopenharmony_ci			case BPF_H:
6608c2ecf20Sopenharmony_ci				emit_insn(ctx, ldxhu, dst, src, tmp);
6618c2ecf20Sopenharmony_ci				break;
6628c2ecf20Sopenharmony_ci			case BPF_W:
6638c2ecf20Sopenharmony_ci				emit_insn(ctx, ldxwu, dst, src, tmp);
6648c2ecf20Sopenharmony_ci				break;
6658c2ecf20Sopenharmony_ci			case BPF_DW:
6668c2ecf20Sopenharmony_ci				emit_insn(ctx, ldxd, dst, src, tmp);
6678c2ecf20Sopenharmony_ci				break;
6688c2ecf20Sopenharmony_ci			}
6698c2ecf20Sopenharmony_ci		}
6708c2ecf20Sopenharmony_ci		break;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* *(size *)(dst + off) = imm */
6738c2ecf20Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_B:
6748c2ecf20Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_H:
6758c2ecf20Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_W:
6768c2ecf20Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_DW:
6778c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, imm, is32);
6788c2ecf20Sopenharmony_ci		if (is_signed_imm12(off)) {
6798c2ecf20Sopenharmony_ci			switch (BPF_SIZE(code)) {
6808c2ecf20Sopenharmony_ci			case BPF_B:
6818c2ecf20Sopenharmony_ci				emit_insn(ctx, stb, tmp, dst, off);
6828c2ecf20Sopenharmony_ci				break;
6838c2ecf20Sopenharmony_ci			case BPF_H:
6848c2ecf20Sopenharmony_ci				emit_insn(ctx, sth, tmp, dst, off);
6858c2ecf20Sopenharmony_ci				break;
6868c2ecf20Sopenharmony_ci			case BPF_W:
6878c2ecf20Sopenharmony_ci				emit_insn(ctx, stw, tmp, dst, off);
6888c2ecf20Sopenharmony_ci				break;
6898c2ecf20Sopenharmony_ci			case BPF_DW:
6908c2ecf20Sopenharmony_ci				emit_insn(ctx, std, tmp, dst, off);
6918c2ecf20Sopenharmony_ci				break;
6928c2ecf20Sopenharmony_ci			}
6938c2ecf20Sopenharmony_ci		} else {
6948c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp2, off, is32);
6958c2ecf20Sopenharmony_ci			switch (BPF_SIZE(code)) {
6968c2ecf20Sopenharmony_ci			case BPF_B:
6978c2ecf20Sopenharmony_ci				emit_insn(ctx, stxb, tmp, dst, tmp2);
6988c2ecf20Sopenharmony_ci				break;
6998c2ecf20Sopenharmony_ci			case BPF_H:
7008c2ecf20Sopenharmony_ci				emit_insn(ctx, stxh, tmp, dst, tmp2);
7018c2ecf20Sopenharmony_ci				break;
7028c2ecf20Sopenharmony_ci			case BPF_W:
7038c2ecf20Sopenharmony_ci				emit_insn(ctx, stxw, tmp, dst, tmp2);
7048c2ecf20Sopenharmony_ci				break;
7058c2ecf20Sopenharmony_ci			case BPF_DW:
7068c2ecf20Sopenharmony_ci				emit_insn(ctx, stxd, tmp, dst, tmp2);
7078c2ecf20Sopenharmony_ci				break;
7088c2ecf20Sopenharmony_ci			}
7098c2ecf20Sopenharmony_ci		}
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	/* *(size *)(dst + off) = src */
7138c2ecf20Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_B:
7148c2ecf20Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_H:
7158c2ecf20Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_W:
7168c2ecf20Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_DW:
7178c2ecf20Sopenharmony_ci		if (is_signed_imm12(off)) {
7188c2ecf20Sopenharmony_ci			switch (BPF_SIZE(code)) {
7198c2ecf20Sopenharmony_ci			case BPF_B:
7208c2ecf20Sopenharmony_ci				emit_insn(ctx, stb, src, dst, off);
7218c2ecf20Sopenharmony_ci				break;
7228c2ecf20Sopenharmony_ci			case BPF_H:
7238c2ecf20Sopenharmony_ci				emit_insn(ctx, sth, src, dst, off);
7248c2ecf20Sopenharmony_ci				break;
7258c2ecf20Sopenharmony_ci			case BPF_W:
7268c2ecf20Sopenharmony_ci				emit_insn(ctx, stw, src, dst, off);
7278c2ecf20Sopenharmony_ci				break;
7288c2ecf20Sopenharmony_ci			case BPF_DW:
7298c2ecf20Sopenharmony_ci				emit_insn(ctx, std, src, dst, off);
7308c2ecf20Sopenharmony_ci				break;
7318c2ecf20Sopenharmony_ci			}
7328c2ecf20Sopenharmony_ci		} else {
7338c2ecf20Sopenharmony_ci			move_imm32(ctx, tmp, off, is32);
7348c2ecf20Sopenharmony_ci			switch (BPF_SIZE(code)) {
7358c2ecf20Sopenharmony_ci			case BPF_B:
7368c2ecf20Sopenharmony_ci				emit_insn(ctx, stxb, src, dst, tmp);
7378c2ecf20Sopenharmony_ci				break;
7388c2ecf20Sopenharmony_ci			case BPF_H:
7398c2ecf20Sopenharmony_ci				emit_insn(ctx, stxh, src, dst, tmp);
7408c2ecf20Sopenharmony_ci				break;
7418c2ecf20Sopenharmony_ci			case BPF_W:
7428c2ecf20Sopenharmony_ci				emit_insn(ctx, stxw, src, dst, tmp);
7438c2ecf20Sopenharmony_ci				break;
7448c2ecf20Sopenharmony_ci			case BPF_DW:
7458c2ecf20Sopenharmony_ci				emit_insn(ctx, stxd, src, dst, tmp);
7468c2ecf20Sopenharmony_ci				break;
7478c2ecf20Sopenharmony_ci			}
7488c2ecf20Sopenharmony_ci		}
7498c2ecf20Sopenharmony_ci		break;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/* atomic_add: lock *(size *)(dst + off) += src */
7528c2ecf20Sopenharmony_ci	case BPF_STX | BPF_XADD | BPF_W:
7538c2ecf20Sopenharmony_ci	case BPF_STX | BPF_XADD | BPF_DW:
7548c2ecf20Sopenharmony_ci		if (insn->imm != BPF_ADD) {
7558c2ecf20Sopenharmony_ci			pr_err_once("unknown atomic op code %02x\n", insn->imm);
7568c2ecf20Sopenharmony_ci			return -EINVAL;
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		move_imm32(ctx, tmp, off, is32);
7608c2ecf20Sopenharmony_ci		emit_insn(ctx, addd, tmp, dst, tmp);
7618c2ecf20Sopenharmony_ci		switch (BPF_SIZE(insn->code)) {
7628c2ecf20Sopenharmony_ci		case BPF_W:
7638c2ecf20Sopenharmony_ci			emit_insn(ctx, amaddw, tmp2, src, tmp);
7648c2ecf20Sopenharmony_ci			break;
7658c2ecf20Sopenharmony_ci		case BPF_DW:
7668c2ecf20Sopenharmony_ci			emit_insn(ctx, amaddd, tmp2, src, tmp);
7678c2ecf20Sopenharmony_ci			break;
7688c2ecf20Sopenharmony_ci		}
7698c2ecf20Sopenharmony_ci		break;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	default:
7728c2ecf20Sopenharmony_ci		pr_err("bpf_jit: unknown opcode %02x\n", code);
7738c2ecf20Sopenharmony_ci		return -EINVAL;
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	return 0;
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic int build_body(struct jit_ctx *ctx, bool extra_pass)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	const struct bpf_prog *prog = ctx->prog;
7828c2ecf20Sopenharmony_ci	int i;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	for (i = 0; i < prog->len; i++) {
7858c2ecf20Sopenharmony_ci		const struct bpf_insn *insn = &prog->insnsi[i];
7868c2ecf20Sopenharmony_ci		int ret;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		if (!ctx->image)
7898c2ecf20Sopenharmony_ci			ctx->offset[i] = ctx->idx;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		ret = build_insn(insn, ctx, extra_pass);
7928c2ecf20Sopenharmony_ci		if (ret > 0) {
7938c2ecf20Sopenharmony_ci			i++;
7948c2ecf20Sopenharmony_ci			if (!ctx->image)
7958c2ecf20Sopenharmony_ci				ctx->offset[i] = ctx->idx;
7968c2ecf20Sopenharmony_ci			continue;
7978c2ecf20Sopenharmony_ci		}
7988c2ecf20Sopenharmony_ci		if (ret)
7998c2ecf20Sopenharmony_ci			return ret;
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (!ctx->image)
8038c2ecf20Sopenharmony_ci		ctx->offset[i] = ctx->idx;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	return 0;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic inline void bpf_flush_icache(void *start, void *end)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	flush_icache_range((unsigned long)start, (unsigned long)end);
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci/* Fill space with illegal instructions */
8148c2ecf20Sopenharmony_cistatic void jit_fill_hole(void *area, unsigned int size)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	u32 *ptr;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/* We are guaranteed to have aligned memory */
8198c2ecf20Sopenharmony_ci	for (ptr = area; size >= sizeof(u32); size -= sizeof(u32))
8208c2ecf20Sopenharmony_ci		*ptr++ = INSN_BREAK;
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cistatic int validate_code(struct jit_ctx *ctx)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	int i;
8268c2ecf20Sopenharmony_ci	union loongarch_instruction insn;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	for (i = 0; i < ctx->idx; i++) {
8298c2ecf20Sopenharmony_ci		insn = ctx->image[i];
8308c2ecf20Sopenharmony_ci		/* Check INSN_BREAK */
8318c2ecf20Sopenharmony_ci		if (insn.word == INSN_BREAK)
8328c2ecf20Sopenharmony_ci			return -1;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	return 0;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistruct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct bpf_prog *tmp, *orig_prog = prog;
8418c2ecf20Sopenharmony_ci	struct bpf_binary_header *header;
8428c2ecf20Sopenharmony_ci	struct jit_data *jit_data;
8438c2ecf20Sopenharmony_ci	struct jit_ctx ctx;
8448c2ecf20Sopenharmony_ci	bool tmp_blinded = false;
8458c2ecf20Sopenharmony_ci	bool extra_pass = false;
8468c2ecf20Sopenharmony_ci	int image_size;
8478c2ecf20Sopenharmony_ci	u8 *image_ptr;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/*
8508c2ecf20Sopenharmony_ci	 * If BPF JIT was not enabled then we must fall back to
8518c2ecf20Sopenharmony_ci	 * the interpreter.
8528c2ecf20Sopenharmony_ci	 */
8538c2ecf20Sopenharmony_ci	if (!prog->jit_requested)
8548c2ecf20Sopenharmony_ci		return orig_prog;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	tmp = bpf_jit_blind_constants(prog);
8578c2ecf20Sopenharmony_ci	/*
8588c2ecf20Sopenharmony_ci	 * If blinding was requested and we failed during blinding,
8598c2ecf20Sopenharmony_ci	 * we must fall back to the interpreter. Otherwise, we save
8608c2ecf20Sopenharmony_ci	 * the new JITed code.
8618c2ecf20Sopenharmony_ci	 */
8628c2ecf20Sopenharmony_ci	if (IS_ERR(tmp))
8638c2ecf20Sopenharmony_ci		return orig_prog;
8648c2ecf20Sopenharmony_ci	if (tmp != prog) {
8658c2ecf20Sopenharmony_ci		tmp_blinded = true;
8668c2ecf20Sopenharmony_ci		prog = tmp;
8678c2ecf20Sopenharmony_ci	}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	jit_data = prog->aux->jit_data;
8708c2ecf20Sopenharmony_ci	if (!jit_data) {
8718c2ecf20Sopenharmony_ci		jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL);
8728c2ecf20Sopenharmony_ci		if (!jit_data) {
8738c2ecf20Sopenharmony_ci			prog = orig_prog;
8748c2ecf20Sopenharmony_ci			goto out;
8758c2ecf20Sopenharmony_ci		}
8768c2ecf20Sopenharmony_ci		prog->aux->jit_data = jit_data;
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci	if (jit_data->ctx.offset) {
8798c2ecf20Sopenharmony_ci		ctx = jit_data->ctx;
8808c2ecf20Sopenharmony_ci		image_ptr = jit_data->image;
8818c2ecf20Sopenharmony_ci		header = jit_data->header;
8828c2ecf20Sopenharmony_ci		extra_pass = true;
8838c2ecf20Sopenharmony_ci		image_size = sizeof(u32) * ctx.idx;
8848c2ecf20Sopenharmony_ci		goto skip_init_ctx;
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	memset(&ctx, 0, sizeof(ctx));
8888c2ecf20Sopenharmony_ci	ctx.prog = prog;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	ctx.offset = kcalloc(prog->len + 1, sizeof(*ctx.offset), GFP_KERNEL);
8918c2ecf20Sopenharmony_ci	if (!ctx.offset) {
8928c2ecf20Sopenharmony_ci		prog = orig_prog;
8938c2ecf20Sopenharmony_ci		goto out_off;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	/* 1. Initial fake pass to compute ctx->idx and set ctx->flags */
8978c2ecf20Sopenharmony_ci	if (build_body(&ctx, extra_pass)) {
8988c2ecf20Sopenharmony_ci		prog = orig_prog;
8998c2ecf20Sopenharmony_ci		goto out_off;
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci	build_prologue(&ctx);
9028c2ecf20Sopenharmony_ci	ctx.epilogue_offset = ctx.idx;
9038c2ecf20Sopenharmony_ci	build_epilogue(&ctx);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* Now we know the actual image size.
9068c2ecf20Sopenharmony_ci	 * As each LoongArch instruction is of length 32bit,
9078c2ecf20Sopenharmony_ci	 * we are translating number of JITed intructions into
9088c2ecf20Sopenharmony_ci	 * the size required to store these JITed code.
9098c2ecf20Sopenharmony_ci	 */
9108c2ecf20Sopenharmony_ci	image_size = sizeof(u32) * ctx.idx;
9118c2ecf20Sopenharmony_ci	/* Now we know the size of the structure to make */
9128c2ecf20Sopenharmony_ci	header = bpf_jit_binary_alloc(image_size, &image_ptr,
9138c2ecf20Sopenharmony_ci				      sizeof(u32), jit_fill_hole);
9148c2ecf20Sopenharmony_ci	if (!header) {
9158c2ecf20Sopenharmony_ci		prog = orig_prog;
9168c2ecf20Sopenharmony_ci		goto out_off;
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	/* 2. Now, the actual pass to generate final JIT code */
9208c2ecf20Sopenharmony_ci	ctx.image = (union loongarch_instruction *)image_ptr;
9218c2ecf20Sopenharmony_ciskip_init_ctx:
9228c2ecf20Sopenharmony_ci	ctx.idx = 0;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	build_prologue(&ctx);
9258c2ecf20Sopenharmony_ci	if (build_body(&ctx, extra_pass)) {
9268c2ecf20Sopenharmony_ci		bpf_jit_binary_free(header);
9278c2ecf20Sopenharmony_ci		prog = orig_prog;
9288c2ecf20Sopenharmony_ci		goto out_off;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci	build_epilogue(&ctx);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/* 3. Extra pass to validate JITed code */
9338c2ecf20Sopenharmony_ci	if (validate_code(&ctx)) {
9348c2ecf20Sopenharmony_ci		bpf_jit_binary_free(header);
9358c2ecf20Sopenharmony_ci		prog = orig_prog;
9368c2ecf20Sopenharmony_ci		goto out_off;
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	/* And we're done */
9408c2ecf20Sopenharmony_ci	if (bpf_jit_enable > 1)
9418c2ecf20Sopenharmony_ci		bpf_jit_dump(prog->len, image_size, 2, ctx.image);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* Update the icache */
9448c2ecf20Sopenharmony_ci	bpf_flush_icache(header, ctx.image + ctx.idx);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (!prog->is_func || extra_pass) {
9478c2ecf20Sopenharmony_ci		if (extra_pass && ctx.idx != jit_data->ctx.idx) {
9488c2ecf20Sopenharmony_ci			pr_err_once("multi-func JIT bug %d != %d\n",
9498c2ecf20Sopenharmony_ci				    ctx.idx, jit_data->ctx.idx);
9508c2ecf20Sopenharmony_ci			bpf_jit_binary_free(header);
9518c2ecf20Sopenharmony_ci			prog->bpf_func = NULL;
9528c2ecf20Sopenharmony_ci			prog->jited = 0;
9538c2ecf20Sopenharmony_ci			goto out_off;
9548c2ecf20Sopenharmony_ci		}
9558c2ecf20Sopenharmony_ci		bpf_jit_binary_lock_ro(header);
9568c2ecf20Sopenharmony_ci	} else {
9578c2ecf20Sopenharmony_ci		jit_data->ctx = ctx;
9588c2ecf20Sopenharmony_ci		jit_data->image = image_ptr;
9598c2ecf20Sopenharmony_ci		jit_data->header = header;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci	prog->bpf_func = (void *)ctx.image;
9628c2ecf20Sopenharmony_ci	prog->jited = 1;
9638c2ecf20Sopenharmony_ci	prog->jited_len = image_size;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (!prog->is_func || extra_pass) {
9668c2ecf20Sopenharmony_ciout_off:
9678c2ecf20Sopenharmony_ci		kfree(ctx.offset);
9688c2ecf20Sopenharmony_ci		kfree(jit_data);
9698c2ecf20Sopenharmony_ci		prog->aux->jit_data = NULL;
9708c2ecf20Sopenharmony_ci	}
9718c2ecf20Sopenharmony_ciout:
9728c2ecf20Sopenharmony_ci	if (tmp_blinded)
9738c2ecf20Sopenharmony_ci		bpf_jit_prog_release_other(prog, prog == orig_prog ?
9748c2ecf20Sopenharmony_ci					   tmp : orig_prog);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	out_offset = -1;
9778c2ecf20Sopenharmony_ci	return prog;
9788c2ecf20Sopenharmony_ci}
979