18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * bpf_jit32.h: BPF JIT compiler for PPC
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Split from bpf_jit.h
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#ifndef _BPF_JIT32_H
108c2ecf20Sopenharmony_ci#define _BPF_JIT32_H
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <asm/asm-compat.h>
138c2ecf20Sopenharmony_ci#include "bpf_jit.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
168c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_R3_OFF	48
178c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_LOCALS	32
188c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_BASIC	(48+64)
198c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_SAVE	(18*8)
208c2ecf20Sopenharmony_ci#define BPF_PPC_STACKFRAME	(BPF_PPC_STACK_BASIC+BPF_PPC_STACK_LOCALS+ \
218c2ecf20Sopenharmony_ci				 BPF_PPC_STACK_SAVE)
228c2ecf20Sopenharmony_ci#define BPF_PPC_SLOWPATH_FRAME	(48+64)
238c2ecf20Sopenharmony_ci#else
248c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_R3_OFF	24
258c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_LOCALS	16
268c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_BASIC	(24+32)
278c2ecf20Sopenharmony_ci#define BPF_PPC_STACK_SAVE	(18*4)
288c2ecf20Sopenharmony_ci#define BPF_PPC_STACKFRAME	(BPF_PPC_STACK_BASIC+BPF_PPC_STACK_LOCALS+ \
298c2ecf20Sopenharmony_ci				 BPF_PPC_STACK_SAVE)
308c2ecf20Sopenharmony_ci#define BPF_PPC_SLOWPATH_FRAME	(24+32)
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define REG_SZ         (BITS_PER_LONG/8)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/*
368c2ecf20Sopenharmony_ci * Generated code register usage:
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * As normal PPC C ABI (e.g. r1=sp, r2=TOC), with:
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * skb		r3	(Entry parameter)
418c2ecf20Sopenharmony_ci * A register	r4
428c2ecf20Sopenharmony_ci * X register	r5
438c2ecf20Sopenharmony_ci * addr param	r6
448c2ecf20Sopenharmony_ci * r7-r10	scratch
458c2ecf20Sopenharmony_ci * skb->data	r14
468c2ecf20Sopenharmony_ci * skb headlen	r15	(skb->len - skb->data_len)
478c2ecf20Sopenharmony_ci * m[0]		r16
488c2ecf20Sopenharmony_ci * m[...]	...
498c2ecf20Sopenharmony_ci * m[15]	r31
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci#define r_skb		3
528c2ecf20Sopenharmony_ci#define r_ret		3
538c2ecf20Sopenharmony_ci#define r_A		4
548c2ecf20Sopenharmony_ci#define r_X		5
558c2ecf20Sopenharmony_ci#define r_addr		6
568c2ecf20Sopenharmony_ci#define r_scratch1	7
578c2ecf20Sopenharmony_ci#define r_scratch2	8
588c2ecf20Sopenharmony_ci#define r_D		14
598c2ecf20Sopenharmony_ci#define r_HL		15
608c2ecf20Sopenharmony_ci#define r_M		16
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * Assembly helpers from arch/powerpc/net/bpf_jit.S:
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_ci#define DECLARE_LOAD_FUNC(func)	\
688c2ecf20Sopenharmony_ci	extern u8 func[], func##_negative_offset[], func##_positive_offset[]
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciDECLARE_LOAD_FUNC(sk_load_word);
718c2ecf20Sopenharmony_ciDECLARE_LOAD_FUNC(sk_load_half);
728c2ecf20Sopenharmony_ciDECLARE_LOAD_FUNC(sk_load_byte);
738c2ecf20Sopenharmony_ciDECLARE_LOAD_FUNC(sk_load_byte_msh);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define PPC_LBZ_OFFS(r, base, i) do { if ((i) < 32768) EMIT(PPC_RAW_LBZ(r, base, i));   \
768c2ecf20Sopenharmony_ci		else {	EMIT(PPC_RAW_ADDIS(r, base, IMM_HA(i)));	      \
778c2ecf20Sopenharmony_ci			EMIT(PPC_RAW_LBZ(r, r, IMM_L(i))); } } while(0)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) EMIT(PPC_RAW_LD(r, base, i));     \
808c2ecf20Sopenharmony_ci		else {	EMIT(PPC_RAW_ADDIS(r, base, IMM_HA(i)));			\
818c2ecf20Sopenharmony_ci			EMIT(PPC_RAW_LD(r, r, IMM_L(i))); } } while(0)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define PPC_LWZ_OFFS(r, base, i) do { if ((i) < 32768) EMIT(PPC_RAW_LWZ(r, base, i));   \
848c2ecf20Sopenharmony_ci		else {	EMIT(PPC_RAW_ADDIS(r, base, IMM_HA(i)));			\
858c2ecf20Sopenharmony_ci			EMIT(PPC_RAW_LWZ(r, r, IMM_L(i))); } } while(0)
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define PPC_LHZ_OFFS(r, base, i) do { if ((i) < 32768) EMIT(PPC_RAW_LHZ(r, base, i));   \
888c2ecf20Sopenharmony_ci		else {	EMIT(PPC_RAW_ADDIS(r, base, IMM_HA(i)));			\
898c2ecf20Sopenharmony_ci			EMIT(PPC_RAW_LHZ(r, r, IMM_L(i))); } } while(0)
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
928c2ecf20Sopenharmony_ci#define PPC_LL_OFFS(r, base, i) do { PPC_LD_OFFS(r, base, i); } while(0)
938c2ecf20Sopenharmony_ci#else
948c2ecf20Sopenharmony_ci#define PPC_LL_OFFS(r, base, i) do { PPC_LWZ_OFFS(r, base, i); } while(0)
958c2ecf20Sopenharmony_ci#endif
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
988c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
998c2ecf20Sopenharmony_ci#define PPC_BPF_LOAD_CPU(r)		\
1008c2ecf20Sopenharmony_ci	do { BUILD_BUG_ON(sizeof_field(struct paca_struct, paca_index) != 2);	\
1018c2ecf20Sopenharmony_ci		PPC_LHZ_OFFS(r, 13, offsetof(struct paca_struct, paca_index));	\
1028c2ecf20Sopenharmony_ci	} while (0)
1038c2ecf20Sopenharmony_ci#else
1048c2ecf20Sopenharmony_ci#define PPC_BPF_LOAD_CPU(r)     \
1058c2ecf20Sopenharmony_ci	do { BUILD_BUG_ON(sizeof_field(struct task_struct, cpu) != 4);		\
1068c2ecf20Sopenharmony_ci		PPC_LHZ_OFFS(r, 2, offsetof(struct task_struct, cpu));		\
1078c2ecf20Sopenharmony_ci	} while(0)
1088c2ecf20Sopenharmony_ci#endif
1098c2ecf20Sopenharmony_ci#else
1108c2ecf20Sopenharmony_ci#define PPC_BPF_LOAD_CPU(r) do { EMIT(PPC_RAW_LI(r, 0)); } while(0)
1118c2ecf20Sopenharmony_ci#endif
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#define PPC_LHBRX_OFFS(r, base, i) \
1148c2ecf20Sopenharmony_ci		do { PPC_LI32(r, i); EMIT(PPC_RAW_LHBRX(r, r, base)); } while(0)
1158c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
1168c2ecf20Sopenharmony_ci#define PPC_NTOHS_OFFS(r, base, i)	PPC_LHBRX_OFFS(r, base, i)
1178c2ecf20Sopenharmony_ci#else
1188c2ecf20Sopenharmony_ci#define PPC_NTOHS_OFFS(r, base, i)	PPC_LHZ_OFFS(r, base, i)
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define PPC_BPF_LL(r, base, i) do { EMIT(PPC_RAW_LWZ(r, base, i)); } while(0)
1228c2ecf20Sopenharmony_ci#define PPC_BPF_STL(r, base, i) do { EMIT(PPC_RAW_STW(r, base, i)); } while(0)
1238c2ecf20Sopenharmony_ci#define PPC_BPF_STLU(r, base, i) do { EMIT(PPC_RAW_STWU(r, base, i)); } while(0)
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define SEEN_DATAREF 0x10000 /* might call external helpers */
1268c2ecf20Sopenharmony_ci#define SEEN_XREG    0x20000 /* X reg is used */
1278c2ecf20Sopenharmony_ci#define SEEN_MEM     0x40000 /* SEEN_MEM+(1<<n) = use mem[n] for temporary
1288c2ecf20Sopenharmony_ci			      * storage */
1298c2ecf20Sopenharmony_ci#define SEEN_MEM_MSK 0x0ffff
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistruct codegen_context {
1328c2ecf20Sopenharmony_ci	unsigned int seen;
1338c2ecf20Sopenharmony_ci	unsigned int idx;
1348c2ecf20Sopenharmony_ci	int pc_ret0; /* bpf index of first RET #0 instruction (if any) */
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#endif
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#endif
140