xref: /openbmc/linux/arch/sparc/net/bpf_jit_comp_64.c (revision d60c7ab6fad75d753f866f2fc87725196645e0f3)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
27a12b503SDavid S. Miller #include <linux/moduleloader.h>
37a12b503SDavid S. Miller #include <linux/workqueue.h>
47a12b503SDavid S. Miller #include <linux/netdevice.h>
57a12b503SDavid S. Miller #include <linux/filter.h>
67a12b503SDavid S. Miller #include <linux/bpf.h>
77a12b503SDavid S. Miller #include <linux/cache.h>
87a12b503SDavid S. Miller #include <linux/if_vlan.h>
97a12b503SDavid S. Miller 
107a12b503SDavid S. Miller #include <asm/cacheflush.h>
117a12b503SDavid S. Miller #include <asm/ptrace.h>
127a12b503SDavid S. Miller 
137a12b503SDavid S. Miller #include "bpf_jit_64.h"
147a12b503SDavid S. Miller 
is_simm13(unsigned int value)157a12b503SDavid S. Miller static inline bool is_simm13(unsigned int value)
167a12b503SDavid S. Miller {
177a12b503SDavid S. Miller 	return value + 0x1000 < 0x2000;
187a12b503SDavid S. Miller }
197a12b503SDavid S. Miller 
is_simm10(unsigned int value)20e3a724edSDavid S. Miller static inline bool is_simm10(unsigned int value)
21e3a724edSDavid S. Miller {
22e3a724edSDavid S. Miller 	return value + 0x200 < 0x400;
23e3a724edSDavid S. Miller }
24e3a724edSDavid S. Miller 
is_simm5(unsigned int value)25e3a724edSDavid S. Miller static inline bool is_simm5(unsigned int value)
26e3a724edSDavid S. Miller {
27e3a724edSDavid S. Miller 	return value + 0x10 < 0x20;
28e3a724edSDavid S. Miller }
29e3a724edSDavid S. Miller 
is_sethi(unsigned int value)3014933dc8SDavid S. Miller static inline bool is_sethi(unsigned int value)
3114933dc8SDavid S. Miller {
3214933dc8SDavid S. Miller 	return (value & ~0x3fffff) == 0;
3314933dc8SDavid S. Miller }
3414933dc8SDavid S. Miller 
bpf_flush_icache(void * start_,void * end_)357a12b503SDavid S. Miller static void bpf_flush_icache(void *start_, void *end_)
367a12b503SDavid S. Miller {
377a12b503SDavid S. Miller 	/* Cheetah's I-cache is fully coherent.  */
387a12b503SDavid S. Miller 	if (tlb_type == spitfire) {
397a12b503SDavid S. Miller 		unsigned long start = (unsigned long) start_;
407a12b503SDavid S. Miller 		unsigned long end = (unsigned long) end_;
417a12b503SDavid S. Miller 
427a12b503SDavid S. Miller 		start &= ~7UL;
437a12b503SDavid S. Miller 		end = (end + 7UL) & ~7UL;
447a12b503SDavid S. Miller 		while (start < end) {
457a12b503SDavid S. Miller 			flushi(start);
467a12b503SDavid S. Miller 			start += 32;
477a12b503SDavid S. Miller 		}
487a12b503SDavid S. Miller 	}
497a12b503SDavid S. Miller }
507a12b503SDavid S. Miller 
517a12b503SDavid S. Miller #define S13(X)		((X) & 0x1fff)
52e3a724edSDavid S. Miller #define S5(X)		((X) & 0x1f)
537a12b503SDavid S. Miller #define IMMED		0x00002000
547a12b503SDavid S. Miller #define RD(X)		((X) << 25)
557a12b503SDavid S. Miller #define RS1(X)		((X) << 14)
567a12b503SDavid S. Miller #define RS2(X)		((X))
577a12b503SDavid S. Miller #define OP(X)		((X) << 30)
587a12b503SDavid S. Miller #define OP2(X)		((X) << 22)
597a12b503SDavid S. Miller #define OP3(X)		((X) << 19)
60e3a724edSDavid S. Miller #define COND(X)		(((X) & 0xf) << 25)
61e3a724edSDavid S. Miller #define CBCOND(X)	(((X) & 0x1f) << 25)
627a12b503SDavid S. Miller #define F1(X)		OP(X)
637a12b503SDavid S. Miller #define F2(X, Y)	(OP(X) | OP2(Y))
647a12b503SDavid S. Miller #define F3(X, Y)	(OP(X) | OP3(Y))
657a12b503SDavid S. Miller #define ASI(X)		(((X) & 0xff) << 5)
667a12b503SDavid S. Miller 
677a12b503SDavid S. Miller #define CONDN		COND(0x0)
687a12b503SDavid S. Miller #define CONDE		COND(0x1)
697a12b503SDavid S. Miller #define CONDLE		COND(0x2)
707a12b503SDavid S. Miller #define CONDL		COND(0x3)
717a12b503SDavid S. Miller #define CONDLEU		COND(0x4)
727a12b503SDavid S. Miller #define CONDCS		COND(0x5)
737a12b503SDavid S. Miller #define CONDNEG		COND(0x6)
747a12b503SDavid S. Miller #define CONDVC		COND(0x7)
757a12b503SDavid S. Miller #define CONDA		COND(0x8)
767a12b503SDavid S. Miller #define CONDNE		COND(0x9)
777a12b503SDavid S. Miller #define CONDG		COND(0xa)
787a12b503SDavid S. Miller #define CONDGE		COND(0xb)
797a12b503SDavid S. Miller #define CONDGU		COND(0xc)
807a12b503SDavid S. Miller #define CONDCC		COND(0xd)
817a12b503SDavid S. Miller #define CONDPOS		COND(0xe)
827a12b503SDavid S. Miller #define CONDVS		COND(0xf)
837a12b503SDavid S. Miller 
847a12b503SDavid S. Miller #define CONDGEU		CONDCC
857a12b503SDavid S. Miller #define CONDLU		CONDCS
867a12b503SDavid S. Miller 
877a12b503SDavid S. Miller #define WDISP22(X)	(((X) >> 2) & 0x3fffff)
887a12b503SDavid S. Miller #define WDISP19(X)	(((X) >> 2) & 0x7ffff)
897a12b503SDavid S. Miller 
90e3a724edSDavid S. Miller /* The 10-bit branch displacement for CBCOND is split into two fields */
WDISP10(u32 off)91e3a724edSDavid S. Miller static u32 WDISP10(u32 off)
92e3a724edSDavid S. Miller {
93e3a724edSDavid S. Miller 	u32 ret = ((off >> 2) & 0xff) << 5;
94e3a724edSDavid S. Miller 
95e3a724edSDavid S. Miller 	ret |= ((off >> (2 + 8)) & 0x03) << 19;
96e3a724edSDavid S. Miller 
97e3a724edSDavid S. Miller 	return ret;
98e3a724edSDavid S. Miller }
99e3a724edSDavid S. Miller 
100e3a724edSDavid S. Miller #define CBCONDE		CBCOND(0x09)
101e3a724edSDavid S. Miller #define CBCONDLE	CBCOND(0x0a)
102e3a724edSDavid S. Miller #define CBCONDL		CBCOND(0x0b)
103e3a724edSDavid S. Miller #define CBCONDLEU	CBCOND(0x0c)
104e3a724edSDavid S. Miller #define CBCONDCS	CBCOND(0x0d)
105e3a724edSDavid S. Miller #define CBCONDN		CBCOND(0x0e)
106e3a724edSDavid S. Miller #define CBCONDVS	CBCOND(0x0f)
107e3a724edSDavid S. Miller #define CBCONDNE	CBCOND(0x19)
108e3a724edSDavid S. Miller #define CBCONDG		CBCOND(0x1a)
109e3a724edSDavid S. Miller #define CBCONDGE	CBCOND(0x1b)
110e3a724edSDavid S. Miller #define CBCONDGU	CBCOND(0x1c)
111e3a724edSDavid S. Miller #define CBCONDCC	CBCOND(0x1d)
112e3a724edSDavid S. Miller #define CBCONDPOS	CBCOND(0x1e)
113e3a724edSDavid S. Miller #define CBCONDVC	CBCOND(0x1f)
114e3a724edSDavid S. Miller 
115e3a724edSDavid S. Miller #define CBCONDGEU	CBCONDCC
116e3a724edSDavid S. Miller #define CBCONDLU	CBCONDCS
117e3a724edSDavid S. Miller 
1187a12b503SDavid S. Miller #define ANNUL		(1 << 29)
1197a12b503SDavid S. Miller #define XCC		(1 << 21)
1207a12b503SDavid S. Miller 
1217a12b503SDavid S. Miller #define BRANCH		(F2(0, 1) | XCC)
122e3a724edSDavid S. Miller #define CBCOND_OP	(F2(0, 3) | XCC)
1237a12b503SDavid S. Miller 
1247a12b503SDavid S. Miller #define BA		(BRANCH | CONDA)
1257a12b503SDavid S. Miller #define BG		(BRANCH | CONDG)
12618423550SDaniel Borkmann #define BL		(BRANCH | CONDL)
12718423550SDaniel Borkmann #define BLE		(BRANCH | CONDLE)
1287a12b503SDavid S. Miller #define BGU		(BRANCH | CONDGU)
1297a12b503SDavid S. Miller #define BLEU		(BRANCH | CONDLEU)
1307a12b503SDavid S. Miller #define BGE		(BRANCH | CONDGE)
1317a12b503SDavid S. Miller #define BGEU		(BRANCH | CONDGEU)
1327a12b503SDavid S. Miller #define BLU		(BRANCH | CONDLU)
1337a12b503SDavid S. Miller #define BE		(BRANCH | CONDE)
1347a12b503SDavid S. Miller #define BNE		(BRANCH | CONDNE)
1357a12b503SDavid S. Miller 
1367a12b503SDavid S. Miller #define SETHI(K, REG)	\
1377a12b503SDavid S. Miller 	(F2(0, 0x4) | RD(REG) | (((K) >> 10) & 0x3fffff))
1387a12b503SDavid S. Miller #define OR_LO(K, REG)	\
1397a12b503SDavid S. Miller 	(F3(2, 0x02) | IMMED | RS1(REG) | ((K) & 0x3ff) | RD(REG))
1407a12b503SDavid S. Miller 
1417a12b503SDavid S. Miller #define ADD		F3(2, 0x00)
1427a12b503SDavid S. Miller #define AND		F3(2, 0x01)
1437a12b503SDavid S. Miller #define ANDCC		F3(2, 0x11)
1447a12b503SDavid S. Miller #define OR		F3(2, 0x02)
1457a12b503SDavid S. Miller #define XOR		F3(2, 0x03)
1467a12b503SDavid S. Miller #define SUB		F3(2, 0x04)
1477a12b503SDavid S. Miller #define SUBCC		F3(2, 0x14)
1487a12b503SDavid S. Miller #define MUL		F3(2, 0x0a)
1497a12b503SDavid S. Miller #define MULX		F3(2, 0x09)
1507a12b503SDavid S. Miller #define UDIVX		F3(2, 0x0d)
1517a12b503SDavid S. Miller #define DIV		F3(2, 0x0e)
1527a12b503SDavid S. Miller #define SLL		F3(2, 0x25)
1537a12b503SDavid S. Miller #define SLLX		(F3(2, 0x25)|(1<<12))
1547a12b503SDavid S. Miller #define SRA		F3(2, 0x27)
1557a12b503SDavid S. Miller #define SRAX		(F3(2, 0x27)|(1<<12))
1567a12b503SDavid S. Miller #define SRL		F3(2, 0x26)
1577a12b503SDavid S. Miller #define SRLX		(F3(2, 0x26)|(1<<12))
1587a12b503SDavid S. Miller #define JMPL		F3(2, 0x38)
1597a12b503SDavid S. Miller #define SAVE		F3(2, 0x3c)
1607a12b503SDavid S. Miller #define RESTORE		F3(2, 0x3d)
1617a12b503SDavid S. Miller #define CALL		F1(1)
1627a12b503SDavid S. Miller #define BR		F2(0, 0x01)
1637a12b503SDavid S. Miller #define RD_Y		F3(2, 0x28)
1647a12b503SDavid S. Miller #define WR_Y		F3(2, 0x30)
1657a12b503SDavid S. Miller 
1667a12b503SDavid S. Miller #define LD32		F3(3, 0x00)
1677a12b503SDavid S. Miller #define LD8		F3(3, 0x01)
1687a12b503SDavid S. Miller #define LD16		F3(3, 0x02)
1697a12b503SDavid S. Miller #define LD64		F3(3, 0x0b)
1707a12b503SDavid S. Miller #define LD64A		F3(3, 0x1b)
1717a12b503SDavid S. Miller #define ST8		F3(3, 0x05)
1727a12b503SDavid S. Miller #define ST16		F3(3, 0x06)
1737a12b503SDavid S. Miller #define ST32		F3(3, 0x04)
1747a12b503SDavid S. Miller #define ST64		F3(3, 0x0e)
1757a12b503SDavid S. Miller 
1767a12b503SDavid S. Miller #define CAS		F3(3, 0x3c)
1777a12b503SDavid S. Miller #define CASX		F3(3, 0x3e)
1787a12b503SDavid S. Miller 
1797a12b503SDavid S. Miller #define LDPTR		LD64
1807a12b503SDavid S. Miller #define BASE_STACKFRAME	176
1817a12b503SDavid S. Miller 
1827a12b503SDavid S. Miller #define LD32I		(LD32 | IMMED)
1837a12b503SDavid S. Miller #define LD8I		(LD8 | IMMED)
1847a12b503SDavid S. Miller #define LD16I		(LD16 | IMMED)
1857a12b503SDavid S. Miller #define LD64I		(LD64 | IMMED)
1867a12b503SDavid S. Miller #define LDPTRI		(LDPTR | IMMED)
1877a12b503SDavid S. Miller #define ST32I		(ST32 | IMMED)
1887a12b503SDavid S. Miller 
1897a12b503SDavid S. Miller struct jit_ctx {
1907a12b503SDavid S. Miller 	struct bpf_prog		*prog;
1917a12b503SDavid S. Miller 	unsigned int		*offset;
1927a12b503SDavid S. Miller 	int			idx;
1937a12b503SDavid S. Miller 	int			epilogue_offset;
1947a12b503SDavid S. Miller 	bool 			tmp_1_used;
1957a12b503SDavid S. Miller 	bool 			tmp_2_used;
1967a12b503SDavid S. Miller 	bool 			tmp_3_used;
1977a12b503SDavid S. Miller 	bool			saw_frame_pointer;
1987a12b503SDavid S. Miller 	bool			saw_call;
1997a12b503SDavid S. Miller 	bool			saw_tail_call;
2007a12b503SDavid S. Miller 	u32			*image;
2017a12b503SDavid S. Miller };
2027a12b503SDavid S. Miller 
2037a12b503SDavid S. Miller #define TMP_REG_1	(MAX_BPF_JIT_REG + 0)
2047a12b503SDavid S. Miller #define TMP_REG_2	(MAX_BPF_JIT_REG + 1)
205fe83963bSDaniel Borkmann #define TMP_REG_3	(MAX_BPF_JIT_REG + 2)
2067a12b503SDavid S. Miller 
2077a12b503SDavid S. Miller /* Map BPF registers to SPARC registers */
2087a12b503SDavid S. Miller static const int bpf2sparc[] = {
2097a12b503SDavid S. Miller 	/* return value from in-kernel function, and exit value from eBPF */
2107a12b503SDavid S. Miller 	[BPF_REG_0] = O5,
2117a12b503SDavid S. Miller 
2127a12b503SDavid S. Miller 	/* arguments from eBPF program to in-kernel function */
2137a12b503SDavid S. Miller 	[BPF_REG_1] = O0,
2147a12b503SDavid S. Miller 	[BPF_REG_2] = O1,
2157a12b503SDavid S. Miller 	[BPF_REG_3] = O2,
2167a12b503SDavid S. Miller 	[BPF_REG_4] = O3,
2177a12b503SDavid S. Miller 	[BPF_REG_5] = O4,
2187a12b503SDavid S. Miller 
2197a12b503SDavid S. Miller 	/* callee saved registers that in-kernel function will preserve */
2207a12b503SDavid S. Miller 	[BPF_REG_6] = L0,
2217a12b503SDavid S. Miller 	[BPF_REG_7] = L1,
2227a12b503SDavid S. Miller 	[BPF_REG_8] = L2,
2237a12b503SDavid S. Miller 	[BPF_REG_9] = L3,
2247a12b503SDavid S. Miller 
2257a12b503SDavid S. Miller 	/* read-only frame pointer to access stack */
2267a12b503SDavid S. Miller 	[BPF_REG_FP] = L6,
2277a12b503SDavid S. Miller 
2287a12b503SDavid S. Miller 	[BPF_REG_AX] = G7,
2297a12b503SDavid S. Miller 
23006edc59cSChristoph Hellwig 	/* temporary register for BPF JIT */
2317a12b503SDavid S. Miller 	[TMP_REG_1] = G1,
2327a12b503SDavid S. Miller 	[TMP_REG_2] = G2,
2337a12b503SDavid S. Miller 	[TMP_REG_3] = G3,
2347a12b503SDavid S. Miller };
2357a12b503SDavid S. Miller 
emit(const u32 insn,struct jit_ctx * ctx)2367a12b503SDavid S. Miller static void emit(const u32 insn, struct jit_ctx *ctx)
2377a12b503SDavid S. Miller {
2387a12b503SDavid S. Miller 	if (ctx->image != NULL)
2397a12b503SDavid S. Miller 		ctx->image[ctx->idx] = insn;
2407a12b503SDavid S. Miller 
2417a12b503SDavid S. Miller 	ctx->idx++;
2427a12b503SDavid S. Miller }
2437a12b503SDavid S. Miller 
emit_call(u32 * func,struct jit_ctx * ctx)2447a12b503SDavid S. Miller static void emit_call(u32 *func, struct jit_ctx *ctx)
2457a12b503SDavid S. Miller {
2467a12b503SDavid S. Miller 	if (ctx->image != NULL) {
2477a12b503SDavid S. Miller 		void *here = &ctx->image[ctx->idx];
2487a12b503SDavid S. Miller 		unsigned int off;
2497a12b503SDavid S. Miller 
2507a12b503SDavid S. Miller 		off = (void *)func - here;
2517a12b503SDavid S. Miller 		ctx->image[ctx->idx] = CALL | ((off >> 2) & 0x3fffffff);
2527a12b503SDavid S. Miller 	}
2537a12b503SDavid S. Miller 	ctx->idx++;
2547a12b503SDavid S. Miller }
2557a12b503SDavid S. Miller 
emit_nop(struct jit_ctx * ctx)2567a12b503SDavid S. Miller static void emit_nop(struct jit_ctx *ctx)
2577a12b503SDavid S. Miller {
2587a12b503SDavid S. Miller 	emit(SETHI(0, G0), ctx);
2597a12b503SDavid S. Miller }
2607a12b503SDavid S. Miller 
emit_reg_move(u32 from,u32 to,struct jit_ctx * ctx)2617a12b503SDavid S. Miller static void emit_reg_move(u32 from, u32 to, struct jit_ctx *ctx)
2627a12b503SDavid S. Miller {
2637a12b503SDavid S. Miller 	emit(OR | RS1(G0) | RS2(from) | RD(to), ctx);
2647a12b503SDavid S. Miller }
2657a12b503SDavid S. Miller 
2667a12b503SDavid S. Miller /* Emit 32-bit constant, zero extended. */
emit_set_const(s32 K,u32 reg,struct jit_ctx * ctx)2677a12b503SDavid S. Miller static void emit_set_const(s32 K, u32 reg, struct jit_ctx *ctx)
2687a12b503SDavid S. Miller {
2697a12b503SDavid S. Miller 	emit(SETHI(K, reg), ctx);
2707a12b503SDavid S. Miller 	emit(OR_LO(K, reg), ctx);
2717a12b503SDavid S. Miller }
2727a12b503SDavid S. Miller 
2737a12b503SDavid S. Miller /* Emit 32-bit constant, sign extended. */
emit_set_const_sext(s32 K,u32 reg,struct jit_ctx * ctx)2747a12b503SDavid S. Miller static void emit_set_const_sext(s32 K, u32 reg, struct jit_ctx *ctx)
2757a12b503SDavid S. Miller {
2767a12b503SDavid S. Miller 	if (K >= 0) {
2777a12b503SDavid S. Miller 		emit(SETHI(K, reg), ctx);
2787a12b503SDavid S. Miller 		emit(OR_LO(K, reg), ctx);
2797a12b503SDavid S. Miller 	} else {
2807a12b503SDavid S. Miller 		u32 hbits = ~(u32) K;
2817a12b503SDavid S. Miller 		u32 lbits = -0x400 | (u32) K;
2827a12b503SDavid S. Miller 
2837a12b503SDavid S. Miller 		emit(SETHI(hbits, reg), ctx);
2847a12b503SDavid S. Miller 		emit(XOR | IMMED | RS1(reg) | S13(lbits) | RD(reg), ctx);
2857a12b503SDavid S. Miller 	}
2867a12b503SDavid S. Miller }
2877a12b503SDavid S. Miller 
emit_alu(u32 opcode,u32 src,u32 dst,struct jit_ctx * ctx)2887a12b503SDavid S. Miller static void emit_alu(u32 opcode, u32 src, u32 dst, struct jit_ctx *ctx)
2897a12b503SDavid S. Miller {
2907a12b503SDavid S. Miller 	emit(opcode | RS1(dst) | RS2(src) | RD(dst), ctx);
2917a12b503SDavid S. Miller }
2927a12b503SDavid S. Miller 
emit_alu3(u32 opcode,u32 a,u32 b,u32 c,struct jit_ctx * ctx)2937a12b503SDavid S. Miller static void emit_alu3(u32 opcode, u32 a, u32 b, u32 c, struct jit_ctx *ctx)
2947a12b503SDavid S. Miller {
2957a12b503SDavid S. Miller 	emit(opcode | RS1(a) | RS2(b) | RD(c), ctx);
2967a12b503SDavid S. Miller }
2977a12b503SDavid S. Miller 
emit_alu_K(unsigned int opcode,unsigned int dst,unsigned int imm,struct jit_ctx * ctx)2987a12b503SDavid S. Miller static void emit_alu_K(unsigned int opcode, unsigned int dst, unsigned int imm,
2997a12b503SDavid S. Miller 		       struct jit_ctx *ctx)
3007a12b503SDavid S. Miller {
3017a12b503SDavid S. Miller 	bool small_immed = is_simm13(imm);
3027a12b503SDavid S. Miller 	unsigned int insn = opcode;
3037a12b503SDavid S. Miller 
3047a12b503SDavid S. Miller 	insn |= RS1(dst) | RD(dst);
3057a12b503SDavid S. Miller 	if (small_immed) {
3067a12b503SDavid S. Miller 		emit(insn | IMMED | S13(imm), ctx);
3077a12b503SDavid S. Miller 	} else {
3087a12b503SDavid S. Miller 		unsigned int tmp = bpf2sparc[TMP_REG_1];
3097a12b503SDavid S. Miller 
3107a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
3117a12b503SDavid S. Miller 
3127a12b503SDavid S. Miller 		emit_set_const_sext(imm, tmp, ctx);
3137a12b503SDavid S. Miller 		emit(insn | RS2(tmp), ctx);
3147a12b503SDavid S. Miller 	}
3157a12b503SDavid S. Miller }
3167a12b503SDavid S. Miller 
emit_alu3_K(unsigned int opcode,unsigned int src,unsigned int imm,unsigned int dst,struct jit_ctx * ctx)3177a12b503SDavid S. Miller static void emit_alu3_K(unsigned int opcode, unsigned int src, unsigned int imm,
3187a12b503SDavid S. Miller 			unsigned int dst, struct jit_ctx *ctx)
3197a12b503SDavid S. Miller {
3207a12b503SDavid S. Miller 	bool small_immed = is_simm13(imm);
3217a12b503SDavid S. Miller 	unsigned int insn = opcode;
3227a12b503SDavid S. Miller 
3237a12b503SDavid S. Miller 	insn |= RS1(src) | RD(dst);
3247a12b503SDavid S. Miller 	if (small_immed) {
3257a12b503SDavid S. Miller 		emit(insn | IMMED | S13(imm), ctx);
3267a12b503SDavid S. Miller 	} else {
3277a12b503SDavid S. Miller 		unsigned int tmp = bpf2sparc[TMP_REG_1];
3287a12b503SDavid S. Miller 
3297a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
3307a12b503SDavid S. Miller 
3317a12b503SDavid S. Miller 		emit_set_const_sext(imm, tmp, ctx);
3327a12b503SDavid S. Miller 		emit(insn | RS2(tmp), ctx);
3337a12b503SDavid S. Miller 	}
3347a12b503SDavid S. Miller }
3357a12b503SDavid S. Miller 
emit_loadimm32(s32 K,unsigned int dest,struct jit_ctx * ctx)3367a12b503SDavid S. Miller static void emit_loadimm32(s32 K, unsigned int dest, struct jit_ctx *ctx)
3377a12b503SDavid S. Miller {
3387a12b503SDavid S. Miller 	if (K >= 0 && is_simm13(K)) {
3397a12b503SDavid S. Miller 		/* or %g0, K, DEST */
3407a12b503SDavid S. Miller 		emit(OR | IMMED | RS1(G0) | S13(K) | RD(dest), ctx);
3417a12b503SDavid S. Miller 	} else {
3427a12b503SDavid S. Miller 		emit_set_const(K, dest, ctx);
3437a12b503SDavid S. Miller 	}
3447a12b503SDavid S. Miller }
3457a12b503SDavid S. Miller 
emit_loadimm(s32 K,unsigned int dest,struct jit_ctx * ctx)3467a12b503SDavid S. Miller static void emit_loadimm(s32 K, unsigned int dest, struct jit_ctx *ctx)
3477a12b503SDavid S. Miller {
3487a12b503SDavid S. Miller 	if (is_simm13(K)) {
3497a12b503SDavid S. Miller 		/* or %g0, K, DEST */
3507a12b503SDavid S. Miller 		emit(OR | IMMED | RS1(G0) | S13(K) | RD(dest), ctx);
3517a12b503SDavid S. Miller 	} else {
3527a12b503SDavid S. Miller 		emit_set_const(K, dest, ctx);
3537a12b503SDavid S. Miller 	}
3547a12b503SDavid S. Miller }
3557a12b503SDavid S. Miller 
emit_loadimm_sext(s32 K,unsigned int dest,struct jit_ctx * ctx)3567a12b503SDavid S. Miller static void emit_loadimm_sext(s32 K, unsigned int dest, struct jit_ctx *ctx)
3577a12b503SDavid S. Miller {
3587a12b503SDavid S. Miller 	if (is_simm13(K)) {
3597a12b503SDavid S. Miller 		/* or %g0, K, DEST */
3607a12b503SDavid S. Miller 		emit(OR | IMMED | RS1(G0) | S13(K) | RD(dest), ctx);
3617a12b503SDavid S. Miller 	} else {
3627a12b503SDavid S. Miller 		emit_set_const_sext(K, dest, ctx);
3637a12b503SDavid S. Miller 	}
3647a12b503SDavid S. Miller }
3657a12b503SDavid S. Miller 
analyze_64bit_constant(u32 high_bits,u32 low_bits,int * hbsp,int * lbsp,int * abbasp)36614933dc8SDavid S. Miller static void analyze_64bit_constant(u32 high_bits, u32 low_bits,
36714933dc8SDavid S. Miller 				   int *hbsp, int *lbsp, int *abbasp)
36814933dc8SDavid S. Miller {
36914933dc8SDavid S. Miller 	int lowest_bit_set, highest_bit_set, all_bits_between_are_set;
37014933dc8SDavid S. Miller 	int i;
37114933dc8SDavid S. Miller 
37214933dc8SDavid S. Miller 	lowest_bit_set = highest_bit_set = -1;
37314933dc8SDavid S. Miller 	i = 0;
37414933dc8SDavid S. Miller 	do {
37514933dc8SDavid S. Miller 		if ((lowest_bit_set == -1) && ((low_bits >> i) & 1))
37614933dc8SDavid S. Miller 			lowest_bit_set = i;
37714933dc8SDavid S. Miller 		if ((highest_bit_set == -1) && ((high_bits >> (32 - i - 1)) & 1))
37814933dc8SDavid S. Miller 			highest_bit_set = (64 - i - 1);
37914933dc8SDavid S. Miller 	}  while (++i < 32 && (highest_bit_set == -1 ||
38014933dc8SDavid S. Miller 			       lowest_bit_set == -1));
38114933dc8SDavid S. Miller 	if (i == 32) {
38214933dc8SDavid S. Miller 		i = 0;
38314933dc8SDavid S. Miller 		do {
38414933dc8SDavid S. Miller 			if (lowest_bit_set == -1 && ((high_bits >> i) & 1))
38514933dc8SDavid S. Miller 				lowest_bit_set = i + 32;
38614933dc8SDavid S. Miller 			if (highest_bit_set == -1 &&
38714933dc8SDavid S. Miller 			    ((low_bits >> (32 - i - 1)) & 1))
38814933dc8SDavid S. Miller 				highest_bit_set = 32 - i - 1;
38914933dc8SDavid S. Miller 		} while (++i < 32 && (highest_bit_set == -1 ||
39014933dc8SDavid S. Miller 				      lowest_bit_set == -1));
39114933dc8SDavid S. Miller 	}
39214933dc8SDavid S. Miller 
39314933dc8SDavid S. Miller 	all_bits_between_are_set = 1;
39414933dc8SDavid S. Miller 	for (i = lowest_bit_set; i <= highest_bit_set; i++) {
39514933dc8SDavid S. Miller 		if (i < 32) {
39614933dc8SDavid S. Miller 			if ((low_bits & (1 << i)) != 0)
39714933dc8SDavid S. Miller 				continue;
39814933dc8SDavid S. Miller 		} else {
39914933dc8SDavid S. Miller 			if ((high_bits & (1 << (i - 32))) != 0)
40014933dc8SDavid S. Miller 				continue;
40114933dc8SDavid S. Miller 		}
40214933dc8SDavid S. Miller 		all_bits_between_are_set = 0;
40314933dc8SDavid S. Miller 		break;
40414933dc8SDavid S. Miller 	}
40514933dc8SDavid S. Miller 	*hbsp = highest_bit_set;
40614933dc8SDavid S. Miller 	*lbsp = lowest_bit_set;
40714933dc8SDavid S. Miller 	*abbasp = all_bits_between_are_set;
40814933dc8SDavid S. Miller }
40914933dc8SDavid S. Miller 
create_simple_focus_bits(unsigned long high_bits,unsigned long low_bits,int lowest_bit_set,int shift)41014933dc8SDavid S. Miller static unsigned long create_simple_focus_bits(unsigned long high_bits,
41114933dc8SDavid S. Miller 					      unsigned long low_bits,
41214933dc8SDavid S. Miller 					      int lowest_bit_set, int shift)
41314933dc8SDavid S. Miller {
41414933dc8SDavid S. Miller 	long hi, lo;
41514933dc8SDavid S. Miller 
41614933dc8SDavid S. Miller 	if (lowest_bit_set < 32) {
41714933dc8SDavid S. Miller 		lo = (low_bits >> lowest_bit_set) << shift;
41814933dc8SDavid S. Miller 		hi = ((high_bits << (32 - lowest_bit_set)) << shift);
41914933dc8SDavid S. Miller 	} else {
42014933dc8SDavid S. Miller 		lo = 0;
42114933dc8SDavid S. Miller 		hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
42214933dc8SDavid S. Miller 	}
42314933dc8SDavid S. Miller 	return hi | lo;
42414933dc8SDavid S. Miller }
42514933dc8SDavid S. Miller 
const64_is_2insns(unsigned long high_bits,unsigned long low_bits)42614933dc8SDavid S. Miller static bool const64_is_2insns(unsigned long high_bits,
42714933dc8SDavid S. Miller 			      unsigned long low_bits)
42814933dc8SDavid S. Miller {
42914933dc8SDavid S. Miller 	int highest_bit_set, lowest_bit_set, all_bits_between_are_set;
43014933dc8SDavid S. Miller 
43114933dc8SDavid S. Miller 	if (high_bits == 0 || high_bits == 0xffffffff)
43214933dc8SDavid S. Miller 		return true;
43314933dc8SDavid S. Miller 
43414933dc8SDavid S. Miller 	analyze_64bit_constant(high_bits, low_bits,
43514933dc8SDavid S. Miller 			       &highest_bit_set, &lowest_bit_set,
43614933dc8SDavid S. Miller 			       &all_bits_between_are_set);
43714933dc8SDavid S. Miller 
43814933dc8SDavid S. Miller 	if ((highest_bit_set == 63 || lowest_bit_set == 0) &&
43914933dc8SDavid S. Miller 	    all_bits_between_are_set != 0)
44014933dc8SDavid S. Miller 		return true;
44114933dc8SDavid S. Miller 
44214933dc8SDavid S. Miller 	if (highest_bit_set - lowest_bit_set < 21)
44314933dc8SDavid S. Miller 		return true;
44414933dc8SDavid S. Miller 
44514933dc8SDavid S. Miller 	return false;
44614933dc8SDavid S. Miller }
44714933dc8SDavid S. Miller 
sparc_emit_set_const64_quick2(unsigned long high_bits,unsigned long low_imm,unsigned int dest,int shift_count,struct jit_ctx * ctx)44814933dc8SDavid S. Miller static void sparc_emit_set_const64_quick2(unsigned long high_bits,
44914933dc8SDavid S. Miller 					  unsigned long low_imm,
45014933dc8SDavid S. Miller 					  unsigned int dest,
45114933dc8SDavid S. Miller 					  int shift_count, struct jit_ctx *ctx)
45214933dc8SDavid S. Miller {
45314933dc8SDavid S. Miller 	emit_loadimm32(high_bits, dest, ctx);
45414933dc8SDavid S. Miller 
45514933dc8SDavid S. Miller 	/* Now shift it up into place.  */
45614933dc8SDavid S. Miller 	emit_alu_K(SLLX, dest, shift_count, ctx);
45714933dc8SDavid S. Miller 
45814933dc8SDavid S. Miller 	/* If there is a low immediate part piece, finish up by
45914933dc8SDavid S. Miller 	 * putting that in as well.
46014933dc8SDavid S. Miller 	 */
46114933dc8SDavid S. Miller 	if (low_imm != 0)
46214933dc8SDavid S. Miller 		emit(OR | IMMED | RS1(dest) | S13(low_imm) | RD(dest), ctx);
46314933dc8SDavid S. Miller }
46414933dc8SDavid S. Miller 
emit_loadimm64(u64 K,unsigned int dest,struct jit_ctx * ctx)4657a12b503SDavid S. Miller static void emit_loadimm64(u64 K, unsigned int dest, struct jit_ctx *ctx)
4667a12b503SDavid S. Miller {
46714933dc8SDavid S. Miller 	int all_bits_between_are_set, lowest_bit_set, highest_bit_set;
4687a12b503SDavid S. Miller 	unsigned int tmp = bpf2sparc[TMP_REG_1];
46914933dc8SDavid S. Miller 	u32 low_bits = (K & 0xffffffff);
47014933dc8SDavid S. Miller 	u32 high_bits = (K >> 32);
4717a12b503SDavid S. Miller 
47214933dc8SDavid S. Miller 	/* These two tests also take care of all of the one
47314933dc8SDavid S. Miller 	 * instruction cases.
47414933dc8SDavid S. Miller 	 */
47514933dc8SDavid S. Miller 	if (high_bits == 0xffffffff && (low_bits & 0x80000000))
47614933dc8SDavid S. Miller 		return emit_loadimm_sext(K, dest, ctx);
47714933dc8SDavid S. Miller 	if (high_bits == 0x00000000)
47814933dc8SDavid S. Miller 		return emit_loadimm32(K, dest, ctx);
47914933dc8SDavid S. Miller 
48014933dc8SDavid S. Miller 	analyze_64bit_constant(high_bits, low_bits, &highest_bit_set,
48114933dc8SDavid S. Miller 			       &lowest_bit_set, &all_bits_between_are_set);
48214933dc8SDavid S. Miller 
48314933dc8SDavid S. Miller 	/* 1) mov	-1, %reg
48414933dc8SDavid S. Miller 	 *    sllx	%reg, shift, %reg
48514933dc8SDavid S. Miller 	 * 2) mov	-1, %reg
48614933dc8SDavid S. Miller 	 *    srlx	%reg, shift, %reg
48714933dc8SDavid S. Miller 	 * 3) mov	some_small_const, %reg
48814933dc8SDavid S. Miller 	 *    sllx	%reg, shift, %reg
48914933dc8SDavid S. Miller 	 */
49014933dc8SDavid S. Miller 	if (((highest_bit_set == 63 || lowest_bit_set == 0) &&
49114933dc8SDavid S. Miller 	     all_bits_between_are_set != 0) ||
49214933dc8SDavid S. Miller 	    ((highest_bit_set - lowest_bit_set) < 12)) {
49314933dc8SDavid S. Miller 		int shift = lowest_bit_set;
49414933dc8SDavid S. Miller 		long the_const = -1;
49514933dc8SDavid S. Miller 
49614933dc8SDavid S. Miller 		if ((highest_bit_set != 63 && lowest_bit_set != 0) ||
49714933dc8SDavid S. Miller 		    all_bits_between_are_set == 0) {
49814933dc8SDavid S. Miller 			the_const =
49914933dc8SDavid S. Miller 				create_simple_focus_bits(high_bits, low_bits,
50014933dc8SDavid S. Miller 							 lowest_bit_set, 0);
50114933dc8SDavid S. Miller 		} else if (lowest_bit_set == 0)
50214933dc8SDavid S. Miller 			shift = -(63 - highest_bit_set);
50314933dc8SDavid S. Miller 
50414933dc8SDavid S. Miller 		emit(OR | IMMED | RS1(G0) | S13(the_const) | RD(dest), ctx);
50514933dc8SDavid S. Miller 		if (shift > 0)
50614933dc8SDavid S. Miller 			emit_alu_K(SLLX, dest, shift, ctx);
50714933dc8SDavid S. Miller 		else if (shift < 0)
50814933dc8SDavid S. Miller 			emit_alu_K(SRLX, dest, -shift, ctx);
50914933dc8SDavid S. Miller 
51014933dc8SDavid S. Miller 		return;
51114933dc8SDavid S. Miller 	}
51214933dc8SDavid S. Miller 
51314933dc8SDavid S. Miller 	/* Now a range of 22 or less bits set somewhere.
51414933dc8SDavid S. Miller 	 * 1) sethi	%hi(focus_bits), %reg
51514933dc8SDavid S. Miller 	 *    sllx	%reg, shift, %reg
51614933dc8SDavid S. Miller 	 * 2) sethi	%hi(focus_bits), %reg
51714933dc8SDavid S. Miller 	 *    srlx	%reg, shift, %reg
51814933dc8SDavid S. Miller 	 */
51914933dc8SDavid S. Miller 	if ((highest_bit_set - lowest_bit_set) < 21) {
52014933dc8SDavid S. Miller 		unsigned long focus_bits =
52114933dc8SDavid S. Miller 			create_simple_focus_bits(high_bits, low_bits,
52214933dc8SDavid S. Miller 						 lowest_bit_set, 10);
52314933dc8SDavid S. Miller 
52414933dc8SDavid S. Miller 		emit(SETHI(focus_bits, dest), ctx);
52514933dc8SDavid S. Miller 
52614933dc8SDavid S. Miller 		/* If lowest_bit_set == 10 then a sethi alone could
52714933dc8SDavid S. Miller 		 * have done it.
52814933dc8SDavid S. Miller 		 */
52914933dc8SDavid S. Miller 		if (lowest_bit_set < 10)
53014933dc8SDavid S. Miller 			emit_alu_K(SRLX, dest, 10 - lowest_bit_set, ctx);
53114933dc8SDavid S. Miller 		else if (lowest_bit_set > 10)
53214933dc8SDavid S. Miller 			emit_alu_K(SLLX, dest, lowest_bit_set - 10, ctx);
53314933dc8SDavid S. Miller 		return;
53414933dc8SDavid S. Miller 	}
53514933dc8SDavid S. Miller 
53614933dc8SDavid S. Miller 	/* Ok, now 3 instruction sequences.  */
53714933dc8SDavid S. Miller 	if (low_bits == 0) {
53814933dc8SDavid S. Miller 		emit_loadimm32(high_bits, dest, ctx);
53914933dc8SDavid S. Miller 		emit_alu_K(SLLX, dest, 32, ctx);
54014933dc8SDavid S. Miller 		return;
54114933dc8SDavid S. Miller 	}
54214933dc8SDavid S. Miller 
54314933dc8SDavid S. Miller 	/* We may be able to do something quick
54414933dc8SDavid S. Miller 	 * when the constant is negated, so try that.
54514933dc8SDavid S. Miller 	 */
54614933dc8SDavid S. Miller 	if (const64_is_2insns((~high_bits) & 0xffffffff,
54714933dc8SDavid S. Miller 			      (~low_bits) & 0xfffffc00)) {
54814933dc8SDavid S. Miller 		/* NOTE: The trailing bits get XOR'd so we need the
54914933dc8SDavid S. Miller 		 * non-negated bits, not the negated ones.
55014933dc8SDavid S. Miller 		 */
55114933dc8SDavid S. Miller 		unsigned long trailing_bits = low_bits & 0x3ff;
55214933dc8SDavid S. Miller 
55314933dc8SDavid S. Miller 		if ((((~high_bits) & 0xffffffff) == 0 &&
55414933dc8SDavid S. Miller 		     ((~low_bits) & 0x80000000) == 0) ||
55514933dc8SDavid S. Miller 		    (((~high_bits) & 0xffffffff) == 0xffffffff &&
55614933dc8SDavid S. Miller 		     ((~low_bits) & 0x80000000) != 0)) {
55714933dc8SDavid S. Miller 			unsigned long fast_int = (~low_bits & 0xffffffff);
55814933dc8SDavid S. Miller 
55914933dc8SDavid S. Miller 			if ((is_sethi(fast_int) &&
56014933dc8SDavid S. Miller 			     (~high_bits & 0xffffffff) == 0)) {
56114933dc8SDavid S. Miller 				emit(SETHI(fast_int, dest), ctx);
56214933dc8SDavid S. Miller 			} else if (is_simm13(fast_int)) {
56314933dc8SDavid S. Miller 				emit(OR | IMMED | RS1(G0) | S13(fast_int) | RD(dest), ctx);
56414933dc8SDavid S. Miller 			} else {
56514933dc8SDavid S. Miller 				emit_loadimm64(fast_int, dest, ctx);
56614933dc8SDavid S. Miller 			}
56714933dc8SDavid S. Miller 		} else {
56814933dc8SDavid S. Miller 			u64 n = ((~low_bits) & 0xfffffc00) |
56914933dc8SDavid S. Miller 				(((unsigned long)((~high_bits) & 0xffffffff))<<32);
57014933dc8SDavid S. Miller 			emit_loadimm64(n, dest, ctx);
57114933dc8SDavid S. Miller 		}
57214933dc8SDavid S. Miller 
57314933dc8SDavid S. Miller 		low_bits = -0x400 | trailing_bits;
57414933dc8SDavid S. Miller 
57514933dc8SDavid S. Miller 		emit(XOR | IMMED | RS1(dest) | S13(low_bits) | RD(dest), ctx);
57614933dc8SDavid S. Miller 		return;
57714933dc8SDavid S. Miller 	}
57814933dc8SDavid S. Miller 
57914933dc8SDavid S. Miller 	/* 1) sethi	%hi(xxx), %reg
58014933dc8SDavid S. Miller 	 *    or	%reg, %lo(xxx), %reg
58114933dc8SDavid S. Miller 	 *    sllx	%reg, yyy, %reg
58214933dc8SDavid S. Miller 	 */
58314933dc8SDavid S. Miller 	if ((highest_bit_set - lowest_bit_set) < 32) {
58414933dc8SDavid S. Miller 		unsigned long focus_bits =
58514933dc8SDavid S. Miller 			create_simple_focus_bits(high_bits, low_bits,
58614933dc8SDavid S. Miller 						 lowest_bit_set, 0);
58714933dc8SDavid S. Miller 
58814933dc8SDavid S. Miller 		/* So what we know is that the set bits straddle the
58914933dc8SDavid S. Miller 		 * middle of the 64-bit word.
59014933dc8SDavid S. Miller 		 */
59114933dc8SDavid S. Miller 		sparc_emit_set_const64_quick2(focus_bits, 0, dest,
59214933dc8SDavid S. Miller 					      lowest_bit_set, ctx);
59314933dc8SDavid S. Miller 		return;
59414933dc8SDavid S. Miller 	}
59514933dc8SDavid S. Miller 
59614933dc8SDavid S. Miller 	/* 1) sethi	%hi(high_bits), %reg
59714933dc8SDavid S. Miller 	 *    or	%reg, %lo(high_bits), %reg
59814933dc8SDavid S. Miller 	 *    sllx	%reg, 32, %reg
59914933dc8SDavid S. Miller 	 *    or	%reg, low_bits, %reg
60014933dc8SDavid S. Miller 	 */
60114933dc8SDavid S. Miller 	if (is_simm13(low_bits) && ((int)low_bits > 0)) {
60214933dc8SDavid S. Miller 		sparc_emit_set_const64_quick2(high_bits, low_bits,
60314933dc8SDavid S. Miller 					      dest, 32, ctx);
60414933dc8SDavid S. Miller 		return;
60514933dc8SDavid S. Miller 	}
60614933dc8SDavid S. Miller 
60714933dc8SDavid S. Miller 	/* Oh well, we tried... Do a full 64-bit decomposition.  */
6087a12b503SDavid S. Miller 	ctx->tmp_1_used = true;
6097a12b503SDavid S. Miller 
61014933dc8SDavid S. Miller 	emit_loadimm32(high_bits, tmp, ctx);
61114933dc8SDavid S. Miller 	emit_loadimm32(low_bits, dest, ctx);
6127a12b503SDavid S. Miller 	emit_alu_K(SLLX, tmp, 32, ctx);
6137a12b503SDavid S. Miller 	emit(OR | RS1(dest) | RS2(tmp) | RD(dest), ctx);
6147a12b503SDavid S. Miller }
6157a12b503SDavid S. Miller 
emit_branch(unsigned int br_opc,unsigned int from_idx,unsigned int to_idx,struct jit_ctx * ctx)6167a12b503SDavid S. Miller static void emit_branch(unsigned int br_opc, unsigned int from_idx, unsigned int to_idx,
6177a12b503SDavid S. Miller 			struct jit_ctx *ctx)
6187a12b503SDavid S. Miller {
6197a12b503SDavid S. Miller 	unsigned int off = to_idx - from_idx;
6207a12b503SDavid S. Miller 
6217a12b503SDavid S. Miller 	if (br_opc & XCC)
6227a12b503SDavid S. Miller 		emit(br_opc | WDISP19(off << 2), ctx);
6237a12b503SDavid S. Miller 	else
6247a12b503SDavid S. Miller 		emit(br_opc | WDISP22(off << 2), ctx);
6257a12b503SDavid S. Miller }
6267a12b503SDavid S. Miller 
emit_cbcond(unsigned int cb_opc,unsigned int from_idx,unsigned int to_idx,const u8 dst,const u8 src,struct jit_ctx * ctx)627e3a724edSDavid S. Miller static void emit_cbcond(unsigned int cb_opc, unsigned int from_idx, unsigned int to_idx,
628e3a724edSDavid S. Miller 			const u8 dst, const u8 src, struct jit_ctx *ctx)
629e3a724edSDavid S. Miller {
630e3a724edSDavid S. Miller 	unsigned int off = to_idx - from_idx;
631e3a724edSDavid S. Miller 
632e3a724edSDavid S. Miller 	emit(cb_opc | WDISP10(off << 2) | RS1(dst) | RS2(src), ctx);
633e3a724edSDavid S. Miller }
634e3a724edSDavid S. Miller 
emit_cbcondi(unsigned int cb_opc,unsigned int from_idx,unsigned int to_idx,const u8 dst,s32 imm,struct jit_ctx * ctx)635e3a724edSDavid S. Miller static void emit_cbcondi(unsigned int cb_opc, unsigned int from_idx, unsigned int to_idx,
636e3a724edSDavid S. Miller 			 const u8 dst, s32 imm, struct jit_ctx *ctx)
637e3a724edSDavid S. Miller {
638e3a724edSDavid S. Miller 	unsigned int off = to_idx - from_idx;
639e3a724edSDavid S. Miller 
640e3a724edSDavid S. Miller 	emit(cb_opc | IMMED | WDISP10(off << 2) | RS1(dst) | S5(imm), ctx);
641e3a724edSDavid S. Miller }
642e3a724edSDavid S. Miller 
6437a12b503SDavid S. Miller #define emit_read_y(REG, CTX)	emit(RD_Y | RD(REG), CTX)
6447a12b503SDavid S. Miller #define emit_write_y(REG, CTX)	emit(WR_Y | IMMED | RS1(REG) | S13(0), CTX)
6457a12b503SDavid S. Miller 
6467a12b503SDavid S. Miller #define emit_cmp(R1, R2, CTX)				\
6477a12b503SDavid S. Miller 	emit(SUBCC | RS1(R1) | RS2(R2) | RD(G0), CTX)
6487a12b503SDavid S. Miller 
6497a12b503SDavid S. Miller #define emit_cmpi(R1, IMM, CTX)				\
650e3a724edSDavid S. Miller 	emit(SUBCC | IMMED | RS1(R1) | S13(IMM) | RD(G0), CTX)
6517a12b503SDavid S. Miller 
6527a12b503SDavid S. Miller #define emit_btst(R1, R2, CTX)				\
6537a12b503SDavid S. Miller 	emit(ANDCC | RS1(R1) | RS2(R2) | RD(G0), CTX)
6547a12b503SDavid S. Miller 
6557a12b503SDavid S. Miller #define emit_btsti(R1, IMM, CTX)			\
6567a12b503SDavid S. Miller 	emit(ANDCC | IMMED | RS1(R1) | S13(IMM) | RD(G0), CTX)
6577a12b503SDavid S. Miller 
emit_compare_and_branch(const u8 code,const u8 dst,u8 src,const s32 imm,bool is_imm,int branch_dst,struct jit_ctx * ctx)658e3a724edSDavid S. Miller static int emit_compare_and_branch(const u8 code, const u8 dst, u8 src,
659e3a724edSDavid S. Miller 				   const s32 imm, bool is_imm, int branch_dst,
660e3a724edSDavid S. Miller 				   struct jit_ctx *ctx)
661e3a724edSDavid S. Miller {
662e3a724edSDavid S. Miller 	bool use_cbcond = (sparc64_elf_hwcap & AV_SPARC_CBCOND) != 0;
663e3a724edSDavid S. Miller 	const u8 tmp = bpf2sparc[TMP_REG_1];
664e3a724edSDavid S. Miller 
665e3a724edSDavid S. Miller 	branch_dst = ctx->offset[branch_dst];
666e3a724edSDavid S. Miller 
667e3a724edSDavid S. Miller 	if (!is_simm10(branch_dst - ctx->idx) ||
668e3a724edSDavid S. Miller 	    BPF_OP(code) == BPF_JSET)
669e3a724edSDavid S. Miller 		use_cbcond = false;
670e3a724edSDavid S. Miller 
671e3a724edSDavid S. Miller 	if (is_imm) {
672e3a724edSDavid S. Miller 		bool fits = true;
673e3a724edSDavid S. Miller 
674e3a724edSDavid S. Miller 		if (use_cbcond) {
675e3a724edSDavid S. Miller 			if (!is_simm5(imm))
676e3a724edSDavid S. Miller 				fits = false;
677e3a724edSDavid S. Miller 		} else if (!is_simm13(imm)) {
678e3a724edSDavid S. Miller 			fits = false;
679e3a724edSDavid S. Miller 		}
680e3a724edSDavid S. Miller 		if (!fits) {
681e3a724edSDavid S. Miller 			ctx->tmp_1_used = true;
682e3a724edSDavid S. Miller 			emit_loadimm_sext(imm, tmp, ctx);
683e3a724edSDavid S. Miller 			src = tmp;
684e3a724edSDavid S. Miller 			is_imm = false;
685e3a724edSDavid S. Miller 		}
686e3a724edSDavid S. Miller 	}
687e3a724edSDavid S. Miller 
688e3a724edSDavid S. Miller 	if (!use_cbcond) {
689e3a724edSDavid S. Miller 		u32 br_opcode;
690e3a724edSDavid S. Miller 
691e3a724edSDavid S. Miller 		if (BPF_OP(code) == BPF_JSET) {
692e3a724edSDavid S. Miller 			if (is_imm)
693e3a724edSDavid S. Miller 				emit_btsti(dst, imm, ctx);
694e3a724edSDavid S. Miller 			else
695e3a724edSDavid S. Miller 				emit_btst(dst, src, ctx);
696e3a724edSDavid S. Miller 		} else {
697e3a724edSDavid S. Miller 			if (is_imm)
698e3a724edSDavid S. Miller 				emit_cmpi(dst, imm, ctx);
699e3a724edSDavid S. Miller 			else
700e3a724edSDavid S. Miller 				emit_cmp(dst, src, ctx);
701e3a724edSDavid S. Miller 		}
702e3a724edSDavid S. Miller 		switch (BPF_OP(code)) {
703e3a724edSDavid S. Miller 		case BPF_JEQ:
704e3a724edSDavid S. Miller 			br_opcode = BE;
705e3a724edSDavid S. Miller 			break;
706e3a724edSDavid S. Miller 		case BPF_JGT:
707e3a724edSDavid S. Miller 			br_opcode = BGU;
708e3a724edSDavid S. Miller 			break;
70918423550SDaniel Borkmann 		case BPF_JLT:
71018423550SDaniel Borkmann 			br_opcode = BLU;
71118423550SDaniel Borkmann 			break;
712e3a724edSDavid S. Miller 		case BPF_JGE:
713e3a724edSDavid S. Miller 			br_opcode = BGEU;
714e3a724edSDavid S. Miller 			break;
71518423550SDaniel Borkmann 		case BPF_JLE:
71618423550SDaniel Borkmann 			br_opcode = BLEU;
71718423550SDaniel Borkmann 			break;
718e3a724edSDavid S. Miller 		case BPF_JSET:
719e3a724edSDavid S. Miller 		case BPF_JNE:
720e3a724edSDavid S. Miller 			br_opcode = BNE;
721e3a724edSDavid S. Miller 			break;
722e3a724edSDavid S. Miller 		case BPF_JSGT:
723e3a724edSDavid S. Miller 			br_opcode = BG;
724e3a724edSDavid S. Miller 			break;
72518423550SDaniel Borkmann 		case BPF_JSLT:
72618423550SDaniel Borkmann 			br_opcode = BL;
72718423550SDaniel Borkmann 			break;
728e3a724edSDavid S. Miller 		case BPF_JSGE:
729e3a724edSDavid S. Miller 			br_opcode = BGE;
730e3a724edSDavid S. Miller 			break;
73118423550SDaniel Borkmann 		case BPF_JSLE:
73218423550SDaniel Borkmann 			br_opcode = BLE;
73318423550SDaniel Borkmann 			break;
734e3a724edSDavid S. Miller 		default:
735e3a724edSDavid S. Miller 			/* Make sure we dont leak kernel information to the
736e3a724edSDavid S. Miller 			 * user.
737e3a724edSDavid S. Miller 			 */
738e3a724edSDavid S. Miller 			return -EFAULT;
739e3a724edSDavid S. Miller 		}
740e3a724edSDavid S. Miller 		emit_branch(br_opcode, ctx->idx, branch_dst, ctx);
741e3a724edSDavid S. Miller 		emit_nop(ctx);
742e3a724edSDavid S. Miller 	} else {
743e3a724edSDavid S. Miller 		u32 cbcond_opcode;
744e3a724edSDavid S. Miller 
745e3a724edSDavid S. Miller 		switch (BPF_OP(code)) {
746e3a724edSDavid S. Miller 		case BPF_JEQ:
747e3a724edSDavid S. Miller 			cbcond_opcode = CBCONDE;
748e3a724edSDavid S. Miller 			break;
749e3a724edSDavid S. Miller 		case BPF_JGT:
750e3a724edSDavid S. Miller 			cbcond_opcode = CBCONDGU;
751e3a724edSDavid S. Miller 			break;
75218423550SDaniel Borkmann 		case BPF_JLT:
75318423550SDaniel Borkmann 			cbcond_opcode = CBCONDLU;
75418423550SDaniel Borkmann 			break;
755e3a724edSDavid S. Miller 		case BPF_JGE:
756e3a724edSDavid S. Miller 			cbcond_opcode = CBCONDGEU;
757e3a724edSDavid S. Miller 			break;
75818423550SDaniel Borkmann 		case BPF_JLE:
75918423550SDaniel Borkmann 			cbcond_opcode = CBCONDLEU;
76018423550SDaniel Borkmann 			break;
761e3a724edSDavid S. Miller 		case BPF_JNE:
762e3a724edSDavid S. Miller 			cbcond_opcode = CBCONDNE;
763e3a724edSDavid S. Miller 			break;
764e3a724edSDavid S. Miller 		case BPF_JSGT:
765e3a724edSDavid S. Miller 			cbcond_opcode = CBCONDG;
766e3a724edSDavid S. Miller 			break;
76718423550SDaniel Borkmann 		case BPF_JSLT:
76818423550SDaniel Borkmann 			cbcond_opcode = CBCONDL;
76918423550SDaniel Borkmann 			break;
770e3a724edSDavid S. Miller 		case BPF_JSGE:
771e3a724edSDavid S. Miller 			cbcond_opcode = CBCONDGE;
772e3a724edSDavid S. Miller 			break;
77318423550SDaniel Borkmann 		case BPF_JSLE:
77418423550SDaniel Borkmann 			cbcond_opcode = CBCONDLE;
77518423550SDaniel Borkmann 			break;
776e3a724edSDavid S. Miller 		default:
777e3a724edSDavid S. Miller 			/* Make sure we dont leak kernel information to the
778e3a724edSDavid S. Miller 			 * user.
779e3a724edSDavid S. Miller 			 */
780e3a724edSDavid S. Miller 			return -EFAULT;
781e3a724edSDavid S. Miller 		}
782e3a724edSDavid S. Miller 		cbcond_opcode |= CBCOND_OP;
783e3a724edSDavid S. Miller 		if (is_imm)
784e3a724edSDavid S. Miller 			emit_cbcondi(cbcond_opcode, ctx->idx, branch_dst,
785e3a724edSDavid S. Miller 				     dst, imm, ctx);
786e3a724edSDavid S. Miller 		else
787e3a724edSDavid S. Miller 			emit_cbcond(cbcond_opcode, ctx->idx, branch_dst,
788e3a724edSDavid S. Miller 				    dst, src, ctx);
789e3a724edSDavid S. Miller 	}
790e3a724edSDavid S. Miller 	return 0;
791e3a724edSDavid S. Miller }
792e3a724edSDavid S. Miller 
7937a12b503SDavid S. Miller /* Just skip the save instruction and the ctx register move.  */
7942b9034b5SDavid Miller #define BPF_TAILCALL_PROLOGUE_SKIP	32
7957a12b503SDavid S. Miller #define BPF_TAILCALL_CNT_SP_OFF		(STACK_BIAS + 128)
7967a12b503SDavid S. Miller 
build_prologue(struct jit_ctx * ctx)7977a12b503SDavid S. Miller static void build_prologue(struct jit_ctx *ctx)
7987a12b503SDavid S. Miller {
7997a12b503SDavid S. Miller 	s32 stack_needed = BASE_STACKFRAME;
8007a12b503SDavid S. Miller 
801a5e2ee5dSDavid S. Miller 	if (ctx->saw_frame_pointer || ctx->saw_tail_call) {
802a5e2ee5dSDavid S. Miller 		struct bpf_prog *prog = ctx->prog;
803a5e2ee5dSDavid S. Miller 		u32 stack_depth;
804a5e2ee5dSDavid S. Miller 
805a5e2ee5dSDavid S. Miller 		stack_depth = prog->aux->stack_depth;
806a5e2ee5dSDavid S. Miller 		stack_needed += round_up(stack_depth, 16);
807a5e2ee5dSDavid S. Miller 	}
8087a12b503SDavid S. Miller 
8097a12b503SDavid S. Miller 	if (ctx->saw_tail_call)
8107a12b503SDavid S. Miller 		stack_needed += 8;
8117a12b503SDavid S. Miller 
8127a12b503SDavid S. Miller 	/* save %sp, -176, %sp */
8137a12b503SDavid S. Miller 	emit(SAVE | IMMED | RS1(SP) | S13(-stack_needed) | RD(SP), ctx);
8147a12b503SDavid S. Miller 
8157a12b503SDavid S. Miller 	/* tail_call_cnt = 0 */
8167a12b503SDavid S. Miller 	if (ctx->saw_tail_call) {
8177a12b503SDavid S. Miller 		u32 off = BPF_TAILCALL_CNT_SP_OFF;
8187a12b503SDavid S. Miller 
8197a12b503SDavid S. Miller 		emit(ST32 | IMMED | RS1(SP) | S13(off) | RD(G0), ctx);
8207a12b503SDavid S. Miller 	} else {
8217a12b503SDavid S. Miller 		emit_nop(ctx);
8227a12b503SDavid S. Miller 	}
8237a12b503SDavid S. Miller 	if (ctx->saw_frame_pointer) {
8247a12b503SDavid S. Miller 		const u8 vfp = bpf2sparc[BPF_REG_FP];
8257a12b503SDavid S. Miller 
8267a12b503SDavid S. Miller 		emit(ADD | IMMED | RS1(FP) | S13(STACK_BIAS) | RD(vfp), ctx);
8272b9034b5SDavid Miller 	} else {
8282b9034b5SDavid Miller 		emit_nop(ctx);
8297a12b503SDavid S. Miller 	}
8307a12b503SDavid S. Miller 
8317a12b503SDavid S. Miller 	emit_reg_move(I0, O0, ctx);
8322b9034b5SDavid Miller 	emit_reg_move(I1, O1, ctx);
8332b9034b5SDavid Miller 	emit_reg_move(I2, O2, ctx);
8342b9034b5SDavid Miller 	emit_reg_move(I3, O3, ctx);
8352b9034b5SDavid Miller 	emit_reg_move(I4, O4, ctx);
8367a12b503SDavid S. Miller 	/* If you add anything here, adjust BPF_TAILCALL_PROLOGUE_SKIP above. */
8377a12b503SDavid S. Miller }
8387a12b503SDavid S. Miller 
build_epilogue(struct jit_ctx * ctx)8397a12b503SDavid S. Miller static void build_epilogue(struct jit_ctx *ctx)
8407a12b503SDavid S. Miller {
8417a12b503SDavid S. Miller 	ctx->epilogue_offset = ctx->idx;
8427a12b503SDavid S. Miller 
8437a12b503SDavid S. Miller 	/* ret (jmpl %i7 + 8, %g0) */
8447a12b503SDavid S. Miller 	emit(JMPL | IMMED | RS1(I7) | S13(8) | RD(G0), ctx);
8457a12b503SDavid S. Miller 
8467a12b503SDavid S. Miller 	/* restore %i5, %g0, %o0 */
8477a12b503SDavid S. Miller 	emit(RESTORE | RS1(bpf2sparc[BPF_REG_0]) | RS2(G0) | RD(O0), ctx);
8487a12b503SDavid S. Miller }
8497a12b503SDavid S. Miller 
emit_tail_call(struct jit_ctx * ctx)8507a12b503SDavid S. Miller static void emit_tail_call(struct jit_ctx *ctx)
8517a12b503SDavid S. Miller {
8527a12b503SDavid S. Miller 	const u8 bpf_array = bpf2sparc[BPF_REG_2];
8537a12b503SDavid S. Miller 	const u8 bpf_index = bpf2sparc[BPF_REG_3];
8547a12b503SDavid S. Miller 	const u8 tmp = bpf2sparc[TMP_REG_1];
8557a12b503SDavid S. Miller 	u32 off;
8567a12b503SDavid S. Miller 
8577a12b503SDavid S. Miller 	ctx->saw_tail_call = true;
8587a12b503SDavid S. Miller 
8597a12b503SDavid S. Miller 	off = offsetof(struct bpf_array, map.max_entries);
8607a12b503SDavid S. Miller 	emit(LD32 | IMMED | RS1(bpf_array) | S13(off) | RD(tmp), ctx);
8617a12b503SDavid S. Miller 	emit_cmp(bpf_index, tmp, ctx);
8627a12b503SDavid S. Miller #define OFFSET1 17
8637a12b503SDavid S. Miller 	emit_branch(BGEU, ctx->idx, ctx->idx + OFFSET1, ctx);
8647a12b503SDavid S. Miller 	emit_nop(ctx);
8657a12b503SDavid S. Miller 
8667a12b503SDavid S. Miller 	off = BPF_TAILCALL_CNT_SP_OFF;
8677a12b503SDavid S. Miller 	emit(LD32 | IMMED | RS1(SP) | S13(off) | RD(tmp), ctx);
8687a12b503SDavid S. Miller 	emit_cmpi(tmp, MAX_TAIL_CALL_CNT, ctx);
8697a12b503SDavid S. Miller #define OFFSET2 13
870ebf7f6f0STiezhu Yang 	emit_branch(BGEU, ctx->idx, ctx->idx + OFFSET2, ctx);
8717a12b503SDavid S. Miller 	emit_nop(ctx);
8727a12b503SDavid S. Miller 
8737a12b503SDavid S. Miller 	emit_alu_K(ADD, tmp, 1, ctx);
8747a12b503SDavid S. Miller 	off = BPF_TAILCALL_CNT_SP_OFF;
8757a12b503SDavid S. Miller 	emit(ST32 | IMMED | RS1(SP) | S13(off) | RD(tmp), ctx);
8767a12b503SDavid S. Miller 
8777a12b503SDavid S. Miller 	emit_alu3_K(SLL, bpf_index, 3, tmp, ctx);
8787a12b503SDavid S. Miller 	emit_alu(ADD, bpf_array, tmp, ctx);
8797a12b503SDavid S. Miller 	off = offsetof(struct bpf_array, ptrs);
8807a12b503SDavid S. Miller 	emit(LD64 | IMMED | RS1(tmp) | S13(off) | RD(tmp), ctx);
8817a12b503SDavid S. Miller 
8827a12b503SDavid S. Miller 	emit_cmpi(tmp, 0, ctx);
8837a12b503SDavid S. Miller #define OFFSET3 5
8847a12b503SDavid S. Miller 	emit_branch(BE, ctx->idx, ctx->idx + OFFSET3, ctx);
8857a12b503SDavid S. Miller 	emit_nop(ctx);
8867a12b503SDavid S. Miller 
8877a12b503SDavid S. Miller 	off = offsetof(struct bpf_prog, bpf_func);
8887a12b503SDavid S. Miller 	emit(LD64 | IMMED | RS1(tmp) | S13(off) | RD(tmp), ctx);
8897a12b503SDavid S. Miller 
8907a12b503SDavid S. Miller 	off = BPF_TAILCALL_PROLOGUE_SKIP;
8917a12b503SDavid S. Miller 	emit(JMPL | IMMED | RS1(tmp) | S13(off) | RD(G0), ctx);
8927a12b503SDavid S. Miller 	emit_nop(ctx);
8937a12b503SDavid S. Miller }
8947a12b503SDavid S. Miller 
build_insn(const struct bpf_insn * insn,struct jit_ctx * ctx)8957a12b503SDavid S. Miller static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
8967a12b503SDavid S. Miller {
8977a12b503SDavid S. Miller 	const u8 code = insn->code;
8987a12b503SDavid S. Miller 	const u8 dst = bpf2sparc[insn->dst_reg];
8997a12b503SDavid S. Miller 	const u8 src = bpf2sparc[insn->src_reg];
9007a12b503SDavid S. Miller 	const int i = insn - ctx->prog->insnsi;
9017a12b503SDavid S. Miller 	const s16 off = insn->off;
9027a12b503SDavid S. Miller 	const s32 imm = insn->imm;
9037a12b503SDavid S. Miller 
9047a12b503SDavid S. Miller 	if (insn->src_reg == BPF_REG_FP)
9057a12b503SDavid S. Miller 		ctx->saw_frame_pointer = true;
9067a12b503SDavid S. Miller 
9077a12b503SDavid S. Miller 	switch (code) {
9087a12b503SDavid S. Miller 	/* dst = src */
9097a12b503SDavid S. Miller 	case BPF_ALU | BPF_MOV | BPF_X:
9107a12b503SDavid S. Miller 		emit_alu3_K(SRL, src, 0, dst, ctx);
9113e2a33cfSJiong Wang 		if (insn_is_zext(&insn[1]))
9123e2a33cfSJiong Wang 			return 1;
9137a12b503SDavid S. Miller 		break;
9147a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_MOV | BPF_X:
9157a12b503SDavid S. Miller 		emit_reg_move(src, dst, ctx);
9167a12b503SDavid S. Miller 		break;
9177a12b503SDavid S. Miller 	/* dst = dst OP src */
9187a12b503SDavid S. Miller 	case BPF_ALU | BPF_ADD | BPF_X:
9197a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_ADD | BPF_X:
9207a12b503SDavid S. Miller 		emit_alu(ADD, src, dst, ctx);
9217a12b503SDavid S. Miller 		goto do_alu32_trunc;
9227a12b503SDavid S. Miller 	case BPF_ALU | BPF_SUB | BPF_X:
9237a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_SUB | BPF_X:
9247a12b503SDavid S. Miller 		emit_alu(SUB, src, dst, ctx);
9257a12b503SDavid S. Miller 		goto do_alu32_trunc;
9267a12b503SDavid S. Miller 	case BPF_ALU | BPF_AND | BPF_X:
9277a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_AND | BPF_X:
9287a12b503SDavid S. Miller 		emit_alu(AND, src, dst, ctx);
9297a12b503SDavid S. Miller 		goto do_alu32_trunc;
9307a12b503SDavid S. Miller 	case BPF_ALU | BPF_OR | BPF_X:
9317a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_OR | BPF_X:
9327a12b503SDavid S. Miller 		emit_alu(OR, src, dst, ctx);
9337a12b503SDavid S. Miller 		goto do_alu32_trunc;
9347a12b503SDavid S. Miller 	case BPF_ALU | BPF_XOR | BPF_X:
9357a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_XOR | BPF_X:
9367a12b503SDavid S. Miller 		emit_alu(XOR, src, dst, ctx);
9377a12b503SDavid S. Miller 		goto do_alu32_trunc;
9387a12b503SDavid S. Miller 	case BPF_ALU | BPF_MUL | BPF_X:
9397a12b503SDavid S. Miller 		emit_alu(MUL, src, dst, ctx);
9407a12b503SDavid S. Miller 		goto do_alu32_trunc;
9417a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_MUL | BPF_X:
9427a12b503SDavid S. Miller 		emit_alu(MULX, src, dst, ctx);
9437a12b503SDavid S. Miller 		break;
9447a12b503SDavid S. Miller 	case BPF_ALU | BPF_DIV | BPF_X:
9457a12b503SDavid S. Miller 		emit_write_y(G0, ctx);
9467a12b503SDavid S. Miller 		emit_alu(DIV, src, dst, ctx);
9473e2a33cfSJiong Wang 		if (insn_is_zext(&insn[1]))
9483e2a33cfSJiong Wang 			return 1;
9497a12b503SDavid S. Miller 		break;
9507a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_DIV | BPF_X:
9517a12b503SDavid S. Miller 		emit_alu(UDIVX, src, dst, ctx);
9527a12b503SDavid S. Miller 		break;
9537a12b503SDavid S. Miller 	case BPF_ALU | BPF_MOD | BPF_X: {
9547a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
9557a12b503SDavid S. Miller 
9567a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
9577a12b503SDavid S. Miller 
9587a12b503SDavid S. Miller 		emit_write_y(G0, ctx);
9597a12b503SDavid S. Miller 		emit_alu3(DIV, dst, src, tmp, ctx);
9607a12b503SDavid S. Miller 		emit_alu3(MULX, tmp, src, tmp, ctx);
9617a12b503SDavid S. Miller 		emit_alu3(SUB, dst, tmp, dst, ctx);
9627a12b503SDavid S. Miller 		goto do_alu32_trunc;
9637a12b503SDavid S. Miller 	}
9647a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_MOD | BPF_X: {
9657a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
9667a12b503SDavid S. Miller 
9677a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
9687a12b503SDavid S. Miller 
9697a12b503SDavid S. Miller 		emit_alu3(UDIVX, dst, src, tmp, ctx);
9707a12b503SDavid S. Miller 		emit_alu3(MULX, tmp, src, tmp, ctx);
9717a12b503SDavid S. Miller 		emit_alu3(SUB, dst, tmp, dst, ctx);
9727a12b503SDavid S. Miller 		break;
9737a12b503SDavid S. Miller 	}
9747a12b503SDavid S. Miller 	case BPF_ALU | BPF_LSH | BPF_X:
9757a12b503SDavid S. Miller 		emit_alu(SLL, src, dst, ctx);
9767a12b503SDavid S. Miller 		goto do_alu32_trunc;
9777a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_LSH | BPF_X:
9787a12b503SDavid S. Miller 		emit_alu(SLLX, src, dst, ctx);
9797a12b503SDavid S. Miller 		break;
9807a12b503SDavid S. Miller 	case BPF_ALU | BPF_RSH | BPF_X:
9817a12b503SDavid S. Miller 		emit_alu(SRL, src, dst, ctx);
9823e2a33cfSJiong Wang 		if (insn_is_zext(&insn[1]))
9833e2a33cfSJiong Wang 			return 1;
9847a12b503SDavid S. Miller 		break;
9857a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_RSH | BPF_X:
9867a12b503SDavid S. Miller 		emit_alu(SRLX, src, dst, ctx);
9877a12b503SDavid S. Miller 		break;
9887a12b503SDavid S. Miller 	case BPF_ALU | BPF_ARSH | BPF_X:
9897a12b503SDavid S. Miller 		emit_alu(SRA, src, dst, ctx);
9907a12b503SDavid S. Miller 		goto do_alu32_trunc;
9917a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_ARSH | BPF_X:
9927a12b503SDavid S. Miller 		emit_alu(SRAX, src, dst, ctx);
9937a12b503SDavid S. Miller 		break;
9947a12b503SDavid S. Miller 
9957a12b503SDavid S. Miller 	/* dst = -dst */
9967a12b503SDavid S. Miller 	case BPF_ALU | BPF_NEG:
9977a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_NEG:
9987a12b503SDavid S. Miller 		emit(SUB | RS1(0) | RS2(dst) | RD(dst), ctx);
9997a12b503SDavid S. Miller 		goto do_alu32_trunc;
10007a12b503SDavid S. Miller 
10017a12b503SDavid S. Miller 	case BPF_ALU | BPF_END | BPF_FROM_BE:
10027a12b503SDavid S. Miller 		switch (imm) {
10037a12b503SDavid S. Miller 		case 16:
10047a12b503SDavid S. Miller 			emit_alu_K(SLL, dst, 16, ctx);
10057a12b503SDavid S. Miller 			emit_alu_K(SRL, dst, 16, ctx);
10063e2a33cfSJiong Wang 			if (insn_is_zext(&insn[1]))
10073e2a33cfSJiong Wang 				return 1;
10087a12b503SDavid S. Miller 			break;
10097a12b503SDavid S. Miller 		case 32:
10103e2a33cfSJiong Wang 			if (!ctx->prog->aux->verifier_zext)
10117a12b503SDavid S. Miller 				emit_alu_K(SRL, dst, 0, ctx);
10127a12b503SDavid S. Miller 			break;
10137a12b503SDavid S. Miller 		case 64:
10147a12b503SDavid S. Miller 			/* nop */
10157a12b503SDavid S. Miller 			break;
10167a12b503SDavid S. Miller 
10177a12b503SDavid S. Miller 		}
10187a12b503SDavid S. Miller 		break;
10197a12b503SDavid S. Miller 
10207a12b503SDavid S. Miller 	/* dst = BSWAP##imm(dst) */
10217a12b503SDavid S. Miller 	case BPF_ALU | BPF_END | BPF_FROM_LE: {
10227a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
10237a12b503SDavid S. Miller 		const u8 tmp2 = bpf2sparc[TMP_REG_2];
10247a12b503SDavid S. Miller 
10257a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
10267a12b503SDavid S. Miller 		switch (imm) {
10277a12b503SDavid S. Miller 		case 16:
10287a12b503SDavid S. Miller 			emit_alu3_K(AND, dst, 0xff, tmp, ctx);
10297a12b503SDavid S. Miller 			emit_alu3_K(SRL, dst, 8, dst, ctx);
10307a12b503SDavid S. Miller 			emit_alu3_K(AND, dst, 0xff, dst, ctx);
10317a12b503SDavid S. Miller 			emit_alu3_K(SLL, tmp, 8, tmp, ctx);
10327a12b503SDavid S. Miller 			emit_alu(OR, tmp, dst, ctx);
10333e2a33cfSJiong Wang 			if (insn_is_zext(&insn[1]))
10343e2a33cfSJiong Wang 				return 1;
10357a12b503SDavid S. Miller 			break;
10367a12b503SDavid S. Miller 
10377a12b503SDavid S. Miller 		case 32:
10387a12b503SDavid S. Miller 			ctx->tmp_2_used = true;
10397a12b503SDavid S. Miller 			emit_alu3_K(SRL, dst, 24, tmp, ctx);	/* tmp  = dst >> 24 */
10407a12b503SDavid S. Miller 			emit_alu3_K(SRL, dst, 16, tmp2, ctx);	/* tmp2 = dst >> 16 */
10417a12b503SDavid S. Miller 			emit_alu3_K(AND, tmp2, 0xff, tmp2, ctx);/* tmp2 = tmp2 & 0xff */
10427a12b503SDavid S. Miller 			emit_alu3_K(SLL, tmp2, 8, tmp2, ctx);	/* tmp2 = tmp2 << 8 */
10437a12b503SDavid S. Miller 			emit_alu(OR, tmp2, tmp, ctx);		/* tmp  = tmp | tmp2 */
10447a12b503SDavid S. Miller 			emit_alu3_K(SRL, dst, 8, tmp2, ctx);	/* tmp2 = dst >> 8 */
10457a12b503SDavid S. Miller 			emit_alu3_K(AND, tmp2, 0xff, tmp2, ctx);/* tmp2 = tmp2 & 0xff */
10467a12b503SDavid S. Miller 			emit_alu3_K(SLL, tmp2, 16, tmp2, ctx);	/* tmp2 = tmp2 << 16 */
10477a12b503SDavid S. Miller 			emit_alu(OR, tmp2, tmp, ctx);		/* tmp  = tmp | tmp2 */
10487a12b503SDavid S. Miller 			emit_alu3_K(AND, dst, 0xff, dst, ctx);	/* dst	= dst & 0xff */
10497a12b503SDavid S. Miller 			emit_alu3_K(SLL, dst, 24, dst, ctx);	/* dst  = dst << 24 */
10507a12b503SDavid S. Miller 			emit_alu(OR, tmp, dst, ctx);		/* dst  = dst | tmp */
10513e2a33cfSJiong Wang 			if (insn_is_zext(&insn[1]))
10523e2a33cfSJiong Wang 				return 1;
10537a12b503SDavid S. Miller 			break;
10547a12b503SDavid S. Miller 
10557a12b503SDavid S. Miller 		case 64:
10567a12b503SDavid S. Miller 			emit_alu3_K(ADD, SP, STACK_BIAS + 128, tmp, ctx);
10577a12b503SDavid S. Miller 			emit(ST64 | RS1(tmp) | RS2(G0) | RD(dst), ctx);
10587a12b503SDavid S. Miller 			emit(LD64A | ASI(ASI_PL) | RS1(tmp) | RS2(G0) | RD(dst), ctx);
10597a12b503SDavid S. Miller 			break;
10607a12b503SDavid S. Miller 		}
10617a12b503SDavid S. Miller 		break;
10627a12b503SDavid S. Miller 	}
10637a12b503SDavid S. Miller 	/* dst = imm */
10647a12b503SDavid S. Miller 	case BPF_ALU | BPF_MOV | BPF_K:
10657a12b503SDavid S. Miller 		emit_loadimm32(imm, dst, ctx);
10663e2a33cfSJiong Wang 		if (insn_is_zext(&insn[1]))
10673e2a33cfSJiong Wang 			return 1;
10687a12b503SDavid S. Miller 		break;
10697a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_MOV | BPF_K:
10707a12b503SDavid S. Miller 		emit_loadimm_sext(imm, dst, ctx);
10717a12b503SDavid S. Miller 		break;
10727a12b503SDavid S. Miller 	/* dst = dst OP imm */
10737a12b503SDavid S. Miller 	case BPF_ALU | BPF_ADD | BPF_K:
10747a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_ADD | BPF_K:
10757a12b503SDavid S. Miller 		emit_alu_K(ADD, dst, imm, ctx);
10767a12b503SDavid S. Miller 		goto do_alu32_trunc;
10777a12b503SDavid S. Miller 	case BPF_ALU | BPF_SUB | BPF_K:
10787a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_SUB | BPF_K:
10797a12b503SDavid S. Miller 		emit_alu_K(SUB, dst, imm, ctx);
10807a12b503SDavid S. Miller 		goto do_alu32_trunc;
10817a12b503SDavid S. Miller 	case BPF_ALU | BPF_AND | BPF_K:
10827a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_AND | BPF_K:
10837a12b503SDavid S. Miller 		emit_alu_K(AND, dst, imm, ctx);
10847a12b503SDavid S. Miller 		goto do_alu32_trunc;
10857a12b503SDavid S. Miller 	case BPF_ALU | BPF_OR | BPF_K:
10867a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_OR | BPF_K:
10877a12b503SDavid S. Miller 		emit_alu_K(OR, dst, imm, ctx);
10887a12b503SDavid S. Miller 		goto do_alu32_trunc;
10897a12b503SDavid S. Miller 	case BPF_ALU | BPF_XOR | BPF_K:
10907a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_XOR | BPF_K:
10917a12b503SDavid S. Miller 		emit_alu_K(XOR, dst, imm, ctx);
10927a12b503SDavid S. Miller 		goto do_alu32_trunc;
10937a12b503SDavid S. Miller 	case BPF_ALU | BPF_MUL | BPF_K:
10947a12b503SDavid S. Miller 		emit_alu_K(MUL, dst, imm, ctx);
10957a12b503SDavid S. Miller 		goto do_alu32_trunc;
10967a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_MUL | BPF_K:
10977a12b503SDavid S. Miller 		emit_alu_K(MULX, dst, imm, ctx);
10987a12b503SDavid S. Miller 		break;
10997a12b503SDavid S. Miller 	case BPF_ALU | BPF_DIV | BPF_K:
11007a12b503SDavid S. Miller 		if (imm == 0)
11017a12b503SDavid S. Miller 			return -EINVAL;
11027a12b503SDavid S. Miller 
11037a12b503SDavid S. Miller 		emit_write_y(G0, ctx);
11047a12b503SDavid S. Miller 		emit_alu_K(DIV, dst, imm, ctx);
11057a12b503SDavid S. Miller 		goto do_alu32_trunc;
11067a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_DIV | BPF_K:
11077a12b503SDavid S. Miller 		if (imm == 0)
11087a12b503SDavid S. Miller 			return -EINVAL;
11097a12b503SDavid S. Miller 
11107a12b503SDavid S. Miller 		emit_alu_K(UDIVX, dst, imm, ctx);
11117a12b503SDavid S. Miller 		break;
11127a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_MOD | BPF_K:
11137a12b503SDavid S. Miller 	case BPF_ALU | BPF_MOD | BPF_K: {
11147a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_2];
11157a12b503SDavid S. Miller 		unsigned int div;
11167a12b503SDavid S. Miller 
11177a12b503SDavid S. Miller 		if (imm == 0)
11187a12b503SDavid S. Miller 			return -EINVAL;
11197a12b503SDavid S. Miller 
11207a12b503SDavid S. Miller 		div = (BPF_CLASS(code) == BPF_ALU64) ? UDIVX : DIV;
11217a12b503SDavid S. Miller 
11227a12b503SDavid S. Miller 		ctx->tmp_2_used = true;
11237a12b503SDavid S. Miller 
11247a12b503SDavid S. Miller 		if (BPF_CLASS(code) != BPF_ALU64)
11257a12b503SDavid S. Miller 			emit_write_y(G0, ctx);
11267a12b503SDavid S. Miller 		if (is_simm13(imm)) {
11277a12b503SDavid S. Miller 			emit(div | IMMED | RS1(dst) | S13(imm) | RD(tmp), ctx);
11287a12b503SDavid S. Miller 			emit(MULX | IMMED | RS1(tmp) | S13(imm) | RD(tmp), ctx);
11297a12b503SDavid S. Miller 			emit(SUB | RS1(dst) | RS2(tmp) | RD(dst), ctx);
11307a12b503SDavid S. Miller 		} else {
11317a12b503SDavid S. Miller 			const u8 tmp1 = bpf2sparc[TMP_REG_1];
11327a12b503SDavid S. Miller 
11337a12b503SDavid S. Miller 			ctx->tmp_1_used = true;
11347a12b503SDavid S. Miller 
11357a12b503SDavid S. Miller 			emit_set_const_sext(imm, tmp1, ctx);
11367a12b503SDavid S. Miller 			emit(div | RS1(dst) | RS2(tmp1) | RD(tmp), ctx);
11377a12b503SDavid S. Miller 			emit(MULX | RS1(tmp) | RS2(tmp1) | RD(tmp), ctx);
11387a12b503SDavid S. Miller 			emit(SUB | RS1(dst) | RS2(tmp) | RD(dst), ctx);
11397a12b503SDavid S. Miller 		}
11407a12b503SDavid S. Miller 		goto do_alu32_trunc;
11417a12b503SDavid S. Miller 	}
11427a12b503SDavid S. Miller 	case BPF_ALU | BPF_LSH | BPF_K:
11437a12b503SDavid S. Miller 		emit_alu_K(SLL, dst, imm, ctx);
11447a12b503SDavid S. Miller 		goto do_alu32_trunc;
11457a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_LSH | BPF_K:
11467a12b503SDavid S. Miller 		emit_alu_K(SLLX, dst, imm, ctx);
11477a12b503SDavid S. Miller 		break;
11487a12b503SDavid S. Miller 	case BPF_ALU | BPF_RSH | BPF_K:
11497a12b503SDavid S. Miller 		emit_alu_K(SRL, dst, imm, ctx);
11503e2a33cfSJiong Wang 		if (insn_is_zext(&insn[1]))
11513e2a33cfSJiong Wang 			return 1;
11527a12b503SDavid S. Miller 		break;
11537a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_RSH | BPF_K:
11547a12b503SDavid S. Miller 		emit_alu_K(SRLX, dst, imm, ctx);
11557a12b503SDavid S. Miller 		break;
11567a12b503SDavid S. Miller 	case BPF_ALU | BPF_ARSH | BPF_K:
11577a12b503SDavid S. Miller 		emit_alu_K(SRA, dst, imm, ctx);
11587a12b503SDavid S. Miller 		goto do_alu32_trunc;
11597a12b503SDavid S. Miller 	case BPF_ALU64 | BPF_ARSH | BPF_K:
11607a12b503SDavid S. Miller 		emit_alu_K(SRAX, dst, imm, ctx);
11617a12b503SDavid S. Miller 		break;
11627a12b503SDavid S. Miller 
11637a12b503SDavid S. Miller 	do_alu32_trunc:
11643e2a33cfSJiong Wang 		if (BPF_CLASS(code) == BPF_ALU &&
11653e2a33cfSJiong Wang 		    !ctx->prog->aux->verifier_zext)
11667a12b503SDavid S. Miller 			emit_alu_K(SRL, dst, 0, ctx);
11677a12b503SDavid S. Miller 		break;
11687a12b503SDavid S. Miller 
11697a12b503SDavid S. Miller 	/* JUMP off */
11707a12b503SDavid S. Miller 	case BPF_JMP | BPF_JA:
11717a12b503SDavid S. Miller 		emit_branch(BA, ctx->idx, ctx->offset[i + off], ctx);
11727a12b503SDavid S. Miller 		emit_nop(ctx);
11737a12b503SDavid S. Miller 		break;
11747a12b503SDavid S. Miller 	/* IF (dst COND src) JUMP off */
11757a12b503SDavid S. Miller 	case BPF_JMP | BPF_JEQ | BPF_X:
11767a12b503SDavid S. Miller 	case BPF_JMP | BPF_JGT | BPF_X:
117718423550SDaniel Borkmann 	case BPF_JMP | BPF_JLT | BPF_X:
11787a12b503SDavid S. Miller 	case BPF_JMP | BPF_JGE | BPF_X:
117918423550SDaniel Borkmann 	case BPF_JMP | BPF_JLE | BPF_X:
11807a12b503SDavid S. Miller 	case BPF_JMP | BPF_JNE | BPF_X:
11817a12b503SDavid S. Miller 	case BPF_JMP | BPF_JSGT | BPF_X:
118218423550SDaniel Borkmann 	case BPF_JMP | BPF_JSLT | BPF_X:
1183e3a724edSDavid S. Miller 	case BPF_JMP | BPF_JSGE | BPF_X:
118418423550SDaniel Borkmann 	case BPF_JMP | BPF_JSLE | BPF_X:
1185e3a724edSDavid S. Miller 	case BPF_JMP | BPF_JSET | BPF_X: {
1186e3a724edSDavid S. Miller 		int err;
11877a12b503SDavid S. Miller 
1188e3a724edSDavid S. Miller 		err = emit_compare_and_branch(code, dst, src, 0, false, i + off, ctx);
1189e3a724edSDavid S. Miller 		if (err)
1190e3a724edSDavid S. Miller 			return err;
11917a12b503SDavid S. Miller 		break;
11927a12b503SDavid S. Miller 	}
11937a12b503SDavid S. Miller 	/* IF (dst COND imm) JUMP off */
11947a12b503SDavid S. Miller 	case BPF_JMP | BPF_JEQ | BPF_K:
11957a12b503SDavid S. Miller 	case BPF_JMP | BPF_JGT | BPF_K:
119618423550SDaniel Borkmann 	case BPF_JMP | BPF_JLT | BPF_K:
11977a12b503SDavid S. Miller 	case BPF_JMP | BPF_JGE | BPF_K:
119818423550SDaniel Borkmann 	case BPF_JMP | BPF_JLE | BPF_K:
11997a12b503SDavid S. Miller 	case BPF_JMP | BPF_JNE | BPF_K:
12007a12b503SDavid S. Miller 	case BPF_JMP | BPF_JSGT | BPF_K:
120118423550SDaniel Borkmann 	case BPF_JMP | BPF_JSLT | BPF_K:
12027a12b503SDavid S. Miller 	case BPF_JMP | BPF_JSGE | BPF_K:
120318423550SDaniel Borkmann 	case BPF_JMP | BPF_JSLE | BPF_K:
1204e3a724edSDavid S. Miller 	case BPF_JMP | BPF_JSET | BPF_K: {
1205e3a724edSDavid S. Miller 		int err;
1206e3a724edSDavid S. Miller 
1207e3a724edSDavid S. Miller 		err = emit_compare_and_branch(code, dst, 0, imm, true, i + off, ctx);
1208e3a724edSDavid S. Miller 		if (err)
1209e3a724edSDavid S. Miller 			return err;
1210e3a724edSDavid S. Miller 		break;
12117a12b503SDavid S. Miller 	}
12127a12b503SDavid S. Miller 
12137a12b503SDavid S. Miller 	/* function call */
12147a12b503SDavid S. Miller 	case BPF_JMP | BPF_CALL:
12157a12b503SDavid S. Miller 	{
12167a12b503SDavid S. Miller 		u8 *func = ((u8 *)__bpf_call_base) + imm;
12177a12b503SDavid S. Miller 
12187a12b503SDavid S. Miller 		ctx->saw_call = true;
12197a12b503SDavid S. Miller 
12207a12b503SDavid S. Miller 		emit_call((u32 *)func, ctx);
12217a12b503SDavid S. Miller 		emit_nop(ctx);
12227a12b503SDavid S. Miller 
12237a12b503SDavid S. Miller 		emit_reg_move(O0, bpf2sparc[BPF_REG_0], ctx);
12247a12b503SDavid S. Miller 		break;
12257a12b503SDavid S. Miller 	}
12267a12b503SDavid S. Miller 
12277a12b503SDavid S. Miller 	/* tail call */
122871189fa9SAlexei Starovoitov 	case BPF_JMP | BPF_TAIL_CALL:
12297a12b503SDavid S. Miller 		emit_tail_call(ctx);
12307a12b503SDavid S. Miller 		break;
12317a12b503SDavid S. Miller 
12327a12b503SDavid S. Miller 	/* function return */
12337a12b503SDavid S. Miller 	case BPF_JMP | BPF_EXIT:
12347a12b503SDavid S. Miller 		/* Optimization: when last instruction is EXIT,
12357a12b503SDavid S. Miller 		   simply fallthrough to epilogue. */
12367a12b503SDavid S. Miller 		if (i == ctx->prog->len - 1)
12377a12b503SDavid S. Miller 			break;
12387a12b503SDavid S. Miller 		emit_branch(BA, ctx->idx, ctx->epilogue_offset, ctx);
12397a12b503SDavid S. Miller 		emit_nop(ctx);
12407a12b503SDavid S. Miller 		break;
12417a12b503SDavid S. Miller 
12427a12b503SDavid S. Miller 	/* dst = imm64 */
12437a12b503SDavid S. Miller 	case BPF_LD | BPF_IMM | BPF_DW:
12447a12b503SDavid S. Miller 	{
12457a12b503SDavid S. Miller 		const struct bpf_insn insn1 = insn[1];
12467a12b503SDavid S. Miller 		u64 imm64;
12477a12b503SDavid S. Miller 
12487a12b503SDavid S. Miller 		imm64 = (u64)insn1.imm << 32 | (u32)imm;
12497a12b503SDavid S. Miller 		emit_loadimm64(imm64, dst, ctx);
12507a12b503SDavid S. Miller 
12517a12b503SDavid S. Miller 		return 1;
12527a12b503SDavid S. Miller 	}
12537a12b503SDavid S. Miller 
12547a12b503SDavid S. Miller 	/* LDX: dst = *(size *)(src + off) */
12557a12b503SDavid S. Miller 	case BPF_LDX | BPF_MEM | BPF_W:
12567a12b503SDavid S. Miller 	case BPF_LDX | BPF_MEM | BPF_H:
12577a12b503SDavid S. Miller 	case BPF_LDX | BPF_MEM | BPF_B:
12587a12b503SDavid S. Miller 	case BPF_LDX | BPF_MEM | BPF_DW: {
12597a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
12607a12b503SDavid S. Miller 		u32 opcode = 0, rs2;
12617a12b503SDavid S. Miller 
12627a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
12637a12b503SDavid S. Miller 		switch (BPF_SIZE(code)) {
12647a12b503SDavid S. Miller 		case BPF_W:
12657a12b503SDavid S. Miller 			opcode = LD32;
12667a12b503SDavid S. Miller 			break;
12677a12b503SDavid S. Miller 		case BPF_H:
12687a12b503SDavid S. Miller 			opcode = LD16;
12697a12b503SDavid S. Miller 			break;
12707a12b503SDavid S. Miller 		case BPF_B:
12717a12b503SDavid S. Miller 			opcode = LD8;
12727a12b503SDavid S. Miller 			break;
12737a12b503SDavid S. Miller 		case BPF_DW:
12747a12b503SDavid S. Miller 			opcode = LD64;
12757a12b503SDavid S. Miller 			break;
12767a12b503SDavid S. Miller 		}
12777a12b503SDavid S. Miller 
12787a12b503SDavid S. Miller 		if (is_simm13(off)) {
12797a12b503SDavid S. Miller 			opcode |= IMMED;
12807a12b503SDavid S. Miller 			rs2 = S13(off);
12817a12b503SDavid S. Miller 		} else {
12827a12b503SDavid S. Miller 			emit_loadimm(off, tmp, ctx);
12837a12b503SDavid S. Miller 			rs2 = RS2(tmp);
12847a12b503SDavid S. Miller 		}
12857a12b503SDavid S. Miller 		emit(opcode | RS1(src) | rs2 | RD(dst), ctx);
12863e2a33cfSJiong Wang 		if (opcode != LD64 && insn_is_zext(&insn[1]))
12873e2a33cfSJiong Wang 			return 1;
12887a12b503SDavid S. Miller 		break;
12897a12b503SDavid S. Miller 	}
1290f5e81d11SDaniel Borkmann 	/* speculation barrier */
1291f5e81d11SDaniel Borkmann 	case BPF_ST | BPF_NOSPEC:
1292f5e81d11SDaniel Borkmann 		break;
12937a12b503SDavid S. Miller 	/* ST: *(size *)(dst + off) = imm */
12947a12b503SDavid S. Miller 	case BPF_ST | BPF_MEM | BPF_W:
12957a12b503SDavid S. Miller 	case BPF_ST | BPF_MEM | BPF_H:
12967a12b503SDavid S. Miller 	case BPF_ST | BPF_MEM | BPF_B:
12977a12b503SDavid S. Miller 	case BPF_ST | BPF_MEM | BPF_DW: {
12987a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
12997a12b503SDavid S. Miller 		const u8 tmp2 = bpf2sparc[TMP_REG_2];
13007a12b503SDavid S. Miller 		u32 opcode = 0, rs2;
13017a12b503SDavid S. Miller 
1302e2ac579aSDavid Miller 		if (insn->dst_reg == BPF_REG_FP)
1303e2ac579aSDavid Miller 			ctx->saw_frame_pointer = true;
1304e2ac579aSDavid Miller 
13057a12b503SDavid S. Miller 		ctx->tmp_2_used = true;
13067a12b503SDavid S. Miller 		emit_loadimm(imm, tmp2, ctx);
13077a12b503SDavid S. Miller 
13087a12b503SDavid S. Miller 		switch (BPF_SIZE(code)) {
13097a12b503SDavid S. Miller 		case BPF_W:
13107a12b503SDavid S. Miller 			opcode = ST32;
13117a12b503SDavid S. Miller 			break;
13127a12b503SDavid S. Miller 		case BPF_H:
13137a12b503SDavid S. Miller 			opcode = ST16;
13147a12b503SDavid S. Miller 			break;
13157a12b503SDavid S. Miller 		case BPF_B:
13167a12b503SDavid S. Miller 			opcode = ST8;
13177a12b503SDavid S. Miller 			break;
13187a12b503SDavid S. Miller 		case BPF_DW:
13197a12b503SDavid S. Miller 			opcode = ST64;
13207a12b503SDavid S. Miller 			break;
13217a12b503SDavid S. Miller 		}
13227a12b503SDavid S. Miller 
13237a12b503SDavid S. Miller 		if (is_simm13(off)) {
13247a12b503SDavid S. Miller 			opcode |= IMMED;
13257a12b503SDavid S. Miller 			rs2 = S13(off);
13267a12b503SDavid S. Miller 		} else {
13277a12b503SDavid S. Miller 			ctx->tmp_1_used = true;
13287a12b503SDavid S. Miller 			emit_loadimm(off, tmp, ctx);
13297a12b503SDavid S. Miller 			rs2 = RS2(tmp);
13307a12b503SDavid S. Miller 		}
13317a12b503SDavid S. Miller 		emit(opcode | RS1(dst) | rs2 | RD(tmp2), ctx);
13327a12b503SDavid S. Miller 		break;
13337a12b503SDavid S. Miller 	}
13347a12b503SDavid S. Miller 
13357a12b503SDavid S. Miller 	/* STX: *(size *)(dst + off) = src */
13367a12b503SDavid S. Miller 	case BPF_STX | BPF_MEM | BPF_W:
13377a12b503SDavid S. Miller 	case BPF_STX | BPF_MEM | BPF_H:
13387a12b503SDavid S. Miller 	case BPF_STX | BPF_MEM | BPF_B:
13397a12b503SDavid S. Miller 	case BPF_STX | BPF_MEM | BPF_DW: {
13407a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
13417a12b503SDavid S. Miller 		u32 opcode = 0, rs2;
13427a12b503SDavid S. Miller 
1343e2ac579aSDavid Miller 		if (insn->dst_reg == BPF_REG_FP)
1344e2ac579aSDavid Miller 			ctx->saw_frame_pointer = true;
1345e2ac579aSDavid Miller 
13467a12b503SDavid S. Miller 		switch (BPF_SIZE(code)) {
13477a12b503SDavid S. Miller 		case BPF_W:
13487a12b503SDavid S. Miller 			opcode = ST32;
13497a12b503SDavid S. Miller 			break;
13507a12b503SDavid S. Miller 		case BPF_H:
13517a12b503SDavid S. Miller 			opcode = ST16;
13527a12b503SDavid S. Miller 			break;
13537a12b503SDavid S. Miller 		case BPF_B:
13547a12b503SDavid S. Miller 			opcode = ST8;
13557a12b503SDavid S. Miller 			break;
13567a12b503SDavid S. Miller 		case BPF_DW:
13577a12b503SDavid S. Miller 			opcode = ST64;
13587a12b503SDavid S. Miller 			break;
13597a12b503SDavid S. Miller 		}
13607a12b503SDavid S. Miller 		if (is_simm13(off)) {
13617a12b503SDavid S. Miller 			opcode |= IMMED;
13627a12b503SDavid S. Miller 			rs2 = S13(off);
13637a12b503SDavid S. Miller 		} else {
13647a12b503SDavid S. Miller 			ctx->tmp_1_used = true;
13657a12b503SDavid S. Miller 			emit_loadimm(off, tmp, ctx);
13667a12b503SDavid S. Miller 			rs2 = RS2(tmp);
13677a12b503SDavid S. Miller 		}
13687a12b503SDavid S. Miller 		emit(opcode | RS1(dst) | rs2 | RD(src), ctx);
13697a12b503SDavid S. Miller 		break;
13707a12b503SDavid S. Miller 	}
13717a12b503SDavid S. Miller 
137291c960b0SBrendan Jackman 	case BPF_STX | BPF_ATOMIC | BPF_W: {
13737a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
13747a12b503SDavid S. Miller 		const u8 tmp2 = bpf2sparc[TMP_REG_2];
13757a12b503SDavid S. Miller 		const u8 tmp3 = bpf2sparc[TMP_REG_3];
13767a12b503SDavid S. Miller 
137791c960b0SBrendan Jackman 		if (insn->imm != BPF_ADD) {
137891c960b0SBrendan Jackman 			pr_err_once("unknown atomic op %02x\n", insn->imm);
137991c960b0SBrendan Jackman 			return -EINVAL;
138091c960b0SBrendan Jackman 		}
138191c960b0SBrendan Jackman 
138291c960b0SBrendan Jackman 		/* lock *(u32 *)(dst + off) += src */
138391c960b0SBrendan Jackman 
1384e2ac579aSDavid Miller 		if (insn->dst_reg == BPF_REG_FP)
1385e2ac579aSDavid Miller 			ctx->saw_frame_pointer = true;
1386e2ac579aSDavid Miller 
13877a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
13887a12b503SDavid S. Miller 		ctx->tmp_2_used = true;
13897a12b503SDavid S. Miller 		ctx->tmp_3_used = true;
13907a12b503SDavid S. Miller 		emit_loadimm(off, tmp, ctx);
13917a12b503SDavid S. Miller 		emit_alu3(ADD, dst, tmp, tmp, ctx);
13927a12b503SDavid S. Miller 
13937a12b503SDavid S. Miller 		emit(LD32 | RS1(tmp) | RS2(G0) | RD(tmp2), ctx);
13947a12b503SDavid S. Miller 		emit_alu3(ADD, tmp2, src, tmp3, ctx);
13957a12b503SDavid S. Miller 		emit(CAS | ASI(ASI_P) | RS1(tmp) | RS2(tmp2) | RD(tmp3), ctx);
13967a12b503SDavid S. Miller 		emit_cmp(tmp2, tmp3, ctx);
13977a12b503SDavid S. Miller 		emit_branch(BNE, 4, 0, ctx);
13987a12b503SDavid S. Miller 		emit_nop(ctx);
13997a12b503SDavid S. Miller 		break;
14007a12b503SDavid S. Miller 	}
14017a12b503SDavid S. Miller 	/* STX XADD: lock *(u64 *)(dst + off) += src */
140291c960b0SBrendan Jackman 	case BPF_STX | BPF_ATOMIC | BPF_DW: {
14037a12b503SDavid S. Miller 		const u8 tmp = bpf2sparc[TMP_REG_1];
14047a12b503SDavid S. Miller 		const u8 tmp2 = bpf2sparc[TMP_REG_2];
14057a12b503SDavid S. Miller 		const u8 tmp3 = bpf2sparc[TMP_REG_3];
14067a12b503SDavid S. Miller 
140791c960b0SBrendan Jackman 		if (insn->imm != BPF_ADD) {
140891c960b0SBrendan Jackman 			pr_err_once("unknown atomic op %02x\n", insn->imm);
140991c960b0SBrendan Jackman 			return -EINVAL;
141091c960b0SBrendan Jackman 		}
141191c960b0SBrendan Jackman 
1412e2ac579aSDavid Miller 		if (insn->dst_reg == BPF_REG_FP)
1413e2ac579aSDavid Miller 			ctx->saw_frame_pointer = true;
1414e2ac579aSDavid Miller 
14157a12b503SDavid S. Miller 		ctx->tmp_1_used = true;
14167a12b503SDavid S. Miller 		ctx->tmp_2_used = true;
14177a12b503SDavid S. Miller 		ctx->tmp_3_used = true;
14187a12b503SDavid S. Miller 		emit_loadimm(off, tmp, ctx);
14197a12b503SDavid S. Miller 		emit_alu3(ADD, dst, tmp, tmp, ctx);
14207a12b503SDavid S. Miller 
14217a12b503SDavid S. Miller 		emit(LD64 | RS1(tmp) | RS2(G0) | RD(tmp2), ctx);
14227a12b503SDavid S. Miller 		emit_alu3(ADD, tmp2, src, tmp3, ctx);
14237a12b503SDavid S. Miller 		emit(CASX | ASI(ASI_P) | RS1(tmp) | RS2(tmp2) | RD(tmp3), ctx);
14247a12b503SDavid S. Miller 		emit_cmp(tmp2, tmp3, ctx);
14257a12b503SDavid S. Miller 		emit_branch(BNE, 4, 0, ctx);
14267a12b503SDavid S. Miller 		emit_nop(ctx);
14277a12b503SDavid S. Miller 		break;
14287a12b503SDavid S. Miller 	}
14297a12b503SDavid S. Miller 
14307a12b503SDavid S. Miller 	default:
14317a12b503SDavid S. Miller 		pr_err_once("unknown opcode %02x\n", code);
14327a12b503SDavid S. Miller 		return -EINVAL;
14337a12b503SDavid S. Miller 	}
14347a12b503SDavid S. Miller 
14357a12b503SDavid S. Miller 	return 0;
14367a12b503SDavid S. Miller }
14377a12b503SDavid S. Miller 
build_body(struct jit_ctx * ctx)14387a12b503SDavid S. Miller static int build_body(struct jit_ctx *ctx)
14397a12b503SDavid S. Miller {
14407a12b503SDavid S. Miller 	const struct bpf_prog *prog = ctx->prog;
14417a12b503SDavid S. Miller 	int i;
14427a12b503SDavid S. Miller 
14437a12b503SDavid S. Miller 	for (i = 0; i < prog->len; i++) {
14447a12b503SDavid S. Miller 		const struct bpf_insn *insn = &prog->insnsi[i];
14457a12b503SDavid S. Miller 		int ret;
14467a12b503SDavid S. Miller 
14477a12b503SDavid S. Miller 		ret = build_insn(insn, ctx);
14487a12b503SDavid S. Miller 
14497a12b503SDavid S. Miller 		if (ret > 0) {
14507a12b503SDavid S. Miller 			i++;
1451e3bf4c61SDavid S. Miller 			ctx->offset[i] = ctx->idx;
14527a12b503SDavid S. Miller 			continue;
14537a12b503SDavid S. Miller 		}
1454e3bf4c61SDavid S. Miller 		ctx->offset[i] = ctx->idx;
14557a12b503SDavid S. Miller 		if (ret)
14567a12b503SDavid S. Miller 			return ret;
14577a12b503SDavid S. Miller 	}
14587a12b503SDavid S. Miller 	return 0;
14597a12b503SDavid S. Miller }
14607a12b503SDavid S. Miller 
jit_fill_hole(void * area,unsigned int size)14617a12b503SDavid S. Miller static void jit_fill_hole(void *area, unsigned int size)
14627a12b503SDavid S. Miller {
14637a12b503SDavid S. Miller 	u32 *ptr;
14647a12b503SDavid S. Miller 	/* We are guaranteed to have aligned memory. */
14657a12b503SDavid S. Miller 	for (ptr = area; size >= sizeof(u32); size -= sizeof(u32))
14667a12b503SDavid S. Miller 		*ptr++ = 0x91d02005; /* ta 5 */
14677a12b503SDavid S. Miller }
14687a12b503SDavid S. Miller 
bpf_jit_needs_zext(void)14693e2a33cfSJiong Wang bool bpf_jit_needs_zext(void)
14703e2a33cfSJiong Wang {
14713e2a33cfSJiong Wang 	return true;
14723e2a33cfSJiong Wang }
14733e2a33cfSJiong Wang 
14745f5a6411SDavid Miller struct sparc64_jit_data {
14755f5a6411SDavid Miller 	struct bpf_binary_header *header;
14765f5a6411SDavid Miller 	u8 *image;
14775f5a6411SDavid Miller 	struct jit_ctx ctx;
14785f5a6411SDavid Miller };
14795f5a6411SDavid Miller 
bpf_int_jit_compile(struct bpf_prog * prog)14807a12b503SDavid S. Miller struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
14817a12b503SDavid S. Miller {
14827a12b503SDavid S. Miller 	struct bpf_prog *tmp, *orig_prog = prog;
14835f5a6411SDavid Miller 	struct sparc64_jit_data *jit_data;
14847a12b503SDavid S. Miller 	struct bpf_binary_header *header;
1485c44768a3SDavid Miller 	u32 prev_image_size, image_size;
14867a12b503SDavid S. Miller 	bool tmp_blinded = false;
14875f5a6411SDavid Miller 	bool extra_pass = false;
14887a12b503SDavid S. Miller 	struct jit_ctx ctx;
14897a12b503SDavid S. Miller 	u8 *image_ptr;
1490c44768a3SDavid Miller 	int pass, i;
14917a12b503SDavid S. Miller 
149260b58afcSAlexei Starovoitov 	if (!prog->jit_requested)
14937a12b503SDavid S. Miller 		return orig_prog;
14947a12b503SDavid S. Miller 
14957a12b503SDavid S. Miller 	tmp = bpf_jit_blind_constants(prog);
14967a12b503SDavid S. Miller 	/* If blinding was requested and we failed during blinding,
14977a12b503SDavid S. Miller 	 * we must fall back to the interpreter.
14987a12b503SDavid S. Miller 	 */
14997a12b503SDavid S. Miller 	if (IS_ERR(tmp))
15007a12b503SDavid S. Miller 		return orig_prog;
15017a12b503SDavid S. Miller 	if (tmp != prog) {
15027a12b503SDavid S. Miller 		tmp_blinded = true;
15037a12b503SDavid S. Miller 		prog = tmp;
15047a12b503SDavid S. Miller 	}
15057a12b503SDavid S. Miller 
15065f5a6411SDavid Miller 	jit_data = prog->aux->jit_data;
15075f5a6411SDavid Miller 	if (!jit_data) {
15085f5a6411SDavid Miller 		jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL);
15095f5a6411SDavid Miller 		if (!jit_data) {
15105f5a6411SDavid Miller 			prog = orig_prog;
15115f5a6411SDavid Miller 			goto out;
15125f5a6411SDavid Miller 		}
15135f5a6411SDavid Miller 		prog->aux->jit_data = jit_data;
15145f5a6411SDavid Miller 	}
15155f5a6411SDavid Miller 	if (jit_data->ctx.offset) {
15165f5a6411SDavid Miller 		ctx = jit_data->ctx;
15175f5a6411SDavid Miller 		image_ptr = jit_data->image;
15185f5a6411SDavid Miller 		header = jit_data->header;
15195f5a6411SDavid Miller 		extra_pass = true;
15205f5a6411SDavid Miller 		image_size = sizeof(u32) * ctx.idx;
1521c44768a3SDavid Miller 		prev_image_size = image_size;
1522c44768a3SDavid Miller 		pass = 1;
15235f5a6411SDavid Miller 		goto skip_init_ctx;
15245f5a6411SDavid Miller 	}
15255f5a6411SDavid Miller 
15267a12b503SDavid S. Miller 	memset(&ctx, 0, sizeof(ctx));
15277a12b503SDavid S. Miller 	ctx.prog = prog;
15287a12b503SDavid S. Miller 
1529c44768a3SDavid Miller 	ctx.offset = kmalloc_array(prog->len, sizeof(unsigned int), GFP_KERNEL);
15307a12b503SDavid S. Miller 	if (ctx.offset == NULL) {
15317a12b503SDavid S. Miller 		prog = orig_prog;
15325f5a6411SDavid Miller 		goto out_off;
15337a12b503SDavid S. Miller 	}
15347a12b503SDavid S. Miller 
1535c44768a3SDavid Miller 	/* Longest sequence emitted is for bswap32, 12 instructions.  Pre-cook
1536c44768a3SDavid Miller 	 * the offset array so that we converge faster.
15377a12b503SDavid S. Miller 	 */
1538c44768a3SDavid Miller 	for (i = 0; i < prog->len; i++)
1539c44768a3SDavid Miller 		ctx.offset[i] = i * (12 * 4);
1540c44768a3SDavid Miller 
1541c44768a3SDavid Miller 	prev_image_size = ~0U;
1542c44768a3SDavid Miller 	for (pass = 1; pass < 40; pass++) {
1543c44768a3SDavid Miller 		ctx.idx = 0;
1544c44768a3SDavid Miller 
1545c44768a3SDavid Miller 		build_prologue(&ctx);
15467a12b503SDavid S. Miller 		if (build_body(&ctx)) {
15477a12b503SDavid S. Miller 			prog = orig_prog;
15487a12b503SDavid S. Miller 			goto out_off;
15497a12b503SDavid S. Miller 		}
15507a12b503SDavid S. Miller 		build_epilogue(&ctx);
15517a12b503SDavid S. Miller 
1552c44768a3SDavid Miller 		if (bpf_jit_enable > 1)
1553c44768a3SDavid Miller 			pr_info("Pass %d: size = %u, seen = [%c%c%c%c%c%c]\n", pass,
1554c44768a3SDavid Miller 				ctx.idx * 4,
1555c44768a3SDavid Miller 				ctx.tmp_1_used ? '1' : ' ',
1556c44768a3SDavid Miller 				ctx.tmp_2_used ? '2' : ' ',
1557c44768a3SDavid Miller 				ctx.tmp_3_used ? '3' : ' ',
1558c44768a3SDavid Miller 				ctx.saw_frame_pointer ? 'F' : ' ',
1559c44768a3SDavid Miller 				ctx.saw_call ? 'C' : ' ',
1560c44768a3SDavid Miller 				ctx.saw_tail_call ? 'T' : ' ');
1561c44768a3SDavid Miller 
1562c44768a3SDavid Miller 		if (ctx.idx * 4 == prev_image_size)
1563c44768a3SDavid Miller 			break;
1564c44768a3SDavid Miller 		prev_image_size = ctx.idx * 4;
1565c44768a3SDavid Miller 		cond_resched();
1566c44768a3SDavid Miller 	}
1567c44768a3SDavid Miller 
15687a12b503SDavid S. Miller 	/* Now we know the actual image size. */
15697a12b503SDavid S. Miller 	image_size = sizeof(u32) * ctx.idx;
15707a12b503SDavid S. Miller 	header = bpf_jit_binary_alloc(image_size, &image_ptr,
15717a12b503SDavid S. Miller 				      sizeof(u32), jit_fill_hole);
15727a12b503SDavid S. Miller 	if (header == NULL) {
15737a12b503SDavid S. Miller 		prog = orig_prog;
15747a12b503SDavid S. Miller 		goto out_off;
15757a12b503SDavid S. Miller 	}
15767a12b503SDavid S. Miller 
15777a12b503SDavid S. Miller 	ctx.image = (u32 *)image_ptr;
15785f5a6411SDavid Miller skip_init_ctx:
15797a12b503SDavid S. Miller 	ctx.idx = 0;
15807a12b503SDavid S. Miller 
15817a12b503SDavid S. Miller 	build_prologue(&ctx);
15827a12b503SDavid S. Miller 
15837a12b503SDavid S. Miller 	if (build_body(&ctx)) {
15847a12b503SDavid S. Miller 		bpf_jit_binary_free(header);
15857a12b503SDavid S. Miller 		prog = orig_prog;
15867a12b503SDavid S. Miller 		goto out_off;
15877a12b503SDavid S. Miller 	}
15887a12b503SDavid S. Miller 
15897a12b503SDavid S. Miller 	build_epilogue(&ctx);
15907a12b503SDavid S. Miller 
1591c44768a3SDavid Miller 	if (ctx.idx * 4 != prev_image_size) {
1592c44768a3SDavid Miller 		pr_err("bpf_jit: Failed to converge, prev_size=%u size=%d\n",
1593c44768a3SDavid Miller 		       prev_image_size, ctx.idx * 4);
1594c44768a3SDavid Miller 		bpf_jit_binary_free(header);
1595c44768a3SDavid Miller 		prog = orig_prog;
1596c44768a3SDavid Miller 		goto out_off;
15977a12b503SDavid S. Miller 	}
15987a12b503SDavid S. Miller 
15997a12b503SDavid S. Miller 	if (bpf_jit_enable > 1)
16007a12b503SDavid S. Miller 		bpf_jit_dump(prog->len, image_size, pass, ctx.image);
16017a12b503SDavid S. Miller 
16020f350231SSong Liu 	bpf_flush_icache(header, (u8 *)header + header->size);
16037a12b503SDavid S. Miller 
16045f5a6411SDavid Miller 	if (!prog->is_func || extra_pass) {
1605*9fef36caSGreg Kroah-Hartman 		bpf_jit_binary_lock_ro(header);
16065f5a6411SDavid Miller 	} else {
16075f5a6411SDavid Miller 		jit_data->ctx = ctx;
16085f5a6411SDavid Miller 		jit_data->image = image_ptr;
16095f5a6411SDavid Miller 		jit_data->header = header;
16105f5a6411SDavid Miller 	}
16117a12b503SDavid S. Miller 
16127a12b503SDavid S. Miller 	prog->bpf_func = (void *)ctx.image;
16137a12b503SDavid S. Miller 	prog->jited = 1;
1614783d28ddSMartin KaFai Lau 	prog->jited_len = image_size;
16157a12b503SDavid S. Miller 
16165f5a6411SDavid Miller 	if (!prog->is_func || extra_pass) {
16179df95e8eSMartin KaFai Lau 		bpf_prog_fill_jited_linfo(prog, ctx.offset);
16187a12b503SDavid S. Miller out_off:
16197a12b503SDavid S. Miller 		kfree(ctx.offset);
16205f5a6411SDavid Miller 		kfree(jit_data);
16215f5a6411SDavid Miller 		prog->aux->jit_data = NULL;
16225f5a6411SDavid Miller 	}
16237a12b503SDavid S. Miller out:
16247a12b503SDavid S. Miller 	if (tmp_blinded)
16257a12b503SDavid S. Miller 		bpf_jit_prog_release_other(prog, prog == orig_prog ?
16267a12b503SDavid S. Miller 					   tmp : orig_prog);
16277a12b503SDavid S. Miller 	return prog;
16287a12b503SDavid S. Miller }
1629