162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * BPF Jit compiler for s390.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Minimum build requirements:
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  - HAVE_MARCH_Z196_FEATURES: laal, laalg
862306a36Sopenharmony_ci *  - HAVE_MARCH_Z10_FEATURES: msfi, cgrj, clgrj
962306a36Sopenharmony_ci *  - HAVE_MARCH_Z9_109_FEATURES: alfi, llilf, clfi, oilf, nilf
1062306a36Sopenharmony_ci *  - 64BIT
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Copyright IBM Corp. 2012,2015
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
1562306a36Sopenharmony_ci *	      Michael Holzheu <holzheu@linux.vnet.ibm.com>
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define KMSG_COMPONENT "bpf_jit"
1962306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/netdevice.h>
2262306a36Sopenharmony_ci#include <linux/filter.h>
2362306a36Sopenharmony_ci#include <linux/init.h>
2462306a36Sopenharmony_ci#include <linux/bpf.h>
2562306a36Sopenharmony_ci#include <linux/mm.h>
2662306a36Sopenharmony_ci#include <linux/kernel.h>
2762306a36Sopenharmony_ci#include <asm/cacheflush.h>
2862306a36Sopenharmony_ci#include <asm/extable.h>
2962306a36Sopenharmony_ci#include <asm/dis.h>
3062306a36Sopenharmony_ci#include <asm/facility.h>
3162306a36Sopenharmony_ci#include <asm/nospec-branch.h>
3262306a36Sopenharmony_ci#include <asm/set_memory.h>
3362306a36Sopenharmony_ci#include <asm/text-patching.h>
3462306a36Sopenharmony_ci#include "bpf_jit.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct bpf_jit {
3762306a36Sopenharmony_ci	u32 seen;		/* Flags to remember seen eBPF instructions */
3862306a36Sopenharmony_ci	u32 seen_reg[16];	/* Array to remember which registers are used */
3962306a36Sopenharmony_ci	u32 *addrs;		/* Array with relative instruction addresses */
4062306a36Sopenharmony_ci	u8 *prg_buf;		/* Start of program */
4162306a36Sopenharmony_ci	int size;		/* Size of program and literal pool */
4262306a36Sopenharmony_ci	int size_prg;		/* Size of program */
4362306a36Sopenharmony_ci	int prg;		/* Current position in program */
4462306a36Sopenharmony_ci	int lit32_start;	/* Start of 32-bit literal pool */
4562306a36Sopenharmony_ci	int lit32;		/* Current position in 32-bit literal pool */
4662306a36Sopenharmony_ci	int lit64_start;	/* Start of 64-bit literal pool */
4762306a36Sopenharmony_ci	int lit64;		/* Current position in 64-bit literal pool */
4862306a36Sopenharmony_ci	int base_ip;		/* Base address for literal pool */
4962306a36Sopenharmony_ci	int exit_ip;		/* Address of exit */
5062306a36Sopenharmony_ci	int r1_thunk_ip;	/* Address of expoline thunk for 'br %r1' */
5162306a36Sopenharmony_ci	int r14_thunk_ip;	/* Address of expoline thunk for 'br %r14' */
5262306a36Sopenharmony_ci	int tail_call_start;	/* Tail call start offset */
5362306a36Sopenharmony_ci	int excnt;		/* Number of exception table entries */
5462306a36Sopenharmony_ci	int prologue_plt_ret;	/* Return address for prologue hotpatch PLT */
5562306a36Sopenharmony_ci	int prologue_plt;	/* Start of prologue hotpatch PLT */
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define SEEN_MEM	BIT(0)		/* use mem[] for temporary storage */
5962306a36Sopenharmony_ci#define SEEN_LITERAL	BIT(1)		/* code uses literals */
6062306a36Sopenharmony_ci#define SEEN_FUNC	BIT(2)		/* calls C functions */
6162306a36Sopenharmony_ci#define SEEN_STACK	(SEEN_FUNC | SEEN_MEM)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * s390 registers
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci#define REG_W0		(MAX_BPF_JIT_REG + 0)	/* Work register 1 (even) */
6762306a36Sopenharmony_ci#define REG_W1		(MAX_BPF_JIT_REG + 1)	/* Work register 2 (odd) */
6862306a36Sopenharmony_ci#define REG_L		(MAX_BPF_JIT_REG + 2)	/* Literal pool register */
6962306a36Sopenharmony_ci#define REG_15		(MAX_BPF_JIT_REG + 3)	/* Register 15 */
7062306a36Sopenharmony_ci#define REG_0		REG_W0			/* Register 0 */
7162306a36Sopenharmony_ci#define REG_1		REG_W1			/* Register 1 */
7262306a36Sopenharmony_ci#define REG_2		BPF_REG_1		/* Register 2 */
7362306a36Sopenharmony_ci#define REG_3		BPF_REG_2		/* Register 3 */
7462306a36Sopenharmony_ci#define REG_4		BPF_REG_3		/* Register 4 */
7562306a36Sopenharmony_ci#define REG_7		BPF_REG_6		/* Register 7 */
7662306a36Sopenharmony_ci#define REG_8		BPF_REG_7		/* Register 8 */
7762306a36Sopenharmony_ci#define REG_14		BPF_REG_0		/* Register 14 */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * Mapping of BPF registers to s390 registers
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_cistatic const int reg2hex[] = {
8362306a36Sopenharmony_ci	/* Return code */
8462306a36Sopenharmony_ci	[BPF_REG_0]	= 14,
8562306a36Sopenharmony_ci	/* Function parameters */
8662306a36Sopenharmony_ci	[BPF_REG_1]	= 2,
8762306a36Sopenharmony_ci	[BPF_REG_2]	= 3,
8862306a36Sopenharmony_ci	[BPF_REG_3]	= 4,
8962306a36Sopenharmony_ci	[BPF_REG_4]	= 5,
9062306a36Sopenharmony_ci	[BPF_REG_5]	= 6,
9162306a36Sopenharmony_ci	/* Call saved registers */
9262306a36Sopenharmony_ci	[BPF_REG_6]	= 7,
9362306a36Sopenharmony_ci	[BPF_REG_7]	= 8,
9462306a36Sopenharmony_ci	[BPF_REG_8]	= 9,
9562306a36Sopenharmony_ci	[BPF_REG_9]	= 10,
9662306a36Sopenharmony_ci	/* BPF stack pointer */
9762306a36Sopenharmony_ci	[BPF_REG_FP]	= 13,
9862306a36Sopenharmony_ci	/* Register for blinding */
9962306a36Sopenharmony_ci	[BPF_REG_AX]	= 12,
10062306a36Sopenharmony_ci	/* Work registers for s390x backend */
10162306a36Sopenharmony_ci	[REG_W0]	= 0,
10262306a36Sopenharmony_ci	[REG_W1]	= 1,
10362306a36Sopenharmony_ci	[REG_L]		= 11,
10462306a36Sopenharmony_ci	[REG_15]	= 15,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic inline u32 reg(u32 dst_reg, u32 src_reg)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	return reg2hex[dst_reg] << 4 | reg2hex[src_reg];
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic inline u32 reg_high(u32 reg)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	return reg2hex[reg] << 4;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	u32 r1 = reg2hex[b1];
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (r1 >= 6 && r1 <= 15 && !jit->seen_reg[r1])
12262306a36Sopenharmony_ci		jit->seen_reg[r1] = 1;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define REG_SET_SEEN(b1)					\
12662306a36Sopenharmony_ci({								\
12762306a36Sopenharmony_ci	reg_set_seen(jit, b1);					\
12862306a36Sopenharmony_ci})
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define REG_SEEN(b1) jit->seen_reg[reg2hex[(b1)]]
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * EMIT macros for code generation
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define _EMIT2(op)						\
13762306a36Sopenharmony_ci({								\
13862306a36Sopenharmony_ci	if (jit->prg_buf)					\
13962306a36Sopenharmony_ci		*(u16 *) (jit->prg_buf + jit->prg) = (op);	\
14062306a36Sopenharmony_ci	jit->prg += 2;						\
14162306a36Sopenharmony_ci})
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define EMIT2(op, b1, b2)					\
14462306a36Sopenharmony_ci({								\
14562306a36Sopenharmony_ci	_EMIT2((op) | reg(b1, b2));				\
14662306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
14762306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
14862306a36Sopenharmony_ci})
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define _EMIT4(op)						\
15162306a36Sopenharmony_ci({								\
15262306a36Sopenharmony_ci	if (jit->prg_buf)					\
15362306a36Sopenharmony_ci		*(u32 *) (jit->prg_buf + jit->prg) = (op);	\
15462306a36Sopenharmony_ci	jit->prg += 4;						\
15562306a36Sopenharmony_ci})
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define EMIT4(op, b1, b2)					\
15862306a36Sopenharmony_ci({								\
15962306a36Sopenharmony_ci	_EMIT4((op) | reg(b1, b2));				\
16062306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
16162306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
16262306a36Sopenharmony_ci})
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define EMIT4_RRF(op, b1, b2, b3)				\
16562306a36Sopenharmony_ci({								\
16662306a36Sopenharmony_ci	_EMIT4((op) | reg_high(b3) << 8 | reg(b1, b2));		\
16762306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
16862306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
16962306a36Sopenharmony_ci	REG_SET_SEEN(b3);					\
17062306a36Sopenharmony_ci})
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci#define _EMIT4_DISP(op, disp)					\
17362306a36Sopenharmony_ci({								\
17462306a36Sopenharmony_ci	unsigned int __disp = (disp) & 0xfff;			\
17562306a36Sopenharmony_ci	_EMIT4((op) | __disp);					\
17662306a36Sopenharmony_ci})
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define EMIT4_DISP(op, b1, b2, disp)				\
17962306a36Sopenharmony_ci({								\
18062306a36Sopenharmony_ci	_EMIT4_DISP((op) | reg_high(b1) << 16 |			\
18162306a36Sopenharmony_ci		    reg_high(b2) << 8, (disp));			\
18262306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
18362306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
18462306a36Sopenharmony_ci})
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define EMIT4_IMM(op, b1, imm)					\
18762306a36Sopenharmony_ci({								\
18862306a36Sopenharmony_ci	unsigned int __imm = (imm) & 0xffff;			\
18962306a36Sopenharmony_ci	_EMIT4((op) | reg_high(b1) << 16 | __imm);		\
19062306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
19162306a36Sopenharmony_ci})
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#define EMIT4_PCREL(op, pcrel)					\
19462306a36Sopenharmony_ci({								\
19562306a36Sopenharmony_ci	long __pcrel = ((pcrel) >> 1) & 0xffff;			\
19662306a36Sopenharmony_ci	_EMIT4((op) | __pcrel);					\
19762306a36Sopenharmony_ci})
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#define EMIT4_PCREL_RIC(op, mask, target)			\
20062306a36Sopenharmony_ci({								\
20162306a36Sopenharmony_ci	int __rel = ((target) - jit->prg) / 2;			\
20262306a36Sopenharmony_ci	_EMIT4((op) | (mask) << 20 | (__rel & 0xffff));		\
20362306a36Sopenharmony_ci})
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci#define _EMIT6(op1, op2)					\
20662306a36Sopenharmony_ci({								\
20762306a36Sopenharmony_ci	if (jit->prg_buf) {					\
20862306a36Sopenharmony_ci		*(u32 *) (jit->prg_buf + jit->prg) = (op1);	\
20962306a36Sopenharmony_ci		*(u16 *) (jit->prg_buf + jit->prg + 4) = (op2);	\
21062306a36Sopenharmony_ci	}							\
21162306a36Sopenharmony_ci	jit->prg += 6;						\
21262306a36Sopenharmony_ci})
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci#define _EMIT6_DISP(op1, op2, disp)				\
21562306a36Sopenharmony_ci({								\
21662306a36Sopenharmony_ci	unsigned int __disp = (disp) & 0xfff;			\
21762306a36Sopenharmony_ci	_EMIT6((op1) | __disp, op2);				\
21862306a36Sopenharmony_ci})
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define _EMIT6_DISP_LH(op1, op2, disp)				\
22162306a36Sopenharmony_ci({								\
22262306a36Sopenharmony_ci	u32 _disp = (u32) (disp);				\
22362306a36Sopenharmony_ci	unsigned int __disp_h = _disp & 0xff000;		\
22462306a36Sopenharmony_ci	unsigned int __disp_l = _disp & 0x00fff;		\
22562306a36Sopenharmony_ci	_EMIT6((op1) | __disp_l, (op2) | __disp_h >> 4);	\
22662306a36Sopenharmony_ci})
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define EMIT6_DISP_LH(op1, op2, b1, b2, b3, disp)		\
22962306a36Sopenharmony_ci({								\
23062306a36Sopenharmony_ci	_EMIT6_DISP_LH((op1) | reg(b1, b2) << 16 |		\
23162306a36Sopenharmony_ci		       reg_high(b3) << 8, op2, disp);		\
23262306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
23362306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
23462306a36Sopenharmony_ci	REG_SET_SEEN(b3);					\
23562306a36Sopenharmony_ci})
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#define EMIT6_PCREL_RIEB(op1, op2, b1, b2, mask, target)	\
23862306a36Sopenharmony_ci({								\
23962306a36Sopenharmony_ci	unsigned int rel = (int)((target) - jit->prg) / 2;	\
24062306a36Sopenharmony_ci	_EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff),	\
24162306a36Sopenharmony_ci	       (op2) | (mask) << 12);				\
24262306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
24362306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
24462306a36Sopenharmony_ci})
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#define EMIT6_PCREL_RIEC(op1, op2, b1, imm, mask, target)	\
24762306a36Sopenharmony_ci({								\
24862306a36Sopenharmony_ci	unsigned int rel = (int)((target) - jit->prg) / 2;	\
24962306a36Sopenharmony_ci	_EMIT6((op1) | (reg_high(b1) | (mask)) << 16 |		\
25062306a36Sopenharmony_ci		(rel & 0xffff), (op2) | ((imm) & 0xff) << 8);	\
25162306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
25262306a36Sopenharmony_ci	BUILD_BUG_ON(((unsigned long) (imm)) > 0xff);		\
25362306a36Sopenharmony_ci})
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci#define EMIT6_PCREL(op1, op2, b1, b2, i, off, mask)		\
25662306a36Sopenharmony_ci({								\
25762306a36Sopenharmony_ci	int rel = (addrs[(i) + (off) + 1] - jit->prg) / 2;	\
25862306a36Sopenharmony_ci	_EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), (op2) | (mask));\
25962306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
26062306a36Sopenharmony_ci	REG_SET_SEEN(b2);					\
26162306a36Sopenharmony_ci})
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#define EMIT6_PCREL_RILB(op, b, target)				\
26462306a36Sopenharmony_ci({								\
26562306a36Sopenharmony_ci	unsigned int rel = (int)((target) - jit->prg) / 2;	\
26662306a36Sopenharmony_ci	_EMIT6((op) | reg_high(b) << 16 | rel >> 16, rel & 0xffff);\
26762306a36Sopenharmony_ci	REG_SET_SEEN(b);					\
26862306a36Sopenharmony_ci})
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci#define EMIT6_PCREL_RIL(op, target)				\
27162306a36Sopenharmony_ci({								\
27262306a36Sopenharmony_ci	unsigned int rel = (int)((target) - jit->prg) / 2;	\
27362306a36Sopenharmony_ci	_EMIT6((op) | rel >> 16, rel & 0xffff);			\
27462306a36Sopenharmony_ci})
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#define EMIT6_PCREL_RILC(op, mask, target)			\
27762306a36Sopenharmony_ci({								\
27862306a36Sopenharmony_ci	EMIT6_PCREL_RIL((op) | (mask) << 20, (target));		\
27962306a36Sopenharmony_ci})
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci#define _EMIT6_IMM(op, imm)					\
28262306a36Sopenharmony_ci({								\
28362306a36Sopenharmony_ci	unsigned int __imm = (imm);				\
28462306a36Sopenharmony_ci	_EMIT6((op) | (__imm >> 16), __imm & 0xffff);		\
28562306a36Sopenharmony_ci})
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci#define EMIT6_IMM(op, b1, imm)					\
28862306a36Sopenharmony_ci({								\
28962306a36Sopenharmony_ci	_EMIT6_IMM((op) | reg_high(b1) << 16, imm);		\
29062306a36Sopenharmony_ci	REG_SET_SEEN(b1);					\
29162306a36Sopenharmony_ci})
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci#define _EMIT_CONST_U32(val)					\
29462306a36Sopenharmony_ci({								\
29562306a36Sopenharmony_ci	unsigned int ret;					\
29662306a36Sopenharmony_ci	ret = jit->lit32;					\
29762306a36Sopenharmony_ci	if (jit->prg_buf)					\
29862306a36Sopenharmony_ci		*(u32 *)(jit->prg_buf + jit->lit32) = (u32)(val);\
29962306a36Sopenharmony_ci	jit->lit32 += 4;					\
30062306a36Sopenharmony_ci	ret;							\
30162306a36Sopenharmony_ci})
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci#define EMIT_CONST_U32(val)					\
30462306a36Sopenharmony_ci({								\
30562306a36Sopenharmony_ci	jit->seen |= SEEN_LITERAL;				\
30662306a36Sopenharmony_ci	_EMIT_CONST_U32(val) - jit->base_ip;			\
30762306a36Sopenharmony_ci})
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci#define _EMIT_CONST_U64(val)					\
31062306a36Sopenharmony_ci({								\
31162306a36Sopenharmony_ci	unsigned int ret;					\
31262306a36Sopenharmony_ci	ret = jit->lit64;					\
31362306a36Sopenharmony_ci	if (jit->prg_buf)					\
31462306a36Sopenharmony_ci		*(u64 *)(jit->prg_buf + jit->lit64) = (u64)(val);\
31562306a36Sopenharmony_ci	jit->lit64 += 8;					\
31662306a36Sopenharmony_ci	ret;							\
31762306a36Sopenharmony_ci})
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci#define EMIT_CONST_U64(val)					\
32062306a36Sopenharmony_ci({								\
32162306a36Sopenharmony_ci	jit->seen |= SEEN_LITERAL;				\
32262306a36Sopenharmony_ci	_EMIT_CONST_U64(val) - jit->base_ip;			\
32362306a36Sopenharmony_ci})
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci#define EMIT_ZERO(b1)						\
32662306a36Sopenharmony_ci({								\
32762306a36Sopenharmony_ci	if (!fp->aux->verifier_zext) {				\
32862306a36Sopenharmony_ci		/* llgfr %dst,%dst (zero extend to 64 bit) */	\
32962306a36Sopenharmony_ci		EMIT4(0xb9160000, b1, b1);			\
33062306a36Sopenharmony_ci		REG_SET_SEEN(b1);				\
33162306a36Sopenharmony_ci	}							\
33262306a36Sopenharmony_ci})
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/*
33562306a36Sopenharmony_ci * Return whether this is the first pass. The first pass is special, since we
33662306a36Sopenharmony_ci * don't know any sizes yet, and thus must be conservative.
33762306a36Sopenharmony_ci */
33862306a36Sopenharmony_cistatic bool is_first_pass(struct bpf_jit *jit)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	return jit->size == 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci/*
34462306a36Sopenharmony_ci * Return whether this is the code generation pass. The code generation pass is
34562306a36Sopenharmony_ci * special, since we should change as little as possible.
34662306a36Sopenharmony_ci */
34762306a36Sopenharmony_cistatic bool is_codegen_pass(struct bpf_jit *jit)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	return jit->prg_buf;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/*
35362306a36Sopenharmony_ci * Return whether "rel" can be encoded as a short PC-relative offset
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_cistatic bool is_valid_rel(int rel)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	return rel >= -65536 && rel <= 65534;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci/*
36162306a36Sopenharmony_ci * Return whether "off" can be reached using a short PC-relative offset
36262306a36Sopenharmony_ci */
36362306a36Sopenharmony_cistatic bool can_use_rel(struct bpf_jit *jit, int off)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	return is_valid_rel(off - jit->prg);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/*
36962306a36Sopenharmony_ci * Return whether given displacement can be encoded using
37062306a36Sopenharmony_ci * Long-Displacement Facility
37162306a36Sopenharmony_ci */
37262306a36Sopenharmony_cistatic bool is_valid_ldisp(int disp)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	return disp >= -524288 && disp <= 524287;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/*
37862306a36Sopenharmony_ci * Return whether the next 32-bit literal pool entry can be referenced using
37962306a36Sopenharmony_ci * Long-Displacement Facility
38062306a36Sopenharmony_ci */
38162306a36Sopenharmony_cistatic bool can_use_ldisp_for_lit32(struct bpf_jit *jit)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	return is_valid_ldisp(jit->lit32 - jit->base_ip);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/*
38762306a36Sopenharmony_ci * Return whether the next 64-bit literal pool entry can be referenced using
38862306a36Sopenharmony_ci * Long-Displacement Facility
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_cistatic bool can_use_ldisp_for_lit64(struct bpf_jit *jit)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	return is_valid_ldisp(jit->lit64 - jit->base_ip);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/*
39662306a36Sopenharmony_ci * Fill whole space with illegal instructions
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_cistatic void jit_fill_hole(void *area, unsigned int size)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	memset(area, 0, size);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/*
40462306a36Sopenharmony_ci * Save registers from "rs" (register start) to "re" (register end) on stack
40562306a36Sopenharmony_ci */
40662306a36Sopenharmony_cistatic void save_regs(struct bpf_jit *jit, u32 rs, u32 re)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	u32 off = STK_OFF_R6 + (rs - 6) * 8;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (rs == re)
41162306a36Sopenharmony_ci		/* stg %rs,off(%r15) */
41262306a36Sopenharmony_ci		_EMIT6(0xe300f000 | rs << 20 | off, 0x0024);
41362306a36Sopenharmony_ci	else
41462306a36Sopenharmony_ci		/* stmg %rs,%re,off(%r15) */
41562306a36Sopenharmony_ci		_EMIT6_DISP(0xeb00f000 | rs << 20 | re << 16, 0x0024, off);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci/*
41962306a36Sopenharmony_ci * Restore registers from "rs" (register start) to "re" (register end) on stack
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic void restore_regs(struct bpf_jit *jit, u32 rs, u32 re, u32 stack_depth)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	u32 off = STK_OFF_R6 + (rs - 6) * 8;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (jit->seen & SEEN_STACK)
42662306a36Sopenharmony_ci		off += STK_OFF + stack_depth;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (rs == re)
42962306a36Sopenharmony_ci		/* lg %rs,off(%r15) */
43062306a36Sopenharmony_ci		_EMIT6(0xe300f000 | rs << 20 | off, 0x0004);
43162306a36Sopenharmony_ci	else
43262306a36Sopenharmony_ci		/* lmg %rs,%re,off(%r15) */
43362306a36Sopenharmony_ci		_EMIT6_DISP(0xeb00f000 | rs << 20 | re << 16, 0x0004, off);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/*
43762306a36Sopenharmony_ci * Return first seen register (from start)
43862306a36Sopenharmony_ci */
43962306a36Sopenharmony_cistatic int get_start(struct bpf_jit *jit, int start)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	int i;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	for (i = start; i <= 15; i++) {
44462306a36Sopenharmony_ci		if (jit->seen_reg[i])
44562306a36Sopenharmony_ci			return i;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci	return 0;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci/*
45162306a36Sopenharmony_ci * Return last seen register (from start) (gap >= 2)
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_cistatic int get_end(struct bpf_jit *jit, int start)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	int i;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	for (i = start; i < 15; i++) {
45862306a36Sopenharmony_ci		if (!jit->seen_reg[i] && !jit->seen_reg[i + 1])
45962306a36Sopenharmony_ci			return i - 1;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci	return jit->seen_reg[15] ? 15 : 14;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#define REGS_SAVE	1
46562306a36Sopenharmony_ci#define REGS_RESTORE	0
46662306a36Sopenharmony_ci/*
46762306a36Sopenharmony_ci * Save and restore clobbered registers (6-15) on stack.
46862306a36Sopenharmony_ci * We save/restore registers in chunks with gap >= 2 registers.
46962306a36Sopenharmony_ci */
47062306a36Sopenharmony_cistatic void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	const int last = 15, save_restore_size = 6;
47362306a36Sopenharmony_ci	int re = 6, rs;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (is_first_pass(jit)) {
47662306a36Sopenharmony_ci		/*
47762306a36Sopenharmony_ci		 * We don't know yet which registers are used. Reserve space
47862306a36Sopenharmony_ci		 * conservatively.
47962306a36Sopenharmony_ci		 */
48062306a36Sopenharmony_ci		jit->prg += (last - re + 1) * save_restore_size;
48162306a36Sopenharmony_ci		return;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	do {
48562306a36Sopenharmony_ci		rs = get_start(jit, re);
48662306a36Sopenharmony_ci		if (!rs)
48762306a36Sopenharmony_ci			break;
48862306a36Sopenharmony_ci		re = get_end(jit, rs + 1);
48962306a36Sopenharmony_ci		if (op == REGS_SAVE)
49062306a36Sopenharmony_ci			save_regs(jit, rs, re);
49162306a36Sopenharmony_ci		else
49262306a36Sopenharmony_ci			restore_regs(jit, rs, re, stack_depth);
49362306a36Sopenharmony_ci		re++;
49462306a36Sopenharmony_ci	} while (re <= last);
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic void bpf_skip(struct bpf_jit *jit, int size)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	if (size >= 6 && !is_valid_rel(size)) {
50062306a36Sopenharmony_ci		/* brcl 0xf,size */
50162306a36Sopenharmony_ci		EMIT6_PCREL_RIL(0xc0f4000000, size);
50262306a36Sopenharmony_ci		size -= 6;
50362306a36Sopenharmony_ci	} else if (size >= 4 && is_valid_rel(size)) {
50462306a36Sopenharmony_ci		/* brc 0xf,size */
50562306a36Sopenharmony_ci		EMIT4_PCREL(0xa7f40000, size);
50662306a36Sopenharmony_ci		size -= 4;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci	while (size >= 2) {
50962306a36Sopenharmony_ci		/* bcr 0,%0 */
51062306a36Sopenharmony_ci		_EMIT2(0x0700);
51162306a36Sopenharmony_ci		size -= 2;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/*
51662306a36Sopenharmony_ci * PLT for hotpatchable calls. The calling convention is the same as for the
51762306a36Sopenharmony_ci * ftrace hotpatch trampolines: %r0 is return address, %r1 is clobbered.
51862306a36Sopenharmony_ci */
51962306a36Sopenharmony_ciextern const char bpf_plt[];
52062306a36Sopenharmony_ciextern const char bpf_plt_ret[];
52162306a36Sopenharmony_ciextern const char bpf_plt_target[];
52262306a36Sopenharmony_ciextern const char bpf_plt_end[];
52362306a36Sopenharmony_ci#define BPF_PLT_SIZE 32
52462306a36Sopenharmony_ciasm(
52562306a36Sopenharmony_ci	".pushsection .rodata\n"
52662306a36Sopenharmony_ci	"	.balign 8\n"
52762306a36Sopenharmony_ci	"bpf_plt:\n"
52862306a36Sopenharmony_ci	"	lgrl %r0,bpf_plt_ret\n"
52962306a36Sopenharmony_ci	"	lgrl %r1,bpf_plt_target\n"
53062306a36Sopenharmony_ci	"	br %r1\n"
53162306a36Sopenharmony_ci	"	.balign 8\n"
53262306a36Sopenharmony_ci	"bpf_plt_ret: .quad 0\n"
53362306a36Sopenharmony_ci	"bpf_plt_target: .quad 0\n"
53462306a36Sopenharmony_ci	"bpf_plt_end:\n"
53562306a36Sopenharmony_ci	"	.popsection\n"
53662306a36Sopenharmony_ci);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void bpf_jit_plt(void *plt, void *ret, void *target)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	memcpy(plt, bpf_plt, BPF_PLT_SIZE);
54162306a36Sopenharmony_ci	*(void **)((char *)plt + (bpf_plt_ret - bpf_plt)) = ret;
54262306a36Sopenharmony_ci	*(void **)((char *)plt + (bpf_plt_target - bpf_plt)) = target ?: ret;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/*
54662306a36Sopenharmony_ci * Emit function prologue
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * Save registers and create stack frame if necessary.
54962306a36Sopenharmony_ci * See stack frame layout description in "bpf_jit.h"!
55062306a36Sopenharmony_ci */
55162306a36Sopenharmony_cistatic void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp,
55262306a36Sopenharmony_ci			     u32 stack_depth)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	/* No-op for hotpatching */
55562306a36Sopenharmony_ci	/* brcl 0,prologue_plt */
55662306a36Sopenharmony_ci	EMIT6_PCREL_RILC(0xc0040000, 0, jit->prologue_plt);
55762306a36Sopenharmony_ci	jit->prologue_plt_ret = jit->prg;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (fp->aux->func_idx == 0) {
56062306a36Sopenharmony_ci		/* Initialize the tail call counter in the main program. */
56162306a36Sopenharmony_ci		/* xc STK_OFF_TCCNT(4,%r15),STK_OFF_TCCNT(%r15) */
56262306a36Sopenharmony_ci		_EMIT6(0xd703f000 | STK_OFF_TCCNT, 0xf000 | STK_OFF_TCCNT);
56362306a36Sopenharmony_ci	} else {
56462306a36Sopenharmony_ci		/*
56562306a36Sopenharmony_ci		 * Skip the tail call counter initialization in subprograms.
56662306a36Sopenharmony_ci		 * Insert nops in order to have tail_call_start at a
56762306a36Sopenharmony_ci		 * predictable offset.
56862306a36Sopenharmony_ci		 */
56962306a36Sopenharmony_ci		bpf_skip(jit, 6);
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci	/* Tail calls have to skip above initialization */
57262306a36Sopenharmony_ci	jit->tail_call_start = jit->prg;
57362306a36Sopenharmony_ci	/* Save registers */
57462306a36Sopenharmony_ci	save_restore_regs(jit, REGS_SAVE, stack_depth);
57562306a36Sopenharmony_ci	/* Setup literal pool */
57662306a36Sopenharmony_ci	if (is_first_pass(jit) || (jit->seen & SEEN_LITERAL)) {
57762306a36Sopenharmony_ci		if (!is_first_pass(jit) &&
57862306a36Sopenharmony_ci		    is_valid_ldisp(jit->size - (jit->prg + 2))) {
57962306a36Sopenharmony_ci			/* basr %l,0 */
58062306a36Sopenharmony_ci			EMIT2(0x0d00, REG_L, REG_0);
58162306a36Sopenharmony_ci			jit->base_ip = jit->prg;
58262306a36Sopenharmony_ci		} else {
58362306a36Sopenharmony_ci			/* larl %l,lit32_start */
58462306a36Sopenharmony_ci			EMIT6_PCREL_RILB(0xc0000000, REG_L, jit->lit32_start);
58562306a36Sopenharmony_ci			jit->base_ip = jit->lit32_start;
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	/* Setup stack and backchain */
58962306a36Sopenharmony_ci	if (is_first_pass(jit) || (jit->seen & SEEN_STACK)) {
59062306a36Sopenharmony_ci		if (is_first_pass(jit) || (jit->seen & SEEN_FUNC))
59162306a36Sopenharmony_ci			/* lgr %w1,%r15 (backchain) */
59262306a36Sopenharmony_ci			EMIT4(0xb9040000, REG_W1, REG_15);
59362306a36Sopenharmony_ci		/* la %bfp,STK_160_UNUSED(%r15) (BPF frame pointer) */
59462306a36Sopenharmony_ci		EMIT4_DISP(0x41000000, BPF_REG_FP, REG_15, STK_160_UNUSED);
59562306a36Sopenharmony_ci		/* aghi %r15,-STK_OFF */
59662306a36Sopenharmony_ci		EMIT4_IMM(0xa70b0000, REG_15, -(STK_OFF + stack_depth));
59762306a36Sopenharmony_ci		if (is_first_pass(jit) || (jit->seen & SEEN_FUNC))
59862306a36Sopenharmony_ci			/* stg %w1,152(%r15) (backchain) */
59962306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0,
60062306a36Sopenharmony_ci				      REG_15, 152);
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci/*
60562306a36Sopenharmony_ci * Emit an expoline for a jump that follows
60662306a36Sopenharmony_ci */
60762306a36Sopenharmony_cistatic void emit_expoline(struct bpf_jit *jit)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	/* exrl %r0,.+10 */
61062306a36Sopenharmony_ci	EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
61162306a36Sopenharmony_ci	/* j . */
61262306a36Sopenharmony_ci	EMIT4_PCREL(0xa7f40000, 0);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci/*
61662306a36Sopenharmony_ci * Emit __s390_indirect_jump_r1 thunk if necessary
61762306a36Sopenharmony_ci */
61862306a36Sopenharmony_cistatic void emit_r1_thunk(struct bpf_jit *jit)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	if (nospec_uses_trampoline()) {
62162306a36Sopenharmony_ci		jit->r1_thunk_ip = jit->prg;
62262306a36Sopenharmony_ci		emit_expoline(jit);
62362306a36Sopenharmony_ci		/* br %r1 */
62462306a36Sopenharmony_ci		_EMIT2(0x07f1);
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/*
62962306a36Sopenharmony_ci * Call r1 either directly or via __s390_indirect_jump_r1 thunk
63062306a36Sopenharmony_ci */
63162306a36Sopenharmony_cistatic void call_r1(struct bpf_jit *jit)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	if (nospec_uses_trampoline())
63462306a36Sopenharmony_ci		/* brasl %r14,__s390_indirect_jump_r1 */
63562306a36Sopenharmony_ci		EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip);
63662306a36Sopenharmony_ci	else
63762306a36Sopenharmony_ci		/* basr %r14,%r1 */
63862306a36Sopenharmony_ci		EMIT2(0x0d00, REG_14, REG_1);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci/*
64262306a36Sopenharmony_ci * Function epilogue
64362306a36Sopenharmony_ci */
64462306a36Sopenharmony_cistatic void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	jit->exit_ip = jit->prg;
64762306a36Sopenharmony_ci	/* Load exit code: lgr %r2,%b0 */
64862306a36Sopenharmony_ci	EMIT4(0xb9040000, REG_2, BPF_REG_0);
64962306a36Sopenharmony_ci	/* Restore registers */
65062306a36Sopenharmony_ci	save_restore_regs(jit, REGS_RESTORE, stack_depth);
65162306a36Sopenharmony_ci	if (nospec_uses_trampoline()) {
65262306a36Sopenharmony_ci		jit->r14_thunk_ip = jit->prg;
65362306a36Sopenharmony_ci		/* Generate __s390_indirect_jump_r14 thunk */
65462306a36Sopenharmony_ci		emit_expoline(jit);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci	/* br %r14 */
65762306a36Sopenharmony_ci	_EMIT2(0x07fe);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (is_first_pass(jit) || (jit->seen & SEEN_FUNC))
66062306a36Sopenharmony_ci		emit_r1_thunk(jit);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	jit->prg = ALIGN(jit->prg, 8);
66362306a36Sopenharmony_ci	jit->prologue_plt = jit->prg;
66462306a36Sopenharmony_ci	if (jit->prg_buf)
66562306a36Sopenharmony_ci		bpf_jit_plt(jit->prg_buf + jit->prg,
66662306a36Sopenharmony_ci			    jit->prg_buf + jit->prologue_plt_ret, NULL);
66762306a36Sopenharmony_ci	jit->prg += BPF_PLT_SIZE;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int get_probe_mem_regno(const u8 *insn)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	/*
67362306a36Sopenharmony_ci	 * insn must point to llgc, llgh, llgf or lg, which have destination
67462306a36Sopenharmony_ci	 * register at the same position.
67562306a36Sopenharmony_ci	 */
67662306a36Sopenharmony_ci	if (insn[0] != 0xe3) /* common llgc, llgh, llgf and lg prefix */
67762306a36Sopenharmony_ci		return -1;
67862306a36Sopenharmony_ci	if (insn[5] != 0x90 && /* llgc */
67962306a36Sopenharmony_ci	    insn[5] != 0x91 && /* llgh */
68062306a36Sopenharmony_ci	    insn[5] != 0x16 && /* llgf */
68162306a36Sopenharmony_ci	    insn[5] != 0x04) /* lg */
68262306a36Sopenharmony_ci		return -1;
68362306a36Sopenharmony_ci	return insn[1] >> 4;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cibool ex_handler_bpf(const struct exception_table_entry *x, struct pt_regs *regs)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	regs->psw.addr = extable_fixup(x);
68962306a36Sopenharmony_ci	regs->gprs[x->data] = 0;
69062306a36Sopenharmony_ci	return true;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp,
69462306a36Sopenharmony_ci			     int probe_prg, int nop_prg)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct exception_table_entry *ex;
69762306a36Sopenharmony_ci	int reg, prg;
69862306a36Sopenharmony_ci	s64 delta;
69962306a36Sopenharmony_ci	u8 *insn;
70062306a36Sopenharmony_ci	int i;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	if (!fp->aux->extable)
70362306a36Sopenharmony_ci		/* Do nothing during early JIT passes. */
70462306a36Sopenharmony_ci		return 0;
70562306a36Sopenharmony_ci	insn = jit->prg_buf + probe_prg;
70662306a36Sopenharmony_ci	reg = get_probe_mem_regno(insn);
70762306a36Sopenharmony_ci	if (WARN_ON_ONCE(reg < 0))
70862306a36Sopenharmony_ci		/* JIT bug - unexpected probe instruction. */
70962306a36Sopenharmony_ci		return -1;
71062306a36Sopenharmony_ci	if (WARN_ON_ONCE(probe_prg + insn_length(*insn) != nop_prg))
71162306a36Sopenharmony_ci		/* JIT bug - gap between probe and nop instructions. */
71262306a36Sopenharmony_ci		return -1;
71362306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
71462306a36Sopenharmony_ci		if (WARN_ON_ONCE(jit->excnt >= fp->aux->num_exentries))
71562306a36Sopenharmony_ci			/* Verifier bug - not enough entries. */
71662306a36Sopenharmony_ci			return -1;
71762306a36Sopenharmony_ci		ex = &fp->aux->extable[jit->excnt];
71862306a36Sopenharmony_ci		/* Add extable entries for probe and nop instructions. */
71962306a36Sopenharmony_ci		prg = i == 0 ? probe_prg : nop_prg;
72062306a36Sopenharmony_ci		delta = jit->prg_buf + prg - (u8 *)&ex->insn;
72162306a36Sopenharmony_ci		if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX))
72262306a36Sopenharmony_ci			/* JIT bug - code and extable must be close. */
72362306a36Sopenharmony_ci			return -1;
72462306a36Sopenharmony_ci		ex->insn = delta;
72562306a36Sopenharmony_ci		/*
72662306a36Sopenharmony_ci		 * Always land on the nop. Note that extable infrastructure
72762306a36Sopenharmony_ci		 * ignores fixup field, it is handled by ex_handler_bpf().
72862306a36Sopenharmony_ci		 */
72962306a36Sopenharmony_ci		delta = jit->prg_buf + nop_prg - (u8 *)&ex->fixup;
73062306a36Sopenharmony_ci		if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX))
73162306a36Sopenharmony_ci			/* JIT bug - landing pad and extable must be close. */
73262306a36Sopenharmony_ci			return -1;
73362306a36Sopenharmony_ci		ex->fixup = delta;
73462306a36Sopenharmony_ci		ex->type = EX_TYPE_BPF;
73562306a36Sopenharmony_ci		ex->data = reg;
73662306a36Sopenharmony_ci		jit->excnt++;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci	return 0;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci/*
74262306a36Sopenharmony_ci * Sign-extend the register if necessary
74362306a36Sopenharmony_ci */
74462306a36Sopenharmony_cistatic int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	if (!(flags & BTF_FMODEL_SIGNED_ARG))
74762306a36Sopenharmony_ci		return 0;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	switch (size) {
75062306a36Sopenharmony_ci	case 1:
75162306a36Sopenharmony_ci		/* lgbr %r,%r */
75262306a36Sopenharmony_ci		EMIT4(0xb9060000, r, r);
75362306a36Sopenharmony_ci		return 0;
75462306a36Sopenharmony_ci	case 2:
75562306a36Sopenharmony_ci		/* lghr %r,%r */
75662306a36Sopenharmony_ci		EMIT4(0xb9070000, r, r);
75762306a36Sopenharmony_ci		return 0;
75862306a36Sopenharmony_ci	case 4:
75962306a36Sopenharmony_ci		/* lgfr %r,%r */
76062306a36Sopenharmony_ci		EMIT4(0xb9140000, r, r);
76162306a36Sopenharmony_ci		return 0;
76262306a36Sopenharmony_ci	case 8:
76362306a36Sopenharmony_ci		return 0;
76462306a36Sopenharmony_ci	default:
76562306a36Sopenharmony_ci		return -1;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci/*
77062306a36Sopenharmony_ci * Compile one eBPF instruction into s390x code
77162306a36Sopenharmony_ci *
77262306a36Sopenharmony_ci * NOTE: Use noinline because for gcov (-fprofile-arcs) gcc allocates a lot of
77362306a36Sopenharmony_ci * stack space for the large switch statement.
77462306a36Sopenharmony_ci */
77562306a36Sopenharmony_cistatic noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
77662306a36Sopenharmony_ci				 int i, bool extra_pass, u32 stack_depth)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct bpf_insn *insn = &fp->insnsi[i];
77962306a36Sopenharmony_ci	u32 dst_reg = insn->dst_reg;
78062306a36Sopenharmony_ci	u32 src_reg = insn->src_reg;
78162306a36Sopenharmony_ci	int last, insn_count = 1;
78262306a36Sopenharmony_ci	u32 *addrs = jit->addrs;
78362306a36Sopenharmony_ci	s32 imm = insn->imm;
78462306a36Sopenharmony_ci	s16 off = insn->off;
78562306a36Sopenharmony_ci	int probe_prg = -1;
78662306a36Sopenharmony_ci	unsigned int mask;
78762306a36Sopenharmony_ci	int nop_prg;
78862306a36Sopenharmony_ci	int err;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (BPF_CLASS(insn->code) == BPF_LDX &&
79162306a36Sopenharmony_ci	    BPF_MODE(insn->code) == BPF_PROBE_MEM)
79262306a36Sopenharmony_ci		probe_prg = jit->prg;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	switch (insn->code) {
79562306a36Sopenharmony_ci	/*
79662306a36Sopenharmony_ci	 * BPF_MOV
79762306a36Sopenharmony_ci	 */
79862306a36Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_X: /* dst = (u32) src */
79962306a36Sopenharmony_ci		/* llgfr %dst,%src */
80062306a36Sopenharmony_ci		EMIT4(0xb9160000, dst_reg, src_reg);
80162306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
80262306a36Sopenharmony_ci			insn_count = 2;
80362306a36Sopenharmony_ci		break;
80462306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */
80562306a36Sopenharmony_ci		/* lgr %dst,%src */
80662306a36Sopenharmony_ci		EMIT4(0xb9040000, dst_reg, src_reg);
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_K: /* dst = (u32) imm */
80962306a36Sopenharmony_ci		/* llilf %dst,imm */
81062306a36Sopenharmony_ci		EMIT6_IMM(0xc00f0000, dst_reg, imm);
81162306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
81262306a36Sopenharmony_ci			insn_count = 2;
81362306a36Sopenharmony_ci		break;
81462306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = imm */
81562306a36Sopenharmony_ci		/* lgfi %dst,imm */
81662306a36Sopenharmony_ci		EMIT6_IMM(0xc0010000, dst_reg, imm);
81762306a36Sopenharmony_ci		break;
81862306a36Sopenharmony_ci	/*
81962306a36Sopenharmony_ci	 * BPF_LD 64
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */
82262306a36Sopenharmony_ci	{
82362306a36Sopenharmony_ci		/* 16 byte instruction that uses two 'struct bpf_insn' */
82462306a36Sopenharmony_ci		u64 imm64;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		imm64 = (u64)(u32) insn[0].imm | ((u64)(u32) insn[1].imm) << 32;
82762306a36Sopenharmony_ci		/* lgrl %dst,imm */
82862306a36Sopenharmony_ci		EMIT6_PCREL_RILB(0xc4080000, dst_reg, _EMIT_CONST_U64(imm64));
82962306a36Sopenharmony_ci		insn_count = 2;
83062306a36Sopenharmony_ci		break;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci	/*
83362306a36Sopenharmony_ci	 * BPF_ADD
83462306a36Sopenharmony_ci	 */
83562306a36Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_X: /* dst = (u32) dst + (u32) src */
83662306a36Sopenharmony_ci		/* ar %dst,%src */
83762306a36Sopenharmony_ci		EMIT2(0x1a00, dst_reg, src_reg);
83862306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
83962306a36Sopenharmony_ci		break;
84062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_X: /* dst = dst + src */
84162306a36Sopenharmony_ci		/* agr %dst,%src */
84262306a36Sopenharmony_ci		EMIT4(0xb9080000, dst_reg, src_reg);
84362306a36Sopenharmony_ci		break;
84462306a36Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_K: /* dst = (u32) dst + (u32) imm */
84562306a36Sopenharmony_ci		if (imm != 0) {
84662306a36Sopenharmony_ci			/* alfi %dst,imm */
84762306a36Sopenharmony_ci			EMIT6_IMM(0xc20b0000, dst_reg, imm);
84862306a36Sopenharmony_ci		}
84962306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
85062306a36Sopenharmony_ci		break;
85162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_K: /* dst = dst + imm */
85262306a36Sopenharmony_ci		if (!imm)
85362306a36Sopenharmony_ci			break;
85462306a36Sopenharmony_ci		/* agfi %dst,imm */
85562306a36Sopenharmony_ci		EMIT6_IMM(0xc2080000, dst_reg, imm);
85662306a36Sopenharmony_ci		break;
85762306a36Sopenharmony_ci	/*
85862306a36Sopenharmony_ci	 * BPF_SUB
85962306a36Sopenharmony_ci	 */
86062306a36Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_X: /* dst = (u32) dst - (u32) src */
86162306a36Sopenharmony_ci		/* sr %dst,%src */
86262306a36Sopenharmony_ci		EMIT2(0x1b00, dst_reg, src_reg);
86362306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
86462306a36Sopenharmony_ci		break;
86562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_X: /* dst = dst - src */
86662306a36Sopenharmony_ci		/* sgr %dst,%src */
86762306a36Sopenharmony_ci		EMIT4(0xb9090000, dst_reg, src_reg);
86862306a36Sopenharmony_ci		break;
86962306a36Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_K: /* dst = (u32) dst - (u32) imm */
87062306a36Sopenharmony_ci		if (imm != 0) {
87162306a36Sopenharmony_ci			/* alfi %dst,-imm */
87262306a36Sopenharmony_ci			EMIT6_IMM(0xc20b0000, dst_reg, -imm);
87362306a36Sopenharmony_ci		}
87462306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
87562306a36Sopenharmony_ci		break;
87662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_K: /* dst = dst - imm */
87762306a36Sopenharmony_ci		if (!imm)
87862306a36Sopenharmony_ci			break;
87962306a36Sopenharmony_ci		if (imm == -0x80000000) {
88062306a36Sopenharmony_ci			/* algfi %dst,0x80000000 */
88162306a36Sopenharmony_ci			EMIT6_IMM(0xc20a0000, dst_reg, 0x80000000);
88262306a36Sopenharmony_ci		} else {
88362306a36Sopenharmony_ci			/* agfi %dst,-imm */
88462306a36Sopenharmony_ci			EMIT6_IMM(0xc2080000, dst_reg, -imm);
88562306a36Sopenharmony_ci		}
88662306a36Sopenharmony_ci		break;
88762306a36Sopenharmony_ci	/*
88862306a36Sopenharmony_ci	 * BPF_MUL
88962306a36Sopenharmony_ci	 */
89062306a36Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_X: /* dst = (u32) dst * (u32) src */
89162306a36Sopenharmony_ci		/* msr %dst,%src */
89262306a36Sopenharmony_ci		EMIT4(0xb2520000, dst_reg, src_reg);
89362306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
89462306a36Sopenharmony_ci		break;
89562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_X: /* dst = dst * src */
89662306a36Sopenharmony_ci		/* msgr %dst,%src */
89762306a36Sopenharmony_ci		EMIT4(0xb90c0000, dst_reg, src_reg);
89862306a36Sopenharmony_ci		break;
89962306a36Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_K: /* dst = (u32) dst * (u32) imm */
90062306a36Sopenharmony_ci		if (imm != 1) {
90162306a36Sopenharmony_ci			/* msfi %r5,imm */
90262306a36Sopenharmony_ci			EMIT6_IMM(0xc2010000, dst_reg, imm);
90362306a36Sopenharmony_ci		}
90462306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
90562306a36Sopenharmony_ci		break;
90662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_K: /* dst = dst * imm */
90762306a36Sopenharmony_ci		if (imm == 1)
90862306a36Sopenharmony_ci			break;
90962306a36Sopenharmony_ci		/* msgfi %dst,imm */
91062306a36Sopenharmony_ci		EMIT6_IMM(0xc2000000, dst_reg, imm);
91162306a36Sopenharmony_ci		break;
91262306a36Sopenharmony_ci	/*
91362306a36Sopenharmony_ci	 * BPF_DIV / BPF_MOD
91462306a36Sopenharmony_ci	 */
91562306a36Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_X: /* dst = (u32) dst / (u32) src */
91662306a36Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_X: /* dst = (u32) dst % (u32) src */
91762306a36Sopenharmony_ci	{
91862306a36Sopenharmony_ci		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci		/* lhi %w0,0 */
92162306a36Sopenharmony_ci		EMIT4_IMM(0xa7080000, REG_W0, 0);
92262306a36Sopenharmony_ci		/* lr %w1,%dst */
92362306a36Sopenharmony_ci		EMIT2(0x1800, REG_W1, dst_reg);
92462306a36Sopenharmony_ci		/* dlr %w0,%src */
92562306a36Sopenharmony_ci		EMIT4(0xb9970000, REG_W0, src_reg);
92662306a36Sopenharmony_ci		/* llgfr %dst,%rc */
92762306a36Sopenharmony_ci		EMIT4(0xb9160000, dst_reg, rc_reg);
92862306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
92962306a36Sopenharmony_ci			insn_count = 2;
93062306a36Sopenharmony_ci		break;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_X: /* dst = dst / src */
93362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_X: /* dst = dst % src */
93462306a36Sopenharmony_ci	{
93562306a36Sopenharmony_ci		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		/* lghi %w0,0 */
93862306a36Sopenharmony_ci		EMIT4_IMM(0xa7090000, REG_W0, 0);
93962306a36Sopenharmony_ci		/* lgr %w1,%dst */
94062306a36Sopenharmony_ci		EMIT4(0xb9040000, REG_W1, dst_reg);
94162306a36Sopenharmony_ci		/* dlgr %w0,%dst */
94262306a36Sopenharmony_ci		EMIT4(0xb9870000, REG_W0, src_reg);
94362306a36Sopenharmony_ci		/* lgr %dst,%rc */
94462306a36Sopenharmony_ci		EMIT4(0xb9040000, dst_reg, rc_reg);
94562306a36Sopenharmony_ci		break;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_K: /* dst = (u32) dst / (u32) imm */
94862306a36Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_K: /* dst = (u32) dst % (u32) imm */
94962306a36Sopenharmony_ci	{
95062306a36Sopenharmony_ci		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		if (imm == 1) {
95362306a36Sopenharmony_ci			if (BPF_OP(insn->code) == BPF_MOD)
95462306a36Sopenharmony_ci				/* lhgi %dst,0 */
95562306a36Sopenharmony_ci				EMIT4_IMM(0xa7090000, dst_reg, 0);
95662306a36Sopenharmony_ci			else
95762306a36Sopenharmony_ci				EMIT_ZERO(dst_reg);
95862306a36Sopenharmony_ci			break;
95962306a36Sopenharmony_ci		}
96062306a36Sopenharmony_ci		/* lhi %w0,0 */
96162306a36Sopenharmony_ci		EMIT4_IMM(0xa7080000, REG_W0, 0);
96262306a36Sopenharmony_ci		/* lr %w1,%dst */
96362306a36Sopenharmony_ci		EMIT2(0x1800, REG_W1, dst_reg);
96462306a36Sopenharmony_ci		if (!is_first_pass(jit) && can_use_ldisp_for_lit32(jit)) {
96562306a36Sopenharmony_ci			/* dl %w0,<d(imm)>(%l) */
96662306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0097, REG_W0, REG_0, REG_L,
96762306a36Sopenharmony_ci				      EMIT_CONST_U32(imm));
96862306a36Sopenharmony_ci		} else {
96962306a36Sopenharmony_ci			/* lgfrl %dst,imm */
97062306a36Sopenharmony_ci			EMIT6_PCREL_RILB(0xc40c0000, dst_reg,
97162306a36Sopenharmony_ci					 _EMIT_CONST_U32(imm));
97262306a36Sopenharmony_ci			jit->seen |= SEEN_LITERAL;
97362306a36Sopenharmony_ci			/* dlr %w0,%dst */
97462306a36Sopenharmony_ci			EMIT4(0xb9970000, REG_W0, dst_reg);
97562306a36Sopenharmony_ci		}
97662306a36Sopenharmony_ci		/* llgfr %dst,%rc */
97762306a36Sopenharmony_ci		EMIT4(0xb9160000, dst_reg, rc_reg);
97862306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
97962306a36Sopenharmony_ci			insn_count = 2;
98062306a36Sopenharmony_ci		break;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_K: /* dst = dst / imm */
98362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_K: /* dst = dst % imm */
98462306a36Sopenharmony_ci	{
98562306a36Sopenharmony_ci		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		if (imm == 1) {
98862306a36Sopenharmony_ci			if (BPF_OP(insn->code) == BPF_MOD)
98962306a36Sopenharmony_ci				/* lhgi %dst,0 */
99062306a36Sopenharmony_ci				EMIT4_IMM(0xa7090000, dst_reg, 0);
99162306a36Sopenharmony_ci			break;
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci		/* lghi %w0,0 */
99462306a36Sopenharmony_ci		EMIT4_IMM(0xa7090000, REG_W0, 0);
99562306a36Sopenharmony_ci		/* lgr %w1,%dst */
99662306a36Sopenharmony_ci		EMIT4(0xb9040000, REG_W1, dst_reg);
99762306a36Sopenharmony_ci		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
99862306a36Sopenharmony_ci			/* dlg %w0,<d(imm)>(%l) */
99962306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0087, REG_W0, REG_0, REG_L,
100062306a36Sopenharmony_ci				      EMIT_CONST_U64(imm));
100162306a36Sopenharmony_ci		} else {
100262306a36Sopenharmony_ci			/* lgrl %dst,imm */
100362306a36Sopenharmony_ci			EMIT6_PCREL_RILB(0xc4080000, dst_reg,
100462306a36Sopenharmony_ci					 _EMIT_CONST_U64(imm));
100562306a36Sopenharmony_ci			jit->seen |= SEEN_LITERAL;
100662306a36Sopenharmony_ci			/* dlgr %w0,%dst */
100762306a36Sopenharmony_ci			EMIT4(0xb9870000, REG_W0, dst_reg);
100862306a36Sopenharmony_ci		}
100962306a36Sopenharmony_ci		/* lgr %dst,%rc */
101062306a36Sopenharmony_ci		EMIT4(0xb9040000, dst_reg, rc_reg);
101162306a36Sopenharmony_ci		break;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci	/*
101462306a36Sopenharmony_ci	 * BPF_AND
101562306a36Sopenharmony_ci	 */
101662306a36Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_X: /* dst = (u32) dst & (u32) src */
101762306a36Sopenharmony_ci		/* nr %dst,%src */
101862306a36Sopenharmony_ci		EMIT2(0x1400, dst_reg, src_reg);
101962306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
102062306a36Sopenharmony_ci		break;
102162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */
102262306a36Sopenharmony_ci		/* ngr %dst,%src */
102362306a36Sopenharmony_ci		EMIT4(0xb9800000, dst_reg, src_reg);
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_K: /* dst = (u32) dst & (u32) imm */
102662306a36Sopenharmony_ci		/* nilf %dst,imm */
102762306a36Sopenharmony_ci		EMIT6_IMM(0xc00b0000, dst_reg, imm);
102862306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
102962306a36Sopenharmony_ci		break;
103062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */
103162306a36Sopenharmony_ci		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
103262306a36Sopenharmony_ci			/* ng %dst,<d(imm)>(%l) */
103362306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0080,
103462306a36Sopenharmony_ci				      dst_reg, REG_0, REG_L,
103562306a36Sopenharmony_ci				      EMIT_CONST_U64(imm));
103662306a36Sopenharmony_ci		} else {
103762306a36Sopenharmony_ci			/* lgrl %w0,imm */
103862306a36Sopenharmony_ci			EMIT6_PCREL_RILB(0xc4080000, REG_W0,
103962306a36Sopenharmony_ci					 _EMIT_CONST_U64(imm));
104062306a36Sopenharmony_ci			jit->seen |= SEEN_LITERAL;
104162306a36Sopenharmony_ci			/* ngr %dst,%w0 */
104262306a36Sopenharmony_ci			EMIT4(0xb9800000, dst_reg, REG_W0);
104362306a36Sopenharmony_ci		}
104462306a36Sopenharmony_ci		break;
104562306a36Sopenharmony_ci	/*
104662306a36Sopenharmony_ci	 * BPF_OR
104762306a36Sopenharmony_ci	 */
104862306a36Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */
104962306a36Sopenharmony_ci		/* or %dst,%src */
105062306a36Sopenharmony_ci		EMIT2(0x1600, dst_reg, src_reg);
105162306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
105262306a36Sopenharmony_ci		break;
105362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */
105462306a36Sopenharmony_ci		/* ogr %dst,%src */
105562306a36Sopenharmony_ci		EMIT4(0xb9810000, dst_reg, src_reg);
105662306a36Sopenharmony_ci		break;
105762306a36Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_K: /* dst = (u32) dst | (u32) imm */
105862306a36Sopenharmony_ci		/* oilf %dst,imm */
105962306a36Sopenharmony_ci		EMIT6_IMM(0xc00d0000, dst_reg, imm);
106062306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
106162306a36Sopenharmony_ci		break;
106262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_K: /* dst = dst | imm */
106362306a36Sopenharmony_ci		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
106462306a36Sopenharmony_ci			/* og %dst,<d(imm)>(%l) */
106562306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0081,
106662306a36Sopenharmony_ci				      dst_reg, REG_0, REG_L,
106762306a36Sopenharmony_ci				      EMIT_CONST_U64(imm));
106862306a36Sopenharmony_ci		} else {
106962306a36Sopenharmony_ci			/* lgrl %w0,imm */
107062306a36Sopenharmony_ci			EMIT6_PCREL_RILB(0xc4080000, REG_W0,
107162306a36Sopenharmony_ci					 _EMIT_CONST_U64(imm));
107262306a36Sopenharmony_ci			jit->seen |= SEEN_LITERAL;
107362306a36Sopenharmony_ci			/* ogr %dst,%w0 */
107462306a36Sopenharmony_ci			EMIT4(0xb9810000, dst_reg, REG_W0);
107562306a36Sopenharmony_ci		}
107662306a36Sopenharmony_ci		break;
107762306a36Sopenharmony_ci	/*
107862306a36Sopenharmony_ci	 * BPF_XOR
107962306a36Sopenharmony_ci	 */
108062306a36Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_X: /* dst = (u32) dst ^ (u32) src */
108162306a36Sopenharmony_ci		/* xr %dst,%src */
108262306a36Sopenharmony_ci		EMIT2(0x1700, dst_reg, src_reg);
108362306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
108462306a36Sopenharmony_ci		break;
108562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_X: /* dst = dst ^ src */
108662306a36Sopenharmony_ci		/* xgr %dst,%src */
108762306a36Sopenharmony_ci		EMIT4(0xb9820000, dst_reg, src_reg);
108862306a36Sopenharmony_ci		break;
108962306a36Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_K: /* dst = (u32) dst ^ (u32) imm */
109062306a36Sopenharmony_ci		if (imm != 0) {
109162306a36Sopenharmony_ci			/* xilf %dst,imm */
109262306a36Sopenharmony_ci			EMIT6_IMM(0xc0070000, dst_reg, imm);
109362306a36Sopenharmony_ci		}
109462306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
109562306a36Sopenharmony_ci		break;
109662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_K: /* dst = dst ^ imm */
109762306a36Sopenharmony_ci		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
109862306a36Sopenharmony_ci			/* xg %dst,<d(imm)>(%l) */
109962306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0082,
110062306a36Sopenharmony_ci				      dst_reg, REG_0, REG_L,
110162306a36Sopenharmony_ci				      EMIT_CONST_U64(imm));
110262306a36Sopenharmony_ci		} else {
110362306a36Sopenharmony_ci			/* lgrl %w0,imm */
110462306a36Sopenharmony_ci			EMIT6_PCREL_RILB(0xc4080000, REG_W0,
110562306a36Sopenharmony_ci					 _EMIT_CONST_U64(imm));
110662306a36Sopenharmony_ci			jit->seen |= SEEN_LITERAL;
110762306a36Sopenharmony_ci			/* xgr %dst,%w0 */
110862306a36Sopenharmony_ci			EMIT4(0xb9820000, dst_reg, REG_W0);
110962306a36Sopenharmony_ci		}
111062306a36Sopenharmony_ci		break;
111162306a36Sopenharmony_ci	/*
111262306a36Sopenharmony_ci	 * BPF_LSH
111362306a36Sopenharmony_ci	 */
111462306a36Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_X: /* dst = (u32) dst << (u32) src */
111562306a36Sopenharmony_ci		/* sll %dst,0(%src) */
111662306a36Sopenharmony_ci		EMIT4_DISP(0x89000000, dst_reg, src_reg, 0);
111762306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
111862306a36Sopenharmony_ci		break;
111962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_X: /* dst = dst << src */
112062306a36Sopenharmony_ci		/* sllg %dst,%dst,0(%src) */
112162306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, src_reg, 0);
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_K: /* dst = (u32) dst << (u32) imm */
112462306a36Sopenharmony_ci		if (imm != 0) {
112562306a36Sopenharmony_ci			/* sll %dst,imm(%r0) */
112662306a36Sopenharmony_ci			EMIT4_DISP(0x89000000, dst_reg, REG_0, imm);
112762306a36Sopenharmony_ci		}
112862306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
112962306a36Sopenharmony_ci		break;
113062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_K: /* dst = dst << imm */
113162306a36Sopenharmony_ci		if (imm == 0)
113262306a36Sopenharmony_ci			break;
113362306a36Sopenharmony_ci		/* sllg %dst,%dst,imm(%r0) */
113462306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, REG_0, imm);
113562306a36Sopenharmony_ci		break;
113662306a36Sopenharmony_ci	/*
113762306a36Sopenharmony_ci	 * BPF_RSH
113862306a36Sopenharmony_ci	 */
113962306a36Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_X: /* dst = (u32) dst >> (u32) src */
114062306a36Sopenharmony_ci		/* srl %dst,0(%src) */
114162306a36Sopenharmony_ci		EMIT4_DISP(0x88000000, dst_reg, src_reg, 0);
114262306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
114362306a36Sopenharmony_ci		break;
114462306a36Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_X: /* dst = dst >> src */
114562306a36Sopenharmony_ci		/* srlg %dst,%dst,0(%src) */
114662306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, src_reg, 0);
114762306a36Sopenharmony_ci		break;
114862306a36Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_K: /* dst = (u32) dst >> (u32) imm */
114962306a36Sopenharmony_ci		if (imm != 0) {
115062306a36Sopenharmony_ci			/* srl %dst,imm(%r0) */
115162306a36Sopenharmony_ci			EMIT4_DISP(0x88000000, dst_reg, REG_0, imm);
115262306a36Sopenharmony_ci		}
115362306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
115462306a36Sopenharmony_ci		break;
115562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_K: /* dst = dst >> imm */
115662306a36Sopenharmony_ci		if (imm == 0)
115762306a36Sopenharmony_ci			break;
115862306a36Sopenharmony_ci		/* srlg %dst,%dst,imm(%r0) */
115962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, REG_0, imm);
116062306a36Sopenharmony_ci		break;
116162306a36Sopenharmony_ci	/*
116262306a36Sopenharmony_ci	 * BPF_ARSH
116362306a36Sopenharmony_ci	 */
116462306a36Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_X: /* ((s32) dst) >>= src */
116562306a36Sopenharmony_ci		/* sra %dst,%dst,0(%src) */
116662306a36Sopenharmony_ci		EMIT4_DISP(0x8a000000, dst_reg, src_reg, 0);
116762306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
116862306a36Sopenharmony_ci		break;
116962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_X: /* ((s64) dst) >>= src */
117062306a36Sopenharmony_ci		/* srag %dst,%dst,0(%src) */
117162306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0);
117262306a36Sopenharmony_ci		break;
117362306a36Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_K: /* ((s32) dst >> imm */
117462306a36Sopenharmony_ci		if (imm != 0) {
117562306a36Sopenharmony_ci			/* sra %dst,imm(%r0) */
117662306a36Sopenharmony_ci			EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
117762306a36Sopenharmony_ci		}
117862306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
117962306a36Sopenharmony_ci		break;
118062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */
118162306a36Sopenharmony_ci		if (imm == 0)
118262306a36Sopenharmony_ci			break;
118362306a36Sopenharmony_ci		/* srag %dst,%dst,imm(%r0) */
118462306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, REG_0, imm);
118562306a36Sopenharmony_ci		break;
118662306a36Sopenharmony_ci	/*
118762306a36Sopenharmony_ci	 * BPF_NEG
118862306a36Sopenharmony_ci	 */
118962306a36Sopenharmony_ci	case BPF_ALU | BPF_NEG: /* dst = (u32) -dst */
119062306a36Sopenharmony_ci		/* lcr %dst,%dst */
119162306a36Sopenharmony_ci		EMIT2(0x1300, dst_reg, dst_reg);
119262306a36Sopenharmony_ci		EMIT_ZERO(dst_reg);
119362306a36Sopenharmony_ci		break;
119462306a36Sopenharmony_ci	case BPF_ALU64 | BPF_NEG: /* dst = -dst */
119562306a36Sopenharmony_ci		/* lcgr %dst,%dst */
119662306a36Sopenharmony_ci		EMIT4(0xb9030000, dst_reg, dst_reg);
119762306a36Sopenharmony_ci		break;
119862306a36Sopenharmony_ci	/*
119962306a36Sopenharmony_ci	 * BPF_FROM_BE/LE
120062306a36Sopenharmony_ci	 */
120162306a36Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_BE:
120262306a36Sopenharmony_ci		/* s390 is big endian, therefore only clear high order bytes */
120362306a36Sopenharmony_ci		switch (imm) {
120462306a36Sopenharmony_ci		case 16: /* dst = (u16) cpu_to_be16(dst) */
120562306a36Sopenharmony_ci			/* llghr %dst,%dst */
120662306a36Sopenharmony_ci			EMIT4(0xb9850000, dst_reg, dst_reg);
120762306a36Sopenharmony_ci			if (insn_is_zext(&insn[1]))
120862306a36Sopenharmony_ci				insn_count = 2;
120962306a36Sopenharmony_ci			break;
121062306a36Sopenharmony_ci		case 32: /* dst = (u32) cpu_to_be32(dst) */
121162306a36Sopenharmony_ci			if (!fp->aux->verifier_zext)
121262306a36Sopenharmony_ci				/* llgfr %dst,%dst */
121362306a36Sopenharmony_ci				EMIT4(0xb9160000, dst_reg, dst_reg);
121462306a36Sopenharmony_ci			break;
121562306a36Sopenharmony_ci		case 64: /* dst = (u64) cpu_to_be64(dst) */
121662306a36Sopenharmony_ci			break;
121762306a36Sopenharmony_ci		}
121862306a36Sopenharmony_ci		break;
121962306a36Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_LE:
122062306a36Sopenharmony_ci		switch (imm) {
122162306a36Sopenharmony_ci		case 16: /* dst = (u16) cpu_to_le16(dst) */
122262306a36Sopenharmony_ci			/* lrvr %dst,%dst */
122362306a36Sopenharmony_ci			EMIT4(0xb91f0000, dst_reg, dst_reg);
122462306a36Sopenharmony_ci			/* srl %dst,16(%r0) */
122562306a36Sopenharmony_ci			EMIT4_DISP(0x88000000, dst_reg, REG_0, 16);
122662306a36Sopenharmony_ci			/* llghr %dst,%dst */
122762306a36Sopenharmony_ci			EMIT4(0xb9850000, dst_reg, dst_reg);
122862306a36Sopenharmony_ci			if (insn_is_zext(&insn[1]))
122962306a36Sopenharmony_ci				insn_count = 2;
123062306a36Sopenharmony_ci			break;
123162306a36Sopenharmony_ci		case 32: /* dst = (u32) cpu_to_le32(dst) */
123262306a36Sopenharmony_ci			/* lrvr %dst,%dst */
123362306a36Sopenharmony_ci			EMIT4(0xb91f0000, dst_reg, dst_reg);
123462306a36Sopenharmony_ci			if (!fp->aux->verifier_zext)
123562306a36Sopenharmony_ci				/* llgfr %dst,%dst */
123662306a36Sopenharmony_ci				EMIT4(0xb9160000, dst_reg, dst_reg);
123762306a36Sopenharmony_ci			break;
123862306a36Sopenharmony_ci		case 64: /* dst = (u64) cpu_to_le64(dst) */
123962306a36Sopenharmony_ci			/* lrvgr %dst,%dst */
124062306a36Sopenharmony_ci			EMIT4(0xb90f0000, dst_reg, dst_reg);
124162306a36Sopenharmony_ci			break;
124262306a36Sopenharmony_ci		}
124362306a36Sopenharmony_ci		break;
124462306a36Sopenharmony_ci	/*
124562306a36Sopenharmony_ci	 * BPF_NOSPEC (speculation barrier)
124662306a36Sopenharmony_ci	 */
124762306a36Sopenharmony_ci	case BPF_ST | BPF_NOSPEC:
124862306a36Sopenharmony_ci		break;
124962306a36Sopenharmony_ci	/*
125062306a36Sopenharmony_ci	 * BPF_ST(X)
125162306a36Sopenharmony_ci	 */
125262306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */
125362306a36Sopenharmony_ci		/* stcy %src,off(%dst) */
125462306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0072, src_reg, dst_reg, REG_0, off);
125562306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
125662306a36Sopenharmony_ci		break;
125762306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */
125862306a36Sopenharmony_ci		/* sthy %src,off(%dst) */
125962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0070, src_reg, dst_reg, REG_0, off);
126062306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
126162306a36Sopenharmony_ci		break;
126262306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */
126362306a36Sopenharmony_ci		/* sty %src,off(%dst) */
126462306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0050, src_reg, dst_reg, REG_0, off);
126562306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
126662306a36Sopenharmony_ci		break;
126762306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */
126862306a36Sopenharmony_ci		/* stg %src,off(%dst) */
126962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0024, src_reg, dst_reg, REG_0, off);
127062306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
127162306a36Sopenharmony_ci		break;
127262306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */
127362306a36Sopenharmony_ci		/* lhi %w0,imm */
127462306a36Sopenharmony_ci		EMIT4_IMM(0xa7080000, REG_W0, (u8) imm);
127562306a36Sopenharmony_ci		/* stcy %w0,off(dst) */
127662306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0072, REG_W0, dst_reg, REG_0, off);
127762306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
127862306a36Sopenharmony_ci		break;
127962306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */
128062306a36Sopenharmony_ci		/* lhi %w0,imm */
128162306a36Sopenharmony_ci		EMIT4_IMM(0xa7080000, REG_W0, (u16) imm);
128262306a36Sopenharmony_ci		/* sthy %w0,off(dst) */
128362306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0070, REG_W0, dst_reg, REG_0, off);
128462306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
128562306a36Sopenharmony_ci		break;
128662306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */
128762306a36Sopenharmony_ci		/* llilf %w0,imm  */
128862306a36Sopenharmony_ci		EMIT6_IMM(0xc00f0000, REG_W0, (u32) imm);
128962306a36Sopenharmony_ci		/* sty %w0,off(%dst) */
129062306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, dst_reg, REG_0, off);
129162306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
129262306a36Sopenharmony_ci		break;
129362306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */
129462306a36Sopenharmony_ci		/* lgfi %w0,imm */
129562306a36Sopenharmony_ci		EMIT6_IMM(0xc0010000, REG_W0, imm);
129662306a36Sopenharmony_ci		/* stg %w0,off(%dst) */
129762306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, dst_reg, REG_0, off);
129862306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
129962306a36Sopenharmony_ci		break;
130062306a36Sopenharmony_ci	/*
130162306a36Sopenharmony_ci	 * BPF_ATOMIC
130262306a36Sopenharmony_ci	 */
130362306a36Sopenharmony_ci	case BPF_STX | BPF_ATOMIC | BPF_DW:
130462306a36Sopenharmony_ci	case BPF_STX | BPF_ATOMIC | BPF_W:
130562306a36Sopenharmony_ci	{
130662306a36Sopenharmony_ci		bool is32 = BPF_SIZE(insn->code) == BPF_W;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci		switch (insn->imm) {
130962306a36Sopenharmony_ci/* {op32|op64} {%w0|%src},%src,off(%dst) */
131062306a36Sopenharmony_ci#define EMIT_ATOMIC(op32, op64) do {					\
131162306a36Sopenharmony_ci	EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64),		\
131262306a36Sopenharmony_ci		      (insn->imm & BPF_FETCH) ? src_reg : REG_W0,	\
131362306a36Sopenharmony_ci		      src_reg, dst_reg, off);				\
131462306a36Sopenharmony_ci	if (is32 && (insn->imm & BPF_FETCH))				\
131562306a36Sopenharmony_ci		EMIT_ZERO(src_reg);					\
131662306a36Sopenharmony_ci} while (0)
131762306a36Sopenharmony_ci		case BPF_ADD:
131862306a36Sopenharmony_ci		case BPF_ADD | BPF_FETCH:
131962306a36Sopenharmony_ci			/* {laal|laalg} */
132062306a36Sopenharmony_ci			EMIT_ATOMIC(0x00fa, 0x00ea);
132162306a36Sopenharmony_ci			break;
132262306a36Sopenharmony_ci		case BPF_AND:
132362306a36Sopenharmony_ci		case BPF_AND | BPF_FETCH:
132462306a36Sopenharmony_ci			/* {lan|lang} */
132562306a36Sopenharmony_ci			EMIT_ATOMIC(0x00f4, 0x00e4);
132662306a36Sopenharmony_ci			break;
132762306a36Sopenharmony_ci		case BPF_OR:
132862306a36Sopenharmony_ci		case BPF_OR | BPF_FETCH:
132962306a36Sopenharmony_ci			/* {lao|laog} */
133062306a36Sopenharmony_ci			EMIT_ATOMIC(0x00f6, 0x00e6);
133162306a36Sopenharmony_ci			break;
133262306a36Sopenharmony_ci		case BPF_XOR:
133362306a36Sopenharmony_ci		case BPF_XOR | BPF_FETCH:
133462306a36Sopenharmony_ci			/* {lax|laxg} */
133562306a36Sopenharmony_ci			EMIT_ATOMIC(0x00f7, 0x00e7);
133662306a36Sopenharmony_ci			break;
133762306a36Sopenharmony_ci#undef EMIT_ATOMIC
133862306a36Sopenharmony_ci		case BPF_XCHG:
133962306a36Sopenharmony_ci			/* {ly|lg} %w0,off(%dst) */
134062306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000,
134162306a36Sopenharmony_ci				      is32 ? 0x0058 : 0x0004, REG_W0, REG_0,
134262306a36Sopenharmony_ci				      dst_reg, off);
134362306a36Sopenharmony_ci			/* 0: {csy|csg} %w0,%src,off(%dst) */
134462306a36Sopenharmony_ci			EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030,
134562306a36Sopenharmony_ci				      REG_W0, src_reg, dst_reg, off);
134662306a36Sopenharmony_ci			/* brc 4,0b */
134762306a36Sopenharmony_ci			EMIT4_PCREL_RIC(0xa7040000, 4, jit->prg - 6);
134862306a36Sopenharmony_ci			/* {llgfr|lgr} %src,%w0 */
134962306a36Sopenharmony_ci			EMIT4(is32 ? 0xb9160000 : 0xb9040000, src_reg, REG_W0);
135062306a36Sopenharmony_ci			if (is32 && insn_is_zext(&insn[1]))
135162306a36Sopenharmony_ci				insn_count = 2;
135262306a36Sopenharmony_ci			break;
135362306a36Sopenharmony_ci		case BPF_CMPXCHG:
135462306a36Sopenharmony_ci			/* 0: {csy|csg} %b0,%src,off(%dst) */
135562306a36Sopenharmony_ci			EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030,
135662306a36Sopenharmony_ci				      BPF_REG_0, src_reg, dst_reg, off);
135762306a36Sopenharmony_ci			break;
135862306a36Sopenharmony_ci		default:
135962306a36Sopenharmony_ci			pr_err("Unknown atomic operation %02x\n", insn->imm);
136062306a36Sopenharmony_ci			return -1;
136162306a36Sopenharmony_ci		}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
136462306a36Sopenharmony_ci		break;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci	/*
136762306a36Sopenharmony_ci	 * BPF_LDX
136862306a36Sopenharmony_ci	 */
136962306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
137062306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_B:
137162306a36Sopenharmony_ci		/* llgc %dst,0(off,%src) */
137262306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0090, dst_reg, src_reg, REG_0, off);
137362306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
137462306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
137562306a36Sopenharmony_ci			insn_count = 2;
137662306a36Sopenharmony_ci		break;
137762306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
137862306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_H:
137962306a36Sopenharmony_ci		/* llgh %dst,0(off,%src) */
138062306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0091, dst_reg, src_reg, REG_0, off);
138162306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
138262306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
138362306a36Sopenharmony_ci			insn_count = 2;
138462306a36Sopenharmony_ci		break;
138562306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
138662306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_W:
138762306a36Sopenharmony_ci		/* llgf %dst,off(%src) */
138862306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
138962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0016, dst_reg, src_reg, REG_0, off);
139062306a36Sopenharmony_ci		if (insn_is_zext(&insn[1]))
139162306a36Sopenharmony_ci			insn_count = 2;
139262306a36Sopenharmony_ci		break;
139362306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
139462306a36Sopenharmony_ci	case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
139562306a36Sopenharmony_ci		/* lg %dst,0(off,%src) */
139662306a36Sopenharmony_ci		jit->seen |= SEEN_MEM;
139762306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0004, dst_reg, src_reg, REG_0, off);
139862306a36Sopenharmony_ci		break;
139962306a36Sopenharmony_ci	/*
140062306a36Sopenharmony_ci	 * BPF_JMP / CALL
140162306a36Sopenharmony_ci	 */
140262306a36Sopenharmony_ci	case BPF_JMP | BPF_CALL:
140362306a36Sopenharmony_ci	{
140462306a36Sopenharmony_ci		const struct btf_func_model *m;
140562306a36Sopenharmony_ci		bool func_addr_fixed;
140662306a36Sopenharmony_ci		int j, ret;
140762306a36Sopenharmony_ci		u64 func;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		ret = bpf_jit_get_func_addr(fp, insn, extra_pass,
141062306a36Sopenharmony_ci					    &func, &func_addr_fixed);
141162306a36Sopenharmony_ci		if (ret < 0)
141262306a36Sopenharmony_ci			return -1;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		REG_SET_SEEN(BPF_REG_5);
141562306a36Sopenharmony_ci		jit->seen |= SEEN_FUNC;
141662306a36Sopenharmony_ci		/*
141762306a36Sopenharmony_ci		 * Copy the tail call counter to where the callee expects it.
141862306a36Sopenharmony_ci		 *
141962306a36Sopenharmony_ci		 * Note 1: The callee can increment the tail call counter, but
142062306a36Sopenharmony_ci		 * we do not load it back, since the x86 JIT does not do this
142162306a36Sopenharmony_ci		 * either.
142262306a36Sopenharmony_ci		 *
142362306a36Sopenharmony_ci		 * Note 2: We assume that the verifier does not let us call the
142462306a36Sopenharmony_ci		 * main program, which clears the tail call counter on entry.
142562306a36Sopenharmony_ci		 */
142662306a36Sopenharmony_ci		/* mvc STK_OFF_TCCNT(4,%r15),N(%r15) */
142762306a36Sopenharmony_ci		_EMIT6(0xd203f000 | STK_OFF_TCCNT,
142862306a36Sopenharmony_ci		       0xf000 | (STK_OFF_TCCNT + STK_OFF + stack_depth));
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		/* Sign-extend the kfunc arguments. */
143162306a36Sopenharmony_ci		if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
143262306a36Sopenharmony_ci			m = bpf_jit_find_kfunc_model(fp, insn);
143362306a36Sopenharmony_ci			if (!m)
143462306a36Sopenharmony_ci				return -1;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci			for (j = 0; j < m->nr_args; j++) {
143762306a36Sopenharmony_ci				if (sign_extend(jit, BPF_REG_1 + j,
143862306a36Sopenharmony_ci						m->arg_size[j],
143962306a36Sopenharmony_ci						m->arg_flags[j]))
144062306a36Sopenharmony_ci					return -1;
144162306a36Sopenharmony_ci			}
144262306a36Sopenharmony_ci		}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci		/* lgrl %w1,func */
144562306a36Sopenharmony_ci		EMIT6_PCREL_RILB(0xc4080000, REG_W1, _EMIT_CONST_U64(func));
144662306a36Sopenharmony_ci		/* %r1() */
144762306a36Sopenharmony_ci		call_r1(jit);
144862306a36Sopenharmony_ci		/* lgr %b0,%r2: load return value into %b0 */
144962306a36Sopenharmony_ci		EMIT4(0xb9040000, BPF_REG_0, REG_2);
145062306a36Sopenharmony_ci		break;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci	case BPF_JMP | BPF_TAIL_CALL: {
145362306a36Sopenharmony_ci		int patch_1_clrj, patch_2_clij, patch_3_brc;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		/*
145662306a36Sopenharmony_ci		 * Implicit input:
145762306a36Sopenharmony_ci		 *  B1: pointer to ctx
145862306a36Sopenharmony_ci		 *  B2: pointer to bpf_array
145962306a36Sopenharmony_ci		 *  B3: index in bpf_array
146062306a36Sopenharmony_ci		 *
146162306a36Sopenharmony_ci		 * if (index >= array->map.max_entries)
146262306a36Sopenharmony_ci		 *         goto out;
146362306a36Sopenharmony_ci		 */
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci		/* llgf %w1,map.max_entries(%b2) */
146662306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
146762306a36Sopenharmony_ci			      offsetof(struct bpf_array, map.max_entries));
146862306a36Sopenharmony_ci		/* if ((u32)%b3 >= (u32)%w1) goto out; */
146962306a36Sopenharmony_ci		/* clrj %b3,%w1,0xa,out */
147062306a36Sopenharmony_ci		patch_1_clrj = jit->prg;
147162306a36Sopenharmony_ci		EMIT6_PCREL_RIEB(0xec000000, 0x0077, BPF_REG_3, REG_W1, 0xa,
147262306a36Sopenharmony_ci				 jit->prg);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		/*
147562306a36Sopenharmony_ci		 * if (tail_call_cnt++ >= MAX_TAIL_CALL_CNT)
147662306a36Sopenharmony_ci		 *         goto out;
147762306a36Sopenharmony_ci		 */
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		if (jit->seen & SEEN_STACK)
148062306a36Sopenharmony_ci			off = STK_OFF_TCCNT + STK_OFF + stack_depth;
148162306a36Sopenharmony_ci		else
148262306a36Sopenharmony_ci			off = STK_OFF_TCCNT;
148362306a36Sopenharmony_ci		/* lhi %w0,1 */
148462306a36Sopenharmony_ci		EMIT4_IMM(0xa7080000, REG_W0, 1);
148562306a36Sopenharmony_ci		/* laal %w1,%w0,off(%r15) */
148662306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off);
148762306a36Sopenharmony_ci		/* clij %w1,MAX_TAIL_CALL_CNT-1,0x2,out */
148862306a36Sopenharmony_ci		patch_2_clij = jit->prg;
148962306a36Sopenharmony_ci		EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT - 1,
149062306a36Sopenharmony_ci				 2, jit->prg);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci		/*
149362306a36Sopenharmony_ci		 * prog = array->ptrs[index];
149462306a36Sopenharmony_ci		 * if (prog == NULL)
149562306a36Sopenharmony_ci		 *         goto out;
149662306a36Sopenharmony_ci		 */
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		/* llgfr %r1,%b3: %r1 = (u32) index */
149962306a36Sopenharmony_ci		EMIT4(0xb9160000, REG_1, BPF_REG_3);
150062306a36Sopenharmony_ci		/* sllg %r1,%r1,3: %r1 *= 8 */
150162306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, REG_1, REG_0, 3);
150262306a36Sopenharmony_ci		/* ltg %r1,prog(%b2,%r1) */
150362306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2,
150462306a36Sopenharmony_ci			      REG_1, offsetof(struct bpf_array, ptrs));
150562306a36Sopenharmony_ci		/* brc 0x8,out */
150662306a36Sopenharmony_ci		patch_3_brc = jit->prg;
150762306a36Sopenharmony_ci		EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci		/*
151062306a36Sopenharmony_ci		 * Restore registers before calling function
151162306a36Sopenharmony_ci		 */
151262306a36Sopenharmony_ci		save_restore_regs(jit, REGS_RESTORE, stack_depth);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		/*
151562306a36Sopenharmony_ci		 * goto *(prog->bpf_func + tail_call_start);
151662306a36Sopenharmony_ci		 */
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci		/* lg %r1,bpf_func(%r1) */
151962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, REG_1, REG_0,
152062306a36Sopenharmony_ci			      offsetof(struct bpf_prog, bpf_func));
152162306a36Sopenharmony_ci		if (nospec_uses_trampoline()) {
152262306a36Sopenharmony_ci			jit->seen |= SEEN_FUNC;
152362306a36Sopenharmony_ci			/* aghi %r1,tail_call_start */
152462306a36Sopenharmony_ci			EMIT4_IMM(0xa70b0000, REG_1, jit->tail_call_start);
152562306a36Sopenharmony_ci			/* brcl 0xf,__s390_indirect_jump_r1 */
152662306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000, 0xf, jit->r1_thunk_ip);
152762306a36Sopenharmony_ci		} else {
152862306a36Sopenharmony_ci			/* bc 0xf,tail_call_start(%r1) */
152962306a36Sopenharmony_ci			_EMIT4(0x47f01000 + jit->tail_call_start);
153062306a36Sopenharmony_ci		}
153162306a36Sopenharmony_ci		/* out: */
153262306a36Sopenharmony_ci		if (jit->prg_buf) {
153362306a36Sopenharmony_ci			*(u16 *)(jit->prg_buf + patch_1_clrj + 2) =
153462306a36Sopenharmony_ci				(jit->prg - patch_1_clrj) >> 1;
153562306a36Sopenharmony_ci			*(u16 *)(jit->prg_buf + patch_2_clij + 2) =
153662306a36Sopenharmony_ci				(jit->prg - patch_2_clij) >> 1;
153762306a36Sopenharmony_ci			*(u16 *)(jit->prg_buf + patch_3_brc + 2) =
153862306a36Sopenharmony_ci				(jit->prg - patch_3_brc) >> 1;
153962306a36Sopenharmony_ci		}
154062306a36Sopenharmony_ci		break;
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci	case BPF_JMP | BPF_EXIT: /* return b0 */
154362306a36Sopenharmony_ci		last = (i == fp->len - 1) ? 1 : 0;
154462306a36Sopenharmony_ci		if (last)
154562306a36Sopenharmony_ci			break;
154662306a36Sopenharmony_ci		if (!is_first_pass(jit) && can_use_rel(jit, jit->exit_ip))
154762306a36Sopenharmony_ci			/* brc 0xf, <exit> */
154862306a36Sopenharmony_ci			EMIT4_PCREL_RIC(0xa7040000, 0xf, jit->exit_ip);
154962306a36Sopenharmony_ci		else
155062306a36Sopenharmony_ci			/* brcl 0xf, <exit> */
155162306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000, 0xf, jit->exit_ip);
155262306a36Sopenharmony_ci		break;
155362306a36Sopenharmony_ci	/*
155462306a36Sopenharmony_ci	 * Branch relative (number of skipped instructions) to offset on
155562306a36Sopenharmony_ci	 * condition.
155662306a36Sopenharmony_ci	 *
155762306a36Sopenharmony_ci	 * Condition code to mask mapping:
155862306a36Sopenharmony_ci	 *
155962306a36Sopenharmony_ci	 * CC | Description	   | Mask
156062306a36Sopenharmony_ci	 * ------------------------------
156162306a36Sopenharmony_ci	 * 0  | Operands equal	   |	8
156262306a36Sopenharmony_ci	 * 1  | First operand low  |	4
156362306a36Sopenharmony_ci	 * 2  | First operand high |	2
156462306a36Sopenharmony_ci	 * 3  | Unused		   |	1
156562306a36Sopenharmony_ci	 *
156662306a36Sopenharmony_ci	 * For s390x relative branches: ip = ip + off_bytes
156762306a36Sopenharmony_ci	 * For BPF relative branches:	insn = insn + off_insns + 1
156862306a36Sopenharmony_ci	 *
156962306a36Sopenharmony_ci	 * For example for s390x with offset 0 we jump to the branch
157062306a36Sopenharmony_ci	 * instruction itself (loop) and for BPF with offset 0 we
157162306a36Sopenharmony_ci	 * branch to the instruction behind the branch.
157262306a36Sopenharmony_ci	 */
157362306a36Sopenharmony_ci	case BPF_JMP | BPF_JA: /* if (true) */
157462306a36Sopenharmony_ci		mask = 0xf000; /* j */
157562306a36Sopenharmony_ci		goto branch_oc;
157662306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_K: /* ((s64) dst > (s64) imm) */
157762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGT | BPF_K: /* ((s32) dst > (s32) imm) */
157862306a36Sopenharmony_ci		mask = 0x2000; /* jh */
157962306a36Sopenharmony_ci		goto branch_ks;
158062306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_K: /* ((s64) dst < (s64) imm) */
158162306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLT | BPF_K: /* ((s32) dst < (s32) imm) */
158262306a36Sopenharmony_ci		mask = 0x4000; /* jl */
158362306a36Sopenharmony_ci		goto branch_ks;
158462306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_K: /* ((s64) dst >= (s64) imm) */
158562306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGE | BPF_K: /* ((s32) dst >= (s32) imm) */
158662306a36Sopenharmony_ci		mask = 0xa000; /* jhe */
158762306a36Sopenharmony_ci		goto branch_ks;
158862306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_K: /* ((s64) dst <= (s64) imm) */
158962306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLE | BPF_K: /* ((s32) dst <= (s32) imm) */
159062306a36Sopenharmony_ci		mask = 0xc000; /* jle */
159162306a36Sopenharmony_ci		goto branch_ks;
159262306a36Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_K: /* (dst_reg > imm) */
159362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGT | BPF_K: /* ((u32) dst_reg > (u32) imm) */
159462306a36Sopenharmony_ci		mask = 0x2000; /* jh */
159562306a36Sopenharmony_ci		goto branch_ku;
159662306a36Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_K: /* (dst_reg < imm) */
159762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLT | BPF_K: /* ((u32) dst_reg < (u32) imm) */
159862306a36Sopenharmony_ci		mask = 0x4000; /* jl */
159962306a36Sopenharmony_ci		goto branch_ku;
160062306a36Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_K: /* (dst_reg >= imm) */
160162306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGE | BPF_K: /* ((u32) dst_reg >= (u32) imm) */
160262306a36Sopenharmony_ci		mask = 0xa000; /* jhe */
160362306a36Sopenharmony_ci		goto branch_ku;
160462306a36Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_K: /* (dst_reg <= imm) */
160562306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLE | BPF_K: /* ((u32) dst_reg <= (u32) imm) */
160662306a36Sopenharmony_ci		mask = 0xc000; /* jle */
160762306a36Sopenharmony_ci		goto branch_ku;
160862306a36Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_K: /* (dst_reg != imm) */
160962306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JNE | BPF_K: /* ((u32) dst_reg != (u32) imm) */
161062306a36Sopenharmony_ci		mask = 0x7000; /* jne */
161162306a36Sopenharmony_ci		goto branch_ku;
161262306a36Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_K: /* (dst_reg == imm) */
161362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JEQ | BPF_K: /* ((u32) dst_reg == (u32) imm) */
161462306a36Sopenharmony_ci		mask = 0x8000; /* je */
161562306a36Sopenharmony_ci		goto branch_ku;
161662306a36Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_K: /* (dst_reg & imm) */
161762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSET | BPF_K: /* ((u32) dst_reg & (u32) imm) */
161862306a36Sopenharmony_ci		mask = 0x7000; /* jnz */
161962306a36Sopenharmony_ci		if (BPF_CLASS(insn->code) == BPF_JMP32) {
162062306a36Sopenharmony_ci			/* llilf %w1,imm (load zero extend imm) */
162162306a36Sopenharmony_ci			EMIT6_IMM(0xc00f0000, REG_W1, imm);
162262306a36Sopenharmony_ci			/* nr %w1,%dst */
162362306a36Sopenharmony_ci			EMIT2(0x1400, REG_W1, dst_reg);
162462306a36Sopenharmony_ci		} else {
162562306a36Sopenharmony_ci			/* lgfi %w1,imm (load sign extend imm) */
162662306a36Sopenharmony_ci			EMIT6_IMM(0xc0010000, REG_W1, imm);
162762306a36Sopenharmony_ci			/* ngr %w1,%dst */
162862306a36Sopenharmony_ci			EMIT4(0xb9800000, REG_W1, dst_reg);
162962306a36Sopenharmony_ci		}
163062306a36Sopenharmony_ci		goto branch_oc;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_X: /* ((s64) dst > (s64) src) */
163362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGT | BPF_X: /* ((s32) dst > (s32) src) */
163462306a36Sopenharmony_ci		mask = 0x2000; /* jh */
163562306a36Sopenharmony_ci		goto branch_xs;
163662306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_X: /* ((s64) dst < (s64) src) */
163762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLT | BPF_X: /* ((s32) dst < (s32) src) */
163862306a36Sopenharmony_ci		mask = 0x4000; /* jl */
163962306a36Sopenharmony_ci		goto branch_xs;
164062306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_X: /* ((s64) dst >= (s64) src) */
164162306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGE | BPF_X: /* ((s32) dst >= (s32) src) */
164262306a36Sopenharmony_ci		mask = 0xa000; /* jhe */
164362306a36Sopenharmony_ci		goto branch_xs;
164462306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_X: /* ((s64) dst <= (s64) src) */
164562306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLE | BPF_X: /* ((s32) dst <= (s32) src) */
164662306a36Sopenharmony_ci		mask = 0xc000; /* jle */
164762306a36Sopenharmony_ci		goto branch_xs;
164862306a36Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_X: /* (dst > src) */
164962306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGT | BPF_X: /* ((u32) dst > (u32) src) */
165062306a36Sopenharmony_ci		mask = 0x2000; /* jh */
165162306a36Sopenharmony_ci		goto branch_xu;
165262306a36Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_X: /* (dst < src) */
165362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLT | BPF_X: /* ((u32) dst < (u32) src) */
165462306a36Sopenharmony_ci		mask = 0x4000; /* jl */
165562306a36Sopenharmony_ci		goto branch_xu;
165662306a36Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_X: /* (dst >= src) */
165762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGE | BPF_X: /* ((u32) dst >= (u32) src) */
165862306a36Sopenharmony_ci		mask = 0xa000; /* jhe */
165962306a36Sopenharmony_ci		goto branch_xu;
166062306a36Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_X: /* (dst <= src) */
166162306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLE | BPF_X: /* ((u32) dst <= (u32) src) */
166262306a36Sopenharmony_ci		mask = 0xc000; /* jle */
166362306a36Sopenharmony_ci		goto branch_xu;
166462306a36Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_X: /* (dst != src) */
166562306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JNE | BPF_X: /* ((u32) dst != (u32) src) */
166662306a36Sopenharmony_ci		mask = 0x7000; /* jne */
166762306a36Sopenharmony_ci		goto branch_xu;
166862306a36Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_X: /* (dst == src) */
166962306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JEQ | BPF_X: /* ((u32) dst == (u32) src) */
167062306a36Sopenharmony_ci		mask = 0x8000; /* je */
167162306a36Sopenharmony_ci		goto branch_xu;
167262306a36Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_X: /* (dst & src) */
167362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSET | BPF_X: /* ((u32) dst & (u32) src) */
167462306a36Sopenharmony_ci	{
167562306a36Sopenharmony_ci		bool is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		mask = 0x7000; /* jnz */
167862306a36Sopenharmony_ci		/* nrk or ngrk %w1,%dst,%src */
167962306a36Sopenharmony_ci		EMIT4_RRF((is_jmp32 ? 0xb9f40000 : 0xb9e40000),
168062306a36Sopenharmony_ci			  REG_W1, dst_reg, src_reg);
168162306a36Sopenharmony_ci		goto branch_oc;
168262306a36Sopenharmony_cibranch_ks:
168362306a36Sopenharmony_ci		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
168462306a36Sopenharmony_ci		/* cfi or cgfi %dst,imm */
168562306a36Sopenharmony_ci		EMIT6_IMM(is_jmp32 ? 0xc20d0000 : 0xc20c0000,
168662306a36Sopenharmony_ci			  dst_reg, imm);
168762306a36Sopenharmony_ci		if (!is_first_pass(jit) &&
168862306a36Sopenharmony_ci		    can_use_rel(jit, addrs[i + off + 1])) {
168962306a36Sopenharmony_ci			/* brc mask,off */
169062306a36Sopenharmony_ci			EMIT4_PCREL_RIC(0xa7040000,
169162306a36Sopenharmony_ci					mask >> 12, addrs[i + off + 1]);
169262306a36Sopenharmony_ci		} else {
169362306a36Sopenharmony_ci			/* brcl mask,off */
169462306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000,
169562306a36Sopenharmony_ci					 mask >> 12, addrs[i + off + 1]);
169662306a36Sopenharmony_ci		}
169762306a36Sopenharmony_ci		break;
169862306a36Sopenharmony_cibranch_ku:
169962306a36Sopenharmony_ci		/* lgfi %w1,imm (load sign extend imm) */
170062306a36Sopenharmony_ci		src_reg = REG_1;
170162306a36Sopenharmony_ci		EMIT6_IMM(0xc0010000, src_reg, imm);
170262306a36Sopenharmony_ci		goto branch_xu;
170362306a36Sopenharmony_cibranch_xs:
170462306a36Sopenharmony_ci		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
170562306a36Sopenharmony_ci		if (!is_first_pass(jit) &&
170662306a36Sopenharmony_ci		    can_use_rel(jit, addrs[i + off + 1])) {
170762306a36Sopenharmony_ci			/* crj or cgrj %dst,%src,mask,off */
170862306a36Sopenharmony_ci			EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0076 : 0x0064),
170962306a36Sopenharmony_ci				    dst_reg, src_reg, i, off, mask);
171062306a36Sopenharmony_ci		} else {
171162306a36Sopenharmony_ci			/* cr or cgr %dst,%src */
171262306a36Sopenharmony_ci			if (is_jmp32)
171362306a36Sopenharmony_ci				EMIT2(0x1900, dst_reg, src_reg);
171462306a36Sopenharmony_ci			else
171562306a36Sopenharmony_ci				EMIT4(0xb9200000, dst_reg, src_reg);
171662306a36Sopenharmony_ci			/* brcl mask,off */
171762306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000,
171862306a36Sopenharmony_ci					 mask >> 12, addrs[i + off + 1]);
171962306a36Sopenharmony_ci		}
172062306a36Sopenharmony_ci		break;
172162306a36Sopenharmony_cibranch_xu:
172262306a36Sopenharmony_ci		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
172362306a36Sopenharmony_ci		if (!is_first_pass(jit) &&
172462306a36Sopenharmony_ci		    can_use_rel(jit, addrs[i + off + 1])) {
172562306a36Sopenharmony_ci			/* clrj or clgrj %dst,%src,mask,off */
172662306a36Sopenharmony_ci			EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0077 : 0x0065),
172762306a36Sopenharmony_ci				    dst_reg, src_reg, i, off, mask);
172862306a36Sopenharmony_ci		} else {
172962306a36Sopenharmony_ci			/* clr or clgr %dst,%src */
173062306a36Sopenharmony_ci			if (is_jmp32)
173162306a36Sopenharmony_ci				EMIT2(0x1500, dst_reg, src_reg);
173262306a36Sopenharmony_ci			else
173362306a36Sopenharmony_ci				EMIT4(0xb9210000, dst_reg, src_reg);
173462306a36Sopenharmony_ci			/* brcl mask,off */
173562306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000,
173662306a36Sopenharmony_ci					 mask >> 12, addrs[i + off + 1]);
173762306a36Sopenharmony_ci		}
173862306a36Sopenharmony_ci		break;
173962306a36Sopenharmony_cibranch_oc:
174062306a36Sopenharmony_ci		if (!is_first_pass(jit) &&
174162306a36Sopenharmony_ci		    can_use_rel(jit, addrs[i + off + 1])) {
174262306a36Sopenharmony_ci			/* brc mask,off */
174362306a36Sopenharmony_ci			EMIT4_PCREL_RIC(0xa7040000,
174462306a36Sopenharmony_ci					mask >> 12, addrs[i + off + 1]);
174562306a36Sopenharmony_ci		} else {
174662306a36Sopenharmony_ci			/* brcl mask,off */
174762306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000,
174862306a36Sopenharmony_ci					 mask >> 12, addrs[i + off + 1]);
174962306a36Sopenharmony_ci		}
175062306a36Sopenharmony_ci		break;
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci	default: /* too complex, give up */
175362306a36Sopenharmony_ci		pr_err("Unknown opcode %02x\n", insn->code);
175462306a36Sopenharmony_ci		return -1;
175562306a36Sopenharmony_ci	}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	if (probe_prg != -1) {
175862306a36Sopenharmony_ci		/*
175962306a36Sopenharmony_ci		 * Handlers of certain exceptions leave psw.addr pointing to
176062306a36Sopenharmony_ci		 * the instruction directly after the failing one. Therefore,
176162306a36Sopenharmony_ci		 * create two exception table entries and also add a nop in
176262306a36Sopenharmony_ci		 * case two probing instructions come directly after each
176362306a36Sopenharmony_ci		 * other.
176462306a36Sopenharmony_ci		 */
176562306a36Sopenharmony_ci		nop_prg = jit->prg;
176662306a36Sopenharmony_ci		/* bcr 0,%0 */
176762306a36Sopenharmony_ci		_EMIT2(0x0700);
176862306a36Sopenharmony_ci		err = bpf_jit_probe_mem(jit, fp, probe_prg, nop_prg);
176962306a36Sopenharmony_ci		if (err < 0)
177062306a36Sopenharmony_ci			return err;
177162306a36Sopenharmony_ci	}
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	return insn_count;
177462306a36Sopenharmony_ci}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci/*
177762306a36Sopenharmony_ci * Return whether new i-th instruction address does not violate any invariant
177862306a36Sopenharmony_ci */
177962306a36Sopenharmony_cistatic bool bpf_is_new_addr_sane(struct bpf_jit *jit, int i)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	/* On the first pass anything goes */
178262306a36Sopenharmony_ci	if (is_first_pass(jit))
178362306a36Sopenharmony_ci		return true;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	/* The codegen pass must not change anything */
178662306a36Sopenharmony_ci	if (is_codegen_pass(jit))
178762306a36Sopenharmony_ci		return jit->addrs[i] == jit->prg;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	/* Passes in between must not increase code size */
179062306a36Sopenharmony_ci	return jit->addrs[i] >= jit->prg;
179162306a36Sopenharmony_ci}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci/*
179462306a36Sopenharmony_ci * Update the address of i-th instruction
179562306a36Sopenharmony_ci */
179662306a36Sopenharmony_cistatic int bpf_set_addr(struct bpf_jit *jit, int i)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	int delta;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (is_codegen_pass(jit)) {
180162306a36Sopenharmony_ci		delta = jit->prg - jit->addrs[i];
180262306a36Sopenharmony_ci		if (delta < 0)
180362306a36Sopenharmony_ci			bpf_skip(jit, -delta);
180462306a36Sopenharmony_ci	}
180562306a36Sopenharmony_ci	if (WARN_ON_ONCE(!bpf_is_new_addr_sane(jit, i)))
180662306a36Sopenharmony_ci		return -1;
180762306a36Sopenharmony_ci	jit->addrs[i] = jit->prg;
180862306a36Sopenharmony_ci	return 0;
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci/*
181262306a36Sopenharmony_ci * Compile eBPF program into s390x code
181362306a36Sopenharmony_ci */
181462306a36Sopenharmony_cistatic int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
181562306a36Sopenharmony_ci			bool extra_pass, u32 stack_depth)
181662306a36Sopenharmony_ci{
181762306a36Sopenharmony_ci	int i, insn_count, lit32_size, lit64_size;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	jit->lit32 = jit->lit32_start;
182062306a36Sopenharmony_ci	jit->lit64 = jit->lit64_start;
182162306a36Sopenharmony_ci	jit->prg = 0;
182262306a36Sopenharmony_ci	jit->excnt = 0;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	bpf_jit_prologue(jit, fp, stack_depth);
182562306a36Sopenharmony_ci	if (bpf_set_addr(jit, 0) < 0)
182662306a36Sopenharmony_ci		return -1;
182762306a36Sopenharmony_ci	for (i = 0; i < fp->len; i += insn_count) {
182862306a36Sopenharmony_ci		insn_count = bpf_jit_insn(jit, fp, i, extra_pass, stack_depth);
182962306a36Sopenharmony_ci		if (insn_count < 0)
183062306a36Sopenharmony_ci			return -1;
183162306a36Sopenharmony_ci		/* Next instruction address */
183262306a36Sopenharmony_ci		if (bpf_set_addr(jit, i + insn_count) < 0)
183362306a36Sopenharmony_ci			return -1;
183462306a36Sopenharmony_ci	}
183562306a36Sopenharmony_ci	bpf_jit_epilogue(jit, stack_depth);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	lit32_size = jit->lit32 - jit->lit32_start;
183862306a36Sopenharmony_ci	lit64_size = jit->lit64 - jit->lit64_start;
183962306a36Sopenharmony_ci	jit->lit32_start = jit->prg;
184062306a36Sopenharmony_ci	if (lit32_size)
184162306a36Sopenharmony_ci		jit->lit32_start = ALIGN(jit->lit32_start, 4);
184262306a36Sopenharmony_ci	jit->lit64_start = jit->lit32_start + lit32_size;
184362306a36Sopenharmony_ci	if (lit64_size)
184462306a36Sopenharmony_ci		jit->lit64_start = ALIGN(jit->lit64_start, 8);
184562306a36Sopenharmony_ci	jit->size = jit->lit64_start + lit64_size;
184662306a36Sopenharmony_ci	jit->size_prg = jit->prg;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	if (WARN_ON_ONCE(fp->aux->extable &&
184962306a36Sopenharmony_ci			 jit->excnt != fp->aux->num_exentries))
185062306a36Sopenharmony_ci		/* Verifier bug - too many entries. */
185162306a36Sopenharmony_ci		return -1;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return 0;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_cibool bpf_jit_needs_zext(void)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	return true;
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cistruct s390_jit_data {
186262306a36Sopenharmony_ci	struct bpf_binary_header *header;
186362306a36Sopenharmony_ci	struct bpf_jit ctx;
186462306a36Sopenharmony_ci	int pass;
186562306a36Sopenharmony_ci};
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_cistatic struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
186862306a36Sopenharmony_ci					       struct bpf_prog *fp)
186962306a36Sopenharmony_ci{
187062306a36Sopenharmony_ci	struct bpf_binary_header *header;
187162306a36Sopenharmony_ci	u32 extable_size;
187262306a36Sopenharmony_ci	u32 code_size;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	/* We need two entries per insn. */
187562306a36Sopenharmony_ci	fp->aux->num_exentries *= 2;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	code_size = roundup(jit->size,
187862306a36Sopenharmony_ci			    __alignof__(struct exception_table_entry));
187962306a36Sopenharmony_ci	extable_size = fp->aux->num_exentries *
188062306a36Sopenharmony_ci		sizeof(struct exception_table_entry);
188162306a36Sopenharmony_ci	header = bpf_jit_binary_alloc(code_size + extable_size, &jit->prg_buf,
188262306a36Sopenharmony_ci				      8, jit_fill_hole);
188362306a36Sopenharmony_ci	if (!header)
188462306a36Sopenharmony_ci		return NULL;
188562306a36Sopenharmony_ci	fp->aux->extable = (struct exception_table_entry *)
188662306a36Sopenharmony_ci		(jit->prg_buf + code_size);
188762306a36Sopenharmony_ci	return header;
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci/*
189162306a36Sopenharmony_ci * Compile eBPF program "fp"
189262306a36Sopenharmony_ci */
189362306a36Sopenharmony_cistruct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
189462306a36Sopenharmony_ci{
189562306a36Sopenharmony_ci	u32 stack_depth = round_up(fp->aux->stack_depth, 8);
189662306a36Sopenharmony_ci	struct bpf_prog *tmp, *orig_fp = fp;
189762306a36Sopenharmony_ci	struct bpf_binary_header *header;
189862306a36Sopenharmony_ci	struct s390_jit_data *jit_data;
189962306a36Sopenharmony_ci	bool tmp_blinded = false;
190062306a36Sopenharmony_ci	bool extra_pass = false;
190162306a36Sopenharmony_ci	struct bpf_jit jit;
190262306a36Sopenharmony_ci	int pass;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (WARN_ON_ONCE(bpf_plt_end - bpf_plt != BPF_PLT_SIZE))
190562306a36Sopenharmony_ci		return orig_fp;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	if (!fp->jit_requested)
190862306a36Sopenharmony_ci		return orig_fp;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	tmp = bpf_jit_blind_constants(fp);
191162306a36Sopenharmony_ci	/*
191262306a36Sopenharmony_ci	 * If blinding was requested and we failed during blinding,
191362306a36Sopenharmony_ci	 * we must fall back to the interpreter.
191462306a36Sopenharmony_ci	 */
191562306a36Sopenharmony_ci	if (IS_ERR(tmp))
191662306a36Sopenharmony_ci		return orig_fp;
191762306a36Sopenharmony_ci	if (tmp != fp) {
191862306a36Sopenharmony_ci		tmp_blinded = true;
191962306a36Sopenharmony_ci		fp = tmp;
192062306a36Sopenharmony_ci	}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	jit_data = fp->aux->jit_data;
192362306a36Sopenharmony_ci	if (!jit_data) {
192462306a36Sopenharmony_ci		jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL);
192562306a36Sopenharmony_ci		if (!jit_data) {
192662306a36Sopenharmony_ci			fp = orig_fp;
192762306a36Sopenharmony_ci			goto out;
192862306a36Sopenharmony_ci		}
192962306a36Sopenharmony_ci		fp->aux->jit_data = jit_data;
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci	if (jit_data->ctx.addrs) {
193262306a36Sopenharmony_ci		jit = jit_data->ctx;
193362306a36Sopenharmony_ci		header = jit_data->header;
193462306a36Sopenharmony_ci		extra_pass = true;
193562306a36Sopenharmony_ci		pass = jit_data->pass + 1;
193662306a36Sopenharmony_ci		goto skip_init_ctx;
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	memset(&jit, 0, sizeof(jit));
194062306a36Sopenharmony_ci	jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
194162306a36Sopenharmony_ci	if (jit.addrs == NULL) {
194262306a36Sopenharmony_ci		fp = orig_fp;
194362306a36Sopenharmony_ci		goto free_addrs;
194462306a36Sopenharmony_ci	}
194562306a36Sopenharmony_ci	/*
194662306a36Sopenharmony_ci	 * Three initial passes:
194762306a36Sopenharmony_ci	 *   - 1/2: Determine clobbered registers
194862306a36Sopenharmony_ci	 *   - 3:   Calculate program size and addrs array
194962306a36Sopenharmony_ci	 */
195062306a36Sopenharmony_ci	for (pass = 1; pass <= 3; pass++) {
195162306a36Sopenharmony_ci		if (bpf_jit_prog(&jit, fp, extra_pass, stack_depth)) {
195262306a36Sopenharmony_ci			fp = orig_fp;
195362306a36Sopenharmony_ci			goto free_addrs;
195462306a36Sopenharmony_ci		}
195562306a36Sopenharmony_ci	}
195662306a36Sopenharmony_ci	/*
195762306a36Sopenharmony_ci	 * Final pass: Allocate and generate program
195862306a36Sopenharmony_ci	 */
195962306a36Sopenharmony_ci	header = bpf_jit_alloc(&jit, fp);
196062306a36Sopenharmony_ci	if (!header) {
196162306a36Sopenharmony_ci		fp = orig_fp;
196262306a36Sopenharmony_ci		goto free_addrs;
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ciskip_init_ctx:
196562306a36Sopenharmony_ci	if (bpf_jit_prog(&jit, fp, extra_pass, stack_depth)) {
196662306a36Sopenharmony_ci		bpf_jit_binary_free(header);
196762306a36Sopenharmony_ci		fp = orig_fp;
196862306a36Sopenharmony_ci		goto free_addrs;
196962306a36Sopenharmony_ci	}
197062306a36Sopenharmony_ci	if (bpf_jit_enable > 1) {
197162306a36Sopenharmony_ci		bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf);
197262306a36Sopenharmony_ci		print_fn_code(jit.prg_buf, jit.size_prg);
197362306a36Sopenharmony_ci	}
197462306a36Sopenharmony_ci	if (!fp->is_func || extra_pass) {
197562306a36Sopenharmony_ci		bpf_jit_binary_lock_ro(header);
197662306a36Sopenharmony_ci	} else {
197762306a36Sopenharmony_ci		jit_data->header = header;
197862306a36Sopenharmony_ci		jit_data->ctx = jit;
197962306a36Sopenharmony_ci		jit_data->pass = pass;
198062306a36Sopenharmony_ci	}
198162306a36Sopenharmony_ci	fp->bpf_func = (void *) jit.prg_buf;
198262306a36Sopenharmony_ci	fp->jited = 1;
198362306a36Sopenharmony_ci	fp->jited_len = jit.size;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	if (!fp->is_func || extra_pass) {
198662306a36Sopenharmony_ci		bpf_prog_fill_jited_linfo(fp, jit.addrs + 1);
198762306a36Sopenharmony_cifree_addrs:
198862306a36Sopenharmony_ci		kvfree(jit.addrs);
198962306a36Sopenharmony_ci		kfree(jit_data);
199062306a36Sopenharmony_ci		fp->aux->jit_data = NULL;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ciout:
199362306a36Sopenharmony_ci	if (tmp_blinded)
199462306a36Sopenharmony_ci		bpf_jit_prog_release_other(fp, fp == orig_fp ?
199562306a36Sopenharmony_ci					   tmp : orig_fp);
199662306a36Sopenharmony_ci	return fp;
199762306a36Sopenharmony_ci}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_cibool bpf_jit_supports_kfunc_call(void)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	return true;
200262306a36Sopenharmony_ci}
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_cibool bpf_jit_supports_far_kfunc_call(void)
200562306a36Sopenharmony_ci{
200662306a36Sopenharmony_ci	return true;
200762306a36Sopenharmony_ci}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ciint bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
201062306a36Sopenharmony_ci		       void *old_addr, void *new_addr)
201162306a36Sopenharmony_ci{
201262306a36Sopenharmony_ci	struct {
201362306a36Sopenharmony_ci		u16 opc;
201462306a36Sopenharmony_ci		s32 disp;
201562306a36Sopenharmony_ci	} __packed insn;
201662306a36Sopenharmony_ci	char expected_plt[BPF_PLT_SIZE];
201762306a36Sopenharmony_ci	char current_plt[BPF_PLT_SIZE];
201862306a36Sopenharmony_ci	char new_plt[BPF_PLT_SIZE];
201962306a36Sopenharmony_ci	char *plt;
202062306a36Sopenharmony_ci	char *ret;
202162306a36Sopenharmony_ci	int err;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	/* Verify the branch to be patched. */
202462306a36Sopenharmony_ci	err = copy_from_kernel_nofault(&insn, ip, sizeof(insn));
202562306a36Sopenharmony_ci	if (err < 0)
202662306a36Sopenharmony_ci		return err;
202762306a36Sopenharmony_ci	if (insn.opc != (0xc004 | (old_addr ? 0xf0 : 0)))
202862306a36Sopenharmony_ci		return -EINVAL;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (t == BPF_MOD_JUMP &&
203162306a36Sopenharmony_ci	    insn.disp == ((char *)new_addr - (char *)ip) >> 1) {
203262306a36Sopenharmony_ci		/*
203362306a36Sopenharmony_ci		 * The branch already points to the destination,
203462306a36Sopenharmony_ci		 * there is no PLT.
203562306a36Sopenharmony_ci		 */
203662306a36Sopenharmony_ci	} else {
203762306a36Sopenharmony_ci		/* Verify the PLT. */
203862306a36Sopenharmony_ci		plt = (char *)ip + (insn.disp << 1);
203962306a36Sopenharmony_ci		err = copy_from_kernel_nofault(current_plt, plt, BPF_PLT_SIZE);
204062306a36Sopenharmony_ci		if (err < 0)
204162306a36Sopenharmony_ci			return err;
204262306a36Sopenharmony_ci		ret = (char *)ip + 6;
204362306a36Sopenharmony_ci		bpf_jit_plt(expected_plt, ret, old_addr);
204462306a36Sopenharmony_ci		if (memcmp(current_plt, expected_plt, BPF_PLT_SIZE))
204562306a36Sopenharmony_ci			return -EINVAL;
204662306a36Sopenharmony_ci		/* Adjust the call address. */
204762306a36Sopenharmony_ci		bpf_jit_plt(new_plt, ret, new_addr);
204862306a36Sopenharmony_ci		s390_kernel_write(plt + (bpf_plt_target - bpf_plt),
204962306a36Sopenharmony_ci				  new_plt + (bpf_plt_target - bpf_plt),
205062306a36Sopenharmony_ci				  sizeof(void *));
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	/* Adjust the mask of the branch. */
205462306a36Sopenharmony_ci	insn.opc = 0xc004 | (new_addr ? 0xf0 : 0);
205562306a36Sopenharmony_ci	s390_kernel_write((char *)ip + 1, (char *)&insn.opc + 1, 1);
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* Make the new code visible to the other CPUs. */
205862306a36Sopenharmony_ci	text_poke_sync_lock();
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	return 0;
206162306a36Sopenharmony_ci}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_cistruct bpf_tramp_jit {
206462306a36Sopenharmony_ci	struct bpf_jit common;
206562306a36Sopenharmony_ci	int orig_stack_args_off;/* Offset of arguments placed on stack by the
206662306a36Sopenharmony_ci				 * func_addr's original caller
206762306a36Sopenharmony_ci				 */
206862306a36Sopenharmony_ci	int stack_size;		/* Trampoline stack size */
206962306a36Sopenharmony_ci	int backchain_off;	/* Offset of backchain */
207062306a36Sopenharmony_ci	int stack_args_off;	/* Offset of stack arguments for calling
207162306a36Sopenharmony_ci				 * func_addr, has to be at the top
207262306a36Sopenharmony_ci				 */
207362306a36Sopenharmony_ci	int reg_args_off;	/* Offset of register arguments for calling
207462306a36Sopenharmony_ci				 * func_addr
207562306a36Sopenharmony_ci				 */
207662306a36Sopenharmony_ci	int ip_off;		/* For bpf_get_func_ip(), has to be at
207762306a36Sopenharmony_ci				 * (ctx - 16)
207862306a36Sopenharmony_ci				 */
207962306a36Sopenharmony_ci	int arg_cnt_off;	/* For bpf_get_func_arg_cnt(), has to be at
208062306a36Sopenharmony_ci				 * (ctx - 8)
208162306a36Sopenharmony_ci				 */
208262306a36Sopenharmony_ci	int bpf_args_off;	/* Offset of BPF_PROG context, which consists
208362306a36Sopenharmony_ci				 * of BPF arguments followed by return value
208462306a36Sopenharmony_ci				 */
208562306a36Sopenharmony_ci	int retval_off;		/* Offset of return value (see above) */
208662306a36Sopenharmony_ci	int r7_r8_off;		/* Offset of saved %r7 and %r8, which are used
208762306a36Sopenharmony_ci				 * for __bpf_prog_enter() return value and
208862306a36Sopenharmony_ci				 * func_addr respectively
208962306a36Sopenharmony_ci				 */
209062306a36Sopenharmony_ci	int run_ctx_off;	/* Offset of struct bpf_tramp_run_ctx */
209162306a36Sopenharmony_ci	int tccnt_off;		/* Offset of saved tailcall counter */
209262306a36Sopenharmony_ci	int r14_off;		/* Offset of saved %r14, has to be at the
209362306a36Sopenharmony_ci				 * bottom */
209462306a36Sopenharmony_ci	int do_fexit;		/* do_fexit: label */
209562306a36Sopenharmony_ci};
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_cistatic void load_imm64(struct bpf_jit *jit, int dst_reg, u64 val)
209862306a36Sopenharmony_ci{
209962306a36Sopenharmony_ci	/* llihf %dst_reg,val_hi */
210062306a36Sopenharmony_ci	EMIT6_IMM(0xc00e0000, dst_reg, (val >> 32));
210162306a36Sopenharmony_ci	/* oilf %rdst_reg,val_lo */
210262306a36Sopenharmony_ci	EMIT6_IMM(0xc00d0000, dst_reg, val);
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_cistatic int invoke_bpf_prog(struct bpf_tramp_jit *tjit,
210662306a36Sopenharmony_ci			   const struct btf_func_model *m,
210762306a36Sopenharmony_ci			   struct bpf_tramp_link *tlink, bool save_ret)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	struct bpf_jit *jit = &tjit->common;
211062306a36Sopenharmony_ci	int cookie_off = tjit->run_ctx_off +
211162306a36Sopenharmony_ci			 offsetof(struct bpf_tramp_run_ctx, bpf_cookie);
211262306a36Sopenharmony_ci	struct bpf_prog *p = tlink->link.prog;
211362306a36Sopenharmony_ci	int patch;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	/*
211662306a36Sopenharmony_ci	 * run_ctx.cookie = tlink->cookie;
211762306a36Sopenharmony_ci	 */
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	/* %r0 = tlink->cookie */
212062306a36Sopenharmony_ci	load_imm64(jit, REG_W0, tlink->cookie);
212162306a36Sopenharmony_ci	/* stg %r0,cookie_off(%r15) */
212262306a36Sopenharmony_ci	EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, REG_0, REG_15, cookie_off);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/*
212562306a36Sopenharmony_ci	 * if ((start = __bpf_prog_enter(p, &run_ctx)) == 0)
212662306a36Sopenharmony_ci	 *         goto skip;
212762306a36Sopenharmony_ci	 */
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	/* %r1 = __bpf_prog_enter */
213062306a36Sopenharmony_ci	load_imm64(jit, REG_1, (u64)bpf_trampoline_enter(p));
213162306a36Sopenharmony_ci	/* %r2 = p */
213262306a36Sopenharmony_ci	load_imm64(jit, REG_2, (u64)p);
213362306a36Sopenharmony_ci	/* la %r3,run_ctx_off(%r15) */
213462306a36Sopenharmony_ci	EMIT4_DISP(0x41000000, REG_3, REG_15, tjit->run_ctx_off);
213562306a36Sopenharmony_ci	/* %r1() */
213662306a36Sopenharmony_ci	call_r1(jit);
213762306a36Sopenharmony_ci	/* ltgr %r7,%r2 */
213862306a36Sopenharmony_ci	EMIT4(0xb9020000, REG_7, REG_2);
213962306a36Sopenharmony_ci	/* brcl 8,skip */
214062306a36Sopenharmony_ci	patch = jit->prg;
214162306a36Sopenharmony_ci	EMIT6_PCREL_RILC(0xc0040000, 8, 0);
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	/*
214462306a36Sopenharmony_ci	 * retval = bpf_func(args, p->insnsi);
214562306a36Sopenharmony_ci	 */
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	/* %r1 = p->bpf_func */
214862306a36Sopenharmony_ci	load_imm64(jit, REG_1, (u64)p->bpf_func);
214962306a36Sopenharmony_ci	/* la %r2,bpf_args_off(%r15) */
215062306a36Sopenharmony_ci	EMIT4_DISP(0x41000000, REG_2, REG_15, tjit->bpf_args_off);
215162306a36Sopenharmony_ci	/* %r3 = p->insnsi */
215262306a36Sopenharmony_ci	if (!p->jited)
215362306a36Sopenharmony_ci		load_imm64(jit, REG_3, (u64)p->insnsi);
215462306a36Sopenharmony_ci	/* %r1() */
215562306a36Sopenharmony_ci	call_r1(jit);
215662306a36Sopenharmony_ci	/* stg %r2,retval_off(%r15) */
215762306a36Sopenharmony_ci	if (save_ret) {
215862306a36Sopenharmony_ci		if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags))
215962306a36Sopenharmony_ci			return -1;
216062306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15,
216162306a36Sopenharmony_ci			      tjit->retval_off);
216262306a36Sopenharmony_ci	}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/* skip: */
216562306a36Sopenharmony_ci	if (jit->prg_buf)
216662306a36Sopenharmony_ci		*(u32 *)&jit->prg_buf[patch + 2] = (jit->prg - patch) >> 1;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	/*
216962306a36Sopenharmony_ci	 * __bpf_prog_exit(p, start, &run_ctx);
217062306a36Sopenharmony_ci	 */
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	/* %r1 = __bpf_prog_exit */
217362306a36Sopenharmony_ci	load_imm64(jit, REG_1, (u64)bpf_trampoline_exit(p));
217462306a36Sopenharmony_ci	/* %r2 = p */
217562306a36Sopenharmony_ci	load_imm64(jit, REG_2, (u64)p);
217662306a36Sopenharmony_ci	/* lgr %r3,%r7 */
217762306a36Sopenharmony_ci	EMIT4(0xb9040000, REG_3, REG_7);
217862306a36Sopenharmony_ci	/* la %r4,run_ctx_off(%r15) */
217962306a36Sopenharmony_ci	EMIT4_DISP(0x41000000, REG_4, REG_15, tjit->run_ctx_off);
218062306a36Sopenharmony_ci	/* %r1() */
218162306a36Sopenharmony_ci	call_r1(jit);
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	return 0;
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_cistatic int alloc_stack(struct bpf_tramp_jit *tjit, size_t size)
218762306a36Sopenharmony_ci{
218862306a36Sopenharmony_ci	int stack_offset = tjit->stack_size;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	tjit->stack_size += size;
219162306a36Sopenharmony_ci	return stack_offset;
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci/* ABI uses %r2 - %r6 for parameter passing. */
219562306a36Sopenharmony_ci#define MAX_NR_REG_ARGS 5
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci/* The "L" field of the "mvc" instruction is 8 bits. */
219862306a36Sopenharmony_ci#define MAX_MVC_SIZE 256
219962306a36Sopenharmony_ci#define MAX_NR_STACK_ARGS (MAX_MVC_SIZE / sizeof(u64))
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci/* -mfentry generates a 6-byte nop on s390x. */
220262306a36Sopenharmony_ci#define S390X_PATCH_SIZE 6
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_cistatic int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
220562306a36Sopenharmony_ci					 struct bpf_tramp_jit *tjit,
220662306a36Sopenharmony_ci					 const struct btf_func_model *m,
220762306a36Sopenharmony_ci					 u32 flags,
220862306a36Sopenharmony_ci					 struct bpf_tramp_links *tlinks,
220962306a36Sopenharmony_ci					 void *func_addr)
221062306a36Sopenharmony_ci{
221162306a36Sopenharmony_ci	struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
221262306a36Sopenharmony_ci	struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
221362306a36Sopenharmony_ci	struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
221462306a36Sopenharmony_ci	int nr_bpf_args, nr_reg_args, nr_stack_args;
221562306a36Sopenharmony_ci	struct bpf_jit *jit = &tjit->common;
221662306a36Sopenharmony_ci	int arg, bpf_arg_off;
221762306a36Sopenharmony_ci	int i, j;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* Support as many stack arguments as "mvc" instruction can handle. */
222062306a36Sopenharmony_ci	nr_reg_args = min_t(int, m->nr_args, MAX_NR_REG_ARGS);
222162306a36Sopenharmony_ci	nr_stack_args = m->nr_args - nr_reg_args;
222262306a36Sopenharmony_ci	if (nr_stack_args > MAX_NR_STACK_ARGS)
222362306a36Sopenharmony_ci		return -ENOTSUPP;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	/* Return to %r14, since func_addr and %r0 are not available. */
222662306a36Sopenharmony_ci	if (!func_addr && !(flags & BPF_TRAMP_F_ORIG_STACK))
222762306a36Sopenharmony_ci		flags |= BPF_TRAMP_F_SKIP_FRAME;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	/*
223062306a36Sopenharmony_ci	 * Compute how many arguments we need to pass to BPF programs.
223162306a36Sopenharmony_ci	 * BPF ABI mirrors that of x86_64: arguments that are 16 bytes or
223262306a36Sopenharmony_ci	 * smaller are packed into 1 or 2 registers; larger arguments are
223362306a36Sopenharmony_ci	 * passed via pointers.
223462306a36Sopenharmony_ci	 * In s390x ABI, arguments that are 8 bytes or smaller are packed into
223562306a36Sopenharmony_ci	 * a register; larger arguments are passed via pointers.
223662306a36Sopenharmony_ci	 * We need to deal with this difference.
223762306a36Sopenharmony_ci	 */
223862306a36Sopenharmony_ci	nr_bpf_args = 0;
223962306a36Sopenharmony_ci	for (i = 0; i < m->nr_args; i++) {
224062306a36Sopenharmony_ci		if (m->arg_size[i] <= 8)
224162306a36Sopenharmony_ci			nr_bpf_args += 1;
224262306a36Sopenharmony_ci		else if (m->arg_size[i] <= 16)
224362306a36Sopenharmony_ci			nr_bpf_args += 2;
224462306a36Sopenharmony_ci		else
224562306a36Sopenharmony_ci			return -ENOTSUPP;
224662306a36Sopenharmony_ci	}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	/*
224962306a36Sopenharmony_ci	 * Calculate the stack layout.
225062306a36Sopenharmony_ci	 */
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	/*
225362306a36Sopenharmony_ci	 * Allocate STACK_FRAME_OVERHEAD bytes for the callees. As the s390x
225462306a36Sopenharmony_ci	 * ABI requires, put our backchain at the end of the allocated memory.
225562306a36Sopenharmony_ci	 */
225662306a36Sopenharmony_ci	tjit->stack_size = STACK_FRAME_OVERHEAD;
225762306a36Sopenharmony_ci	tjit->backchain_off = tjit->stack_size - sizeof(u64);
225862306a36Sopenharmony_ci	tjit->stack_args_off = alloc_stack(tjit, nr_stack_args * sizeof(u64));
225962306a36Sopenharmony_ci	tjit->reg_args_off = alloc_stack(tjit, nr_reg_args * sizeof(u64));
226062306a36Sopenharmony_ci	tjit->ip_off = alloc_stack(tjit, sizeof(u64));
226162306a36Sopenharmony_ci	tjit->arg_cnt_off = alloc_stack(tjit, sizeof(u64));
226262306a36Sopenharmony_ci	tjit->bpf_args_off = alloc_stack(tjit, nr_bpf_args * sizeof(u64));
226362306a36Sopenharmony_ci	tjit->retval_off = alloc_stack(tjit, sizeof(u64));
226462306a36Sopenharmony_ci	tjit->r7_r8_off = alloc_stack(tjit, 2 * sizeof(u64));
226562306a36Sopenharmony_ci	tjit->run_ctx_off = alloc_stack(tjit,
226662306a36Sopenharmony_ci					sizeof(struct bpf_tramp_run_ctx));
226762306a36Sopenharmony_ci	tjit->tccnt_off = alloc_stack(tjit, sizeof(u64));
226862306a36Sopenharmony_ci	tjit->r14_off = alloc_stack(tjit, sizeof(u64) * 2);
226962306a36Sopenharmony_ci	/*
227062306a36Sopenharmony_ci	 * In accordance with the s390x ABI, the caller has allocated
227162306a36Sopenharmony_ci	 * STACK_FRAME_OVERHEAD bytes for us. 8 of them contain the caller's
227262306a36Sopenharmony_ci	 * backchain, and the rest we can use.
227362306a36Sopenharmony_ci	 */
227462306a36Sopenharmony_ci	tjit->stack_size -= STACK_FRAME_OVERHEAD - sizeof(u64);
227562306a36Sopenharmony_ci	tjit->orig_stack_args_off = tjit->stack_size + STACK_FRAME_OVERHEAD;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	/* lgr %r1,%r15 */
227862306a36Sopenharmony_ci	EMIT4(0xb9040000, REG_1, REG_15);
227962306a36Sopenharmony_ci	/* aghi %r15,-stack_size */
228062306a36Sopenharmony_ci	EMIT4_IMM(0xa70b0000, REG_15, -tjit->stack_size);
228162306a36Sopenharmony_ci	/* stg %r1,backchain_off(%r15) */
228262306a36Sopenharmony_ci	EMIT6_DISP_LH(0xe3000000, 0x0024, REG_1, REG_0, REG_15,
228362306a36Sopenharmony_ci		      tjit->backchain_off);
228462306a36Sopenharmony_ci	/* mvc tccnt_off(4,%r15),stack_size+STK_OFF_TCCNT(%r15) */
228562306a36Sopenharmony_ci	_EMIT6(0xd203f000 | tjit->tccnt_off,
228662306a36Sopenharmony_ci	       0xf000 | (tjit->stack_size + STK_OFF_TCCNT));
228762306a36Sopenharmony_ci	/* stmg %r2,%rN,fwd_reg_args_off(%r15) */
228862306a36Sopenharmony_ci	if (nr_reg_args)
228962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x0024, REG_2,
229062306a36Sopenharmony_ci			      REG_2 + (nr_reg_args - 1), REG_15,
229162306a36Sopenharmony_ci			      tjit->reg_args_off);
229262306a36Sopenharmony_ci	for (i = 0, j = 0; i < m->nr_args; i++) {
229362306a36Sopenharmony_ci		if (i < MAX_NR_REG_ARGS)
229462306a36Sopenharmony_ci			arg = REG_2 + i;
229562306a36Sopenharmony_ci		else
229662306a36Sopenharmony_ci			arg = tjit->orig_stack_args_off +
229762306a36Sopenharmony_ci			      (i - MAX_NR_REG_ARGS) * sizeof(u64);
229862306a36Sopenharmony_ci		bpf_arg_off = tjit->bpf_args_off + j * sizeof(u64);
229962306a36Sopenharmony_ci		if (m->arg_size[i] <= 8) {
230062306a36Sopenharmony_ci			if (i < MAX_NR_REG_ARGS)
230162306a36Sopenharmony_ci				/* stg %arg,bpf_arg_off(%r15) */
230262306a36Sopenharmony_ci				EMIT6_DISP_LH(0xe3000000, 0x0024, arg,
230362306a36Sopenharmony_ci					      REG_0, REG_15, bpf_arg_off);
230462306a36Sopenharmony_ci			else
230562306a36Sopenharmony_ci				/* mvc bpf_arg_off(8,%r15),arg(%r15) */
230662306a36Sopenharmony_ci				_EMIT6(0xd207f000 | bpf_arg_off,
230762306a36Sopenharmony_ci				       0xf000 | arg);
230862306a36Sopenharmony_ci			j += 1;
230962306a36Sopenharmony_ci		} else {
231062306a36Sopenharmony_ci			if (i < MAX_NR_REG_ARGS) {
231162306a36Sopenharmony_ci				/* mvc bpf_arg_off(16,%r15),0(%arg) */
231262306a36Sopenharmony_ci				_EMIT6(0xd20ff000 | bpf_arg_off,
231362306a36Sopenharmony_ci				       reg2hex[arg] << 12);
231462306a36Sopenharmony_ci			} else {
231562306a36Sopenharmony_ci				/* lg %r1,arg(%r15) */
231662306a36Sopenharmony_ci				EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, REG_0,
231762306a36Sopenharmony_ci					      REG_15, arg);
231862306a36Sopenharmony_ci				/* mvc bpf_arg_off(16,%r15),0(%r1) */
231962306a36Sopenharmony_ci				_EMIT6(0xd20ff000 | bpf_arg_off, 0x1000);
232062306a36Sopenharmony_ci			}
232162306a36Sopenharmony_ci			j += 2;
232262306a36Sopenharmony_ci		}
232362306a36Sopenharmony_ci	}
232462306a36Sopenharmony_ci	/* stmg %r7,%r8,r7_r8_off(%r15) */
232562306a36Sopenharmony_ci	EMIT6_DISP_LH(0xeb000000, 0x0024, REG_7, REG_8, REG_15,
232662306a36Sopenharmony_ci		      tjit->r7_r8_off);
232762306a36Sopenharmony_ci	/* stg %r14,r14_off(%r15) */
232862306a36Sopenharmony_ci	EMIT6_DISP_LH(0xe3000000, 0x0024, REG_14, REG_0, REG_15, tjit->r14_off);
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (flags & BPF_TRAMP_F_ORIG_STACK) {
233162306a36Sopenharmony_ci		/*
233262306a36Sopenharmony_ci		 * The ftrace trampoline puts the return address (which is the
233362306a36Sopenharmony_ci		 * address of the original function + S390X_PATCH_SIZE) into
233462306a36Sopenharmony_ci		 * %r0; see ftrace_shared_hotpatch_trampoline_br and
233562306a36Sopenharmony_ci		 * ftrace_init_nop() for details.
233662306a36Sopenharmony_ci		 */
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci		/* lgr %r8,%r0 */
233962306a36Sopenharmony_ci		EMIT4(0xb9040000, REG_8, REG_0);
234062306a36Sopenharmony_ci	} else {
234162306a36Sopenharmony_ci		/* %r8 = func_addr + S390X_PATCH_SIZE */
234262306a36Sopenharmony_ci		load_imm64(jit, REG_8, (u64)func_addr + S390X_PATCH_SIZE);
234362306a36Sopenharmony_ci	}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	/*
234662306a36Sopenharmony_ci	 * ip = func_addr;
234762306a36Sopenharmony_ci	 * arg_cnt = m->nr_args;
234862306a36Sopenharmony_ci	 */
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	if (flags & BPF_TRAMP_F_IP_ARG) {
235162306a36Sopenharmony_ci		/* %r0 = func_addr */
235262306a36Sopenharmony_ci		load_imm64(jit, REG_0, (u64)func_addr);
235362306a36Sopenharmony_ci		/* stg %r0,ip_off(%r15) */
235462306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0024, REG_0, REG_0, REG_15,
235562306a36Sopenharmony_ci			      tjit->ip_off);
235662306a36Sopenharmony_ci	}
235762306a36Sopenharmony_ci	/* lghi %r0,nr_bpf_args */
235862306a36Sopenharmony_ci	EMIT4_IMM(0xa7090000, REG_0, nr_bpf_args);
235962306a36Sopenharmony_ci	/* stg %r0,arg_cnt_off(%r15) */
236062306a36Sopenharmony_ci	EMIT6_DISP_LH(0xe3000000, 0x0024, REG_0, REG_0, REG_15,
236162306a36Sopenharmony_ci		      tjit->arg_cnt_off);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (flags & BPF_TRAMP_F_CALL_ORIG) {
236462306a36Sopenharmony_ci		/*
236562306a36Sopenharmony_ci		 * __bpf_tramp_enter(im);
236662306a36Sopenharmony_ci		 */
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci		/* %r1 = __bpf_tramp_enter */
236962306a36Sopenharmony_ci		load_imm64(jit, REG_1, (u64)__bpf_tramp_enter);
237062306a36Sopenharmony_ci		/* %r2 = im */
237162306a36Sopenharmony_ci		load_imm64(jit, REG_2, (u64)im);
237262306a36Sopenharmony_ci		/* %r1() */
237362306a36Sopenharmony_ci		call_r1(jit);
237462306a36Sopenharmony_ci	}
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	for (i = 0; i < fentry->nr_links; i++)
237762306a36Sopenharmony_ci		if (invoke_bpf_prog(tjit, m, fentry->links[i],
237862306a36Sopenharmony_ci				    flags & BPF_TRAMP_F_RET_FENTRY_RET))
237962306a36Sopenharmony_ci			return -EINVAL;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	if (fmod_ret->nr_links) {
238262306a36Sopenharmony_ci		/*
238362306a36Sopenharmony_ci		 * retval = 0;
238462306a36Sopenharmony_ci		 */
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci		/* xc retval_off(8,%r15),retval_off(%r15) */
238762306a36Sopenharmony_ci		_EMIT6(0xd707f000 | tjit->retval_off,
238862306a36Sopenharmony_ci		       0xf000 | tjit->retval_off);
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci		for (i = 0; i < fmod_ret->nr_links; i++) {
239162306a36Sopenharmony_ci			if (invoke_bpf_prog(tjit, m, fmod_ret->links[i], true))
239262306a36Sopenharmony_ci				return -EINVAL;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci			/*
239562306a36Sopenharmony_ci			 * if (retval)
239662306a36Sopenharmony_ci			 *         goto do_fexit;
239762306a36Sopenharmony_ci			 */
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci			/* ltg %r0,retval_off(%r15) */
240062306a36Sopenharmony_ci			EMIT6_DISP_LH(0xe3000000, 0x0002, REG_0, REG_0, REG_15,
240162306a36Sopenharmony_ci				      tjit->retval_off);
240262306a36Sopenharmony_ci			/* brcl 7,do_fexit */
240362306a36Sopenharmony_ci			EMIT6_PCREL_RILC(0xc0040000, 7, tjit->do_fexit);
240462306a36Sopenharmony_ci		}
240562306a36Sopenharmony_ci	}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	if (flags & BPF_TRAMP_F_CALL_ORIG) {
240862306a36Sopenharmony_ci		/*
240962306a36Sopenharmony_ci		 * retval = func_addr(args);
241062306a36Sopenharmony_ci		 */
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci		/* lmg %r2,%rN,reg_args_off(%r15) */
241362306a36Sopenharmony_ci		if (nr_reg_args)
241462306a36Sopenharmony_ci			EMIT6_DISP_LH(0xeb000000, 0x0004, REG_2,
241562306a36Sopenharmony_ci				      REG_2 + (nr_reg_args - 1), REG_15,
241662306a36Sopenharmony_ci				      tjit->reg_args_off);
241762306a36Sopenharmony_ci		/* mvc stack_args_off(N,%r15),orig_stack_args_off(%r15) */
241862306a36Sopenharmony_ci		if (nr_stack_args)
241962306a36Sopenharmony_ci			_EMIT6(0xd200f000 |
242062306a36Sopenharmony_ci				       (nr_stack_args * sizeof(u64) - 1) << 16 |
242162306a36Sopenharmony_ci				       tjit->stack_args_off,
242262306a36Sopenharmony_ci			       0xf000 | tjit->orig_stack_args_off);
242362306a36Sopenharmony_ci		/* mvc STK_OFF_TCCNT(4,%r15),tccnt_off(%r15) */
242462306a36Sopenharmony_ci		_EMIT6(0xd203f000 | STK_OFF_TCCNT, 0xf000 | tjit->tccnt_off);
242562306a36Sopenharmony_ci		/* lgr %r1,%r8 */
242662306a36Sopenharmony_ci		EMIT4(0xb9040000, REG_1, REG_8);
242762306a36Sopenharmony_ci		/* %r1() */
242862306a36Sopenharmony_ci		call_r1(jit);
242962306a36Sopenharmony_ci		/* stg %r2,retval_off(%r15) */
243062306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15,
243162306a36Sopenharmony_ci			      tjit->retval_off);
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci		im->ip_after_call = jit->prg_buf + jit->prg;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci		/*
243662306a36Sopenharmony_ci		 * The following nop will be patched by bpf_tramp_image_put().
243762306a36Sopenharmony_ci		 */
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci		/* brcl 0,im->ip_epilogue */
244062306a36Sopenharmony_ci		EMIT6_PCREL_RILC(0xc0040000, 0, (u64)im->ip_epilogue);
244162306a36Sopenharmony_ci	}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	/* do_fexit: */
244462306a36Sopenharmony_ci	tjit->do_fexit = jit->prg;
244562306a36Sopenharmony_ci	for (i = 0; i < fexit->nr_links; i++)
244662306a36Sopenharmony_ci		if (invoke_bpf_prog(tjit, m, fexit->links[i], false))
244762306a36Sopenharmony_ci			return -EINVAL;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	if (flags & BPF_TRAMP_F_CALL_ORIG) {
245062306a36Sopenharmony_ci		im->ip_epilogue = jit->prg_buf + jit->prg;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci		/*
245362306a36Sopenharmony_ci		 * __bpf_tramp_exit(im);
245462306a36Sopenharmony_ci		 */
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci		/* %r1 = __bpf_tramp_exit */
245762306a36Sopenharmony_ci		load_imm64(jit, REG_1, (u64)__bpf_tramp_exit);
245862306a36Sopenharmony_ci		/* %r2 = im */
245962306a36Sopenharmony_ci		load_imm64(jit, REG_2, (u64)im);
246062306a36Sopenharmony_ci		/* %r1() */
246162306a36Sopenharmony_ci		call_r1(jit);
246262306a36Sopenharmony_ci	}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	/* lmg %r2,%rN,reg_args_off(%r15) */
246562306a36Sopenharmony_ci	if ((flags & BPF_TRAMP_F_RESTORE_REGS) && nr_reg_args)
246662306a36Sopenharmony_ci		EMIT6_DISP_LH(0xeb000000, 0x0004, REG_2,
246762306a36Sopenharmony_ci			      REG_2 + (nr_reg_args - 1), REG_15,
246862306a36Sopenharmony_ci			      tjit->reg_args_off);
246962306a36Sopenharmony_ci	/* lgr %r1,%r8 */
247062306a36Sopenharmony_ci	if (!(flags & BPF_TRAMP_F_SKIP_FRAME))
247162306a36Sopenharmony_ci		EMIT4(0xb9040000, REG_1, REG_8);
247262306a36Sopenharmony_ci	/* lmg %r7,%r8,r7_r8_off(%r15) */
247362306a36Sopenharmony_ci	EMIT6_DISP_LH(0xeb000000, 0x0004, REG_7, REG_8, REG_15,
247462306a36Sopenharmony_ci		      tjit->r7_r8_off);
247562306a36Sopenharmony_ci	/* lg %r14,r14_off(%r15) */
247662306a36Sopenharmony_ci	EMIT6_DISP_LH(0xe3000000, 0x0004, REG_14, REG_0, REG_15, tjit->r14_off);
247762306a36Sopenharmony_ci	/* lg %r2,retval_off(%r15) */
247862306a36Sopenharmony_ci	if (flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET))
247962306a36Sopenharmony_ci		EMIT6_DISP_LH(0xe3000000, 0x0004, REG_2, REG_0, REG_15,
248062306a36Sopenharmony_ci			      tjit->retval_off);
248162306a36Sopenharmony_ci	/* mvc stack_size+STK_OFF_TCCNT(4,%r15),tccnt_off(%r15) */
248262306a36Sopenharmony_ci	_EMIT6(0xd203f000 | (tjit->stack_size + STK_OFF_TCCNT),
248362306a36Sopenharmony_ci	       0xf000 | tjit->tccnt_off);
248462306a36Sopenharmony_ci	/* aghi %r15,stack_size */
248562306a36Sopenharmony_ci	EMIT4_IMM(0xa70b0000, REG_15, tjit->stack_size);
248662306a36Sopenharmony_ci	/* Emit an expoline for the following indirect jump. */
248762306a36Sopenharmony_ci	if (nospec_uses_trampoline())
248862306a36Sopenharmony_ci		emit_expoline(jit);
248962306a36Sopenharmony_ci	if (flags & BPF_TRAMP_F_SKIP_FRAME)
249062306a36Sopenharmony_ci		/* br %r14 */
249162306a36Sopenharmony_ci		_EMIT2(0x07fe);
249262306a36Sopenharmony_ci	else
249362306a36Sopenharmony_ci		/* br %r1 */
249462306a36Sopenharmony_ci		_EMIT2(0x07f1);
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	emit_r1_thunk(jit);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	return 0;
249962306a36Sopenharmony_ci}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ciint arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
250262306a36Sopenharmony_ci				void *image_end, const struct btf_func_model *m,
250362306a36Sopenharmony_ci				u32 flags, struct bpf_tramp_links *tlinks,
250462306a36Sopenharmony_ci				void *func_addr)
250562306a36Sopenharmony_ci{
250662306a36Sopenharmony_ci	struct bpf_tramp_jit tjit;
250762306a36Sopenharmony_ci	int ret;
250862306a36Sopenharmony_ci	int i;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
251162306a36Sopenharmony_ci		if (i == 0) {
251262306a36Sopenharmony_ci			/* Compute offsets, check whether the code fits. */
251362306a36Sopenharmony_ci			memset(&tjit, 0, sizeof(tjit));
251462306a36Sopenharmony_ci		} else {
251562306a36Sopenharmony_ci			/* Generate the code. */
251662306a36Sopenharmony_ci			tjit.common.prg = 0;
251762306a36Sopenharmony_ci			tjit.common.prg_buf = image;
251862306a36Sopenharmony_ci		}
251962306a36Sopenharmony_ci		ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags,
252062306a36Sopenharmony_ci						    tlinks, func_addr);
252162306a36Sopenharmony_ci		if (ret < 0)
252262306a36Sopenharmony_ci			return ret;
252362306a36Sopenharmony_ci		if (tjit.common.prg > (char *)image_end - (char *)image)
252462306a36Sopenharmony_ci			/*
252562306a36Sopenharmony_ci			 * Use the same error code as for exceeding
252662306a36Sopenharmony_ci			 * BPF_MAX_TRAMP_LINKS.
252762306a36Sopenharmony_ci			 */
252862306a36Sopenharmony_ci			return -E2BIG;
252962306a36Sopenharmony_ci	}
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	return tjit.common.prg;
253262306a36Sopenharmony_ci}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_cibool bpf_jit_supports_subprog_tailcalls(void)
253562306a36Sopenharmony_ci{
253662306a36Sopenharmony_ci	return true;
253762306a36Sopenharmony_ci}
2538