Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/net/bpf_jit.h
51375 views
1
/* SPDX-License-Identifier: GPL-2.0-only */
2
/*
3
* bpf_jit.h: BPF JIT compiler for PPC
4
*
5
* Copyright 2011 Matt Evans <[email protected]>, IBM Corporation
6
* 2016 Naveen N. Rao <[email protected]>
7
*/
8
#ifndef _BPF_JIT_H
9
#define _BPF_JIT_H
10
11
#ifndef __ASSEMBLER__
12
13
#include <asm/types.h>
14
#include <asm/ppc-opcode.h>
15
#include <linux/build_bug.h>
16
17
#ifdef CONFIG_PPC64_ELF_ABI_V1
18
#define FUNCTION_DESCR_SIZE 24
19
#else
20
#define FUNCTION_DESCR_SIZE 0
21
#endif
22
23
#define CTX_NIA(ctx) ((unsigned long)ctx->idx * 4)
24
25
#define SZL sizeof(unsigned long)
26
#define BPF_INSN_SAFETY 64
27
#define BPF_PPC_TAILCALL 8
28
29
#define PLANT_INSTR(d, idx, instr) \
30
do { if (d) { (d)[idx] = instr; } idx++; } while (0)
31
#define EMIT(instr) PLANT_INSTR(image, ctx->idx, instr)
32
33
/* Long jump; (unconditional 'branch') */
34
#define PPC_JMP(dest) \
35
do { \
36
long offset = (long)(dest) - CTX_NIA(ctx); \
37
if ((dest) != 0 && !is_offset_in_branch_range(offset)) { \
38
pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \
39
return -ERANGE; \
40
} \
41
EMIT(PPC_RAW_BRANCH(offset)); \
42
} while (0)
43
44
/* "cond" here covers BO:BI fields. */
45
#define PPC_BCC_SHORT(cond, dest) \
46
do { \
47
long offset = (long)(dest) - CTX_NIA(ctx); \
48
if ((dest) != 0 && !is_offset_in_cond_branch_range(offset)) { \
49
pr_err_ratelimited("Conditional branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \
50
return -ERANGE; \
51
} \
52
EMIT(PPC_INST_BRANCH_COND | (((cond) & 0x3ff) << 16) | (offset & 0xfffc)); \
53
} while (0)
54
55
/* When constant jump offset is known prior */
56
#define PPC_BCC_CONST_SHORT(cond, offset) \
57
do { \
58
BUILD_BUG_ON(offset < -0x8000 || offset > 0x7fff || (offset & 0x3)); \
59
EMIT(PPC_INST_BRANCH_COND | (((cond) & 0x3ff) << 16) | (offset & 0xfffc)); \
60
} while (0)
61
62
/*
63
* Sign-extended 32-bit immediate load
64
*
65
* If this is a dummy pass (!image), account for
66
* maximum possible instructions.
67
*/
68
#define PPC_LI32(d, i) do { \
69
if (!image) \
70
ctx->idx += 2; \
71
else { \
72
if ((int)(uintptr_t)(i) >= -32768 && \
73
(int)(uintptr_t)(i) < 32768) \
74
EMIT(PPC_RAW_LI(d, i)); \
75
else { \
76
EMIT(PPC_RAW_LIS(d, IMM_H(i))); \
77
if (IMM_L(i)) \
78
EMIT(PPC_RAW_ORI(d, d, IMM_L(i))); \
79
} \
80
} } while (0)
81
82
#ifdef CONFIG_PPC64
83
84
/* for gpr non volatile registers BPG_REG_6 to 10 */
85
#define BPF_PPC_STACK_SAVE (6 * 8)
86
87
/* If dummy pass (!image), account for maximum possible instructions */
88
#define PPC_LI64(d, i) do { \
89
if (!image) \
90
ctx->idx += 5; \
91
else { \
92
if ((long)(i) >= -2147483648 && \
93
(long)(i) < 2147483648) \
94
PPC_LI32(d, i); \
95
else { \
96
if (!((uintptr_t)(i) & 0xffff800000000000ULL)) \
97
EMIT(PPC_RAW_LI(d, ((uintptr_t)(i) >> 32) & \
98
0xffff)); \
99
else { \
100
EMIT(PPC_RAW_LIS(d, ((uintptr_t)(i) >> 48))); \
101
if ((uintptr_t)(i) & 0x0000ffff00000000ULL) \
102
EMIT(PPC_RAW_ORI(d, d, \
103
((uintptr_t)(i) >> 32) & 0xffff)); \
104
} \
105
EMIT(PPC_RAW_SLDI(d, d, 32)); \
106
if ((uintptr_t)(i) & 0x00000000ffff0000ULL) \
107
EMIT(PPC_RAW_ORIS(d, d, \
108
((uintptr_t)(i) >> 16) & 0xffff)); \
109
if ((uintptr_t)(i) & 0x000000000000ffffULL) \
110
EMIT(PPC_RAW_ORI(d, d, (uintptr_t)(i) & \
111
0xffff)); \
112
} \
113
} } while (0)
114
#define PPC_LI_ADDR PPC_LI64
115
116
#ifndef CONFIG_PPC_KERNEL_PCREL
117
#define PPC64_LOAD_PACA() \
118
EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc)))
119
#else
120
#define PPC64_LOAD_PACA() do {} while (0)
121
#endif
122
#else
123
#define PPC_LI64(d, i) BUILD_BUG()
124
#define PPC_LI_ADDR PPC_LI32
125
#define PPC64_LOAD_PACA() BUILD_BUG()
126
#endif
127
128
/*
129
* The fly in the ointment of code size changing from pass to pass is
130
* avoided by padding the short branch case with a NOP. If code size differs
131
* with different branch reaches we will have the issue of code moving from
132
* one pass to the next and will need a few passes to converge on a stable
133
* state.
134
*/
135
#define PPC_BCC(cond, dest) do { \
136
if (is_offset_in_cond_branch_range((long)(dest) - CTX_NIA(ctx))) { \
137
PPC_BCC_SHORT(cond, dest); \
138
EMIT(PPC_RAW_NOP()); \
139
} else { \
140
/* Flip the 'T or F' bit to invert comparison */ \
141
PPC_BCC_SHORT(cond ^ COND_CMP_TRUE, CTX_NIA(ctx) + 2*4); \
142
PPC_JMP(dest); \
143
} } while(0)
144
145
/* To create a branch condition, select a bit of cr0... */
146
#define CR0_LT 0
147
#define CR0_GT 1
148
#define CR0_EQ 2
149
/* ...and modify BO[3] */
150
#define COND_CMP_TRUE 0x100
151
#define COND_CMP_FALSE 0x000
152
/* Together, they make all required comparisons: */
153
#define COND_GT (CR0_GT | COND_CMP_TRUE)
154
#define COND_GE (CR0_LT | COND_CMP_FALSE)
155
#define COND_EQ (CR0_EQ | COND_CMP_TRUE)
156
#define COND_NE (CR0_EQ | COND_CMP_FALSE)
157
#define COND_LT (CR0_LT | COND_CMP_TRUE)
158
#define COND_LE (CR0_GT | COND_CMP_FALSE)
159
160
#define SEEN_FUNC 0x20000000 /* might call external helpers */
161
#define SEEN_TAILCALL 0x40000000 /* uses tail calls */
162
163
struct codegen_context {
164
/*
165
* This is used to track register usage as well
166
* as calls to external helpers.
167
* - register usage is tracked with corresponding
168
* bits (r3-r31)
169
* - rest of the bits can be used to track other
170
* things -- for now, we use bits 0 to 2
171
* encoded in SEEN_* macros above
172
*/
173
unsigned int seen;
174
unsigned int idx;
175
unsigned int stack_size;
176
int b2p[MAX_BPF_JIT_REG + 3];
177
unsigned int exentry_idx;
178
unsigned int alt_exit_addr;
179
u64 arena_vm_start;
180
u64 user_vm_start;
181
bool is_subprog;
182
bool exception_boundary;
183
bool exception_cb;
184
};
185
186
#define bpf_to_ppc(r) (ctx->b2p[r])
187
188
#ifdef CONFIG_PPC32
189
#define BPF_FIXUP_LEN 3 /* Three instructions => 12 bytes */
190
#else
191
#define BPF_FIXUP_LEN 2 /* Two instructions => 8 bytes */
192
#endif
193
194
static inline bool bpf_is_seen_register(struct codegen_context *ctx, int i)
195
{
196
return ctx->seen & (1 << (31 - i));
197
}
198
199
static inline void bpf_set_seen_register(struct codegen_context *ctx, int i)
200
{
201
ctx->seen |= 1 << (31 - i);
202
}
203
204
static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
205
{
206
ctx->seen &= ~(1 << (31 - i));
207
}
208
209
void bpf_jit_init_reg_mapping(struct codegen_context *ctx);
210
int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func);
211
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,
212
u32 *addrs, int pass, bool extra_pass);
213
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
214
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
215
void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx);
216
void bpf_jit_realloc_regs(struct codegen_context *ctx);
217
int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr);
218
219
int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, u32 *fimage, int pass,
220
struct codegen_context *ctx, int insn_idx,
221
int jmp_off, int dst_reg, u32 code);
222
223
int bpf_jit_stack_tailcallinfo_offset(struct codegen_context *ctx);
224
#endif
225
226
#endif
227
228