bpf_jit_comp.c 28.9 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
Z
Zi Shen Lim 已提交
2 3 4
/*
 * BPF JIT compiler for ARM64
 *
5
 * Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@gmail.com>
Z
Zi Shen Lim 已提交
6 7 8 9
 */

#define pr_fmt(fmt) "bpf_jit: " fmt

10
#include <linux/bitfield.h>
11
#include <linux/bpf.h>
Z
Zi Shen Lim 已提交
12 13 14
#include <linux/filter.h>
#include <linux/printk.h>
#include <linux/slab.h>
15

Z
Zi Shen Lim 已提交
16 17
#include <asm/byteorder.h>
#include <asm/cacheflush.h>
18
#include <asm/debug-monitors.h>
L
Laura Abbott 已提交
19
#include <asm/set_memory.h>
Z
Zi Shen Lim 已提交
20 21 22

#include "bpf_jit.h"

23 24
#define TMP_REG_1 (MAX_BPF_JIT_REG + 0)
#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
25
#define TCALL_CNT (MAX_BPF_JIT_REG + 2)
26
#define TMP_REG_3 (MAX_BPF_JIT_REG + 3)
Z
Zi Shen Lim 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

/* Map BPF registers to A64 registers */
static const int bpf2a64[] = {
	/* return value from in-kernel function, and exit value from eBPF */
	[BPF_REG_0] = A64_R(7),
	/* arguments from eBPF program to in-kernel function */
	[BPF_REG_1] = A64_R(0),
	[BPF_REG_2] = A64_R(1),
	[BPF_REG_3] = A64_R(2),
	[BPF_REG_4] = A64_R(3),
	[BPF_REG_5] = A64_R(4),
	/* callee saved registers that in-kernel function will preserve */
	[BPF_REG_6] = A64_R(19),
	[BPF_REG_7] = A64_R(20),
	[BPF_REG_8] = A64_R(21),
	[BPF_REG_9] = A64_R(22),
	/* read-only frame pointer to access stack */
44
	[BPF_REG_FP] = A64_R(25),
45 46 47
	/* temporary registers for internal BPF JIT */
	[TMP_REG_1] = A64_R(10),
	[TMP_REG_2] = A64_R(11),
48
	[TMP_REG_3] = A64_R(12),
49 50
	/* tail_call_cnt */
	[TCALL_CNT] = A64_R(26),
51 52
	/* temporary register for blinding constants */
	[BPF_REG_AX] = A64_R(9),
Z
Zi Shen Lim 已提交
53 54 55 56 57
};

struct jit_ctx {
	const struct bpf_prog *prog;
	int idx;
58
	int epilogue_offset;
Z
Zi Shen Lim 已提交
59
	int *offset;
60
	int exentry_idx;
61
	__le32 *image;
62
	u32 stack_size;
Z
Zi Shen Lim 已提交
63 64 65 66 67 68 69 70 71 72
};

static inline void emit(const u32 insn, struct jit_ctx *ctx)
{
	if (ctx->image != NULL)
		ctx->image[ctx->idx] = cpu_to_le32(insn);

	ctx->idx++;
}

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
static inline void emit_a64_mov_i(const int is64, const int reg,
				  const s32 val, struct jit_ctx *ctx)
{
	u16 hi = val >> 16;
	u16 lo = val & 0xffff;

	if (hi & 0x8000) {
		if (hi == 0xffff) {
			emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx);
		} else {
			emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx);
			if (lo != 0xffff)
				emit(A64_MOVK(is64, reg, lo, 0), ctx);
		}
	} else {
		emit(A64_MOVZ(is64, reg, lo, 0), ctx);
		if (hi)
			emit(A64_MOVK(is64, reg, hi, 16), ctx);
	}
}

static int i64_i16_blocks(const u64 val, bool inverse)
{
	return (((val >>  0) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
	       (((val >> 16) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
	       (((val >> 32) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
	       (((val >> 48) & 0xffff) != (inverse ? 0xffff : 0x0000));
}

Z
Zi Shen Lim 已提交
102 103 104
static inline void emit_a64_mov_i64(const int reg, const u64 val,
				    struct jit_ctx *ctx)
{
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
	u64 nrm_tmp = val, rev_tmp = ~val;
	bool inverse;
	int shift;

	if (!(nrm_tmp >> 32))
		return emit_a64_mov_i(0, reg, (u32)val, ctx);

	inverse = i64_i16_blocks(nrm_tmp, true) < i64_i16_blocks(nrm_tmp, false);
	shift = max(round_down((inverse ? (fls64(rev_tmp) - 1) :
					  (fls64(nrm_tmp) - 1)), 16), 0);
	if (inverse)
		emit(A64_MOVN(1, reg, (rev_tmp >> shift) & 0xffff, shift), ctx);
	else
		emit(A64_MOVZ(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
	shift -= 16;
	while (shift >= 0) {
		if (((nrm_tmp >> shift) & 0xffff) != (inverse ? 0xffff : 0x0000))
			emit(A64_MOVK(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
		shift -= 16;
Z
Zi Shen Lim 已提交
124 125 126
	}
}

127
/*
128 129 130
 * Kernel addresses in the vmalloc space use at most 48 bits, and the
 * remaining bits are guaranteed to be 0x1. So we can compose the address
 * with a fixed length movn/movk/movk sequence.
131
 */
132 133 134 135 136 137
static inline void emit_addr_mov_i64(const int reg, const u64 val,
				     struct jit_ctx *ctx)
{
	u64 tmp = val;
	int shift = 0;

138 139
	emit(A64_MOVN(1, reg, ~tmp & 0xffff, shift), ctx);
	while (shift < 32) {
140 141 142 143 144 145
		tmp >>= 16;
		shift += 16;
		emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
	}
}

146
static inline int bpf2a64_offset(int bpf_insn, int off,
Z
Zi Shen Lim 已提交
147 148
				 const struct jit_ctx *ctx)
{
149 150 151 152 153 154 155 156
	/* BPF JMP offset is relative to the next instruction */
	bpf_insn++;
	/*
	 * Whereas arm64 branch instructions encode the offset
	 * from the branch itself, so we must subtract 1 from the
	 * instruction offset.
	 */
	return ctx->offset[bpf_insn + off] - (ctx->offset[bpf_insn] - 1);
Z
Zi Shen Lim 已提交
157 158
}

159 160
static void jit_fill_hole(void *area, unsigned int size)
{
161
	__le32 *ptr;
162 163 164 165 166
	/* We are guaranteed to have aligned memory. */
	for (ptr = area; size >= sizeof(u32); size -= sizeof(u32))
		*ptr++ = cpu_to_le32(AARCH64_BREAK_FAULT);
}

Z
Zi Shen Lim 已提交
167 168
static inline int epilogue_offset(const struct jit_ctx *ctx)
{
169 170
	int to = ctx->epilogue_offset;
	int from = ctx->idx;
Z
Zi Shen Lim 已提交
171 172 173 174

	return to - from;
}

175 176 177 178 179 180
static bool is_addsub_imm(u32 imm)
{
	/* Either imm12 or shifted imm12. */
	return !(imm & ~0xfff) || !(imm & ~0xfff000);
}

181
/* Tail call offset to jump into */
182 183 184
#if IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)
#define PROLOGUE_OFFSET 8
#else
185
#define PROLOGUE_OFFSET 7
186
#endif
187

188
static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
Z
Zi Shen Lim 已提交
189
{
190
	const struct bpf_prog *prog = ctx->prog;
Z
Zi Shen Lim 已提交
191 192 193 194 195
	const u8 r6 = bpf2a64[BPF_REG_6];
	const u8 r7 = bpf2a64[BPF_REG_7];
	const u8 r8 = bpf2a64[BPF_REG_8];
	const u8 r9 = bpf2a64[BPF_REG_9];
	const u8 fp = bpf2a64[BPF_REG_FP];
196 197 198
	const u8 tcc = bpf2a64[TCALL_CNT];
	const int idx0 = ctx->idx;
	int cur_offset;
Z
Zi Shen Lim 已提交
199

200 201 202 203 204 205 206 207
	/*
	 * BPF prog stack layout
	 *
	 *                         high
	 * original A64_SP =>   0:+-----+ BPF prologue
	 *                        |FP/LR|
	 * current A64_FP =>  -16:+-----+
	 *                        | ... | callee saved registers
208
	 * BPF fp register => -64:+-----+ <= (BPF_FP)
209 210 211
	 *                        |     |
	 *                        | ... | BPF prog stack
	 *                        |     |
212
	 *                        +-----+ <= (BPF_FP - prog->aux->stack_depth)
213
	 *                        |RSVD | padding
214
	 * current A64_SP =>      +-----+ <= (BPF_FP - ctx->stack_size)
215 216 217 218 219 220 221 222
	 *                        |     |
	 *                        | ... | Function call stack
	 *                        |     |
	 *                        +-----+
	 *                          low
	 *
	 */

223 224 225 226
	/* BTI landing pad */
	if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
		emit(A64_BTI_C, ctx);

227 228 229 230
	/* Save FP and LR registers to stay align with ARM64 AAPCS */
	emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
	emit(A64_MOV(1, A64_FP, A64_SP), ctx);

231
	/* Save callee-saved registers */
Z
Zi Shen Lim 已提交
232 233
	emit(A64_PUSH(r6, r7, A64_SP), ctx);
	emit(A64_PUSH(r8, r9, A64_SP), ctx);
234
	emit(A64_PUSH(fp, tcc, A64_SP), ctx);
Z
Zi Shen Lim 已提交
235

236
	/* Set up BPF prog stack base register */
Z
Zi Shen Lim 已提交
237 238
	emit(A64_MOV(1, fp, A64_SP), ctx);

239 240 241
	if (!ebpf_from_cbpf) {
		/* Initialize tail_call_cnt */
		emit(A64_MOVZ(1, tcc, 0, 0), ctx);
242

243 244 245 246 247 248
		cur_offset = ctx->idx - idx0;
		if (cur_offset != PROLOGUE_OFFSET) {
			pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n",
				    cur_offset, PROLOGUE_OFFSET);
			return -1;
		}
249 250 251 252

		/* BTI landing pad for the tail call, done with a BR */
		if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
			emit(A64_BTI_J, ctx);
253
	}
254

255 256
	/* Stack must be multiples of 16B */
	ctx->stack_size = round_up(prog->aux->stack_depth, 16);
257 258 259

	/* Set up function call stack */
	emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
	return 0;
}

static int out_offset = -1; /* initialized on the first pass of build_body() */
static int emit_bpf_tail_call(struct jit_ctx *ctx)
{
	/* bpf_tail_call(void *prog_ctx, struct bpf_array *array, u64 index) */
	const u8 r2 = bpf2a64[BPF_REG_2];
	const u8 r3 = bpf2a64[BPF_REG_3];

	const u8 tmp = bpf2a64[TMP_REG_1];
	const u8 prg = bpf2a64[TMP_REG_2];
	const u8 tcc = bpf2a64[TCALL_CNT];
	const int idx0 = ctx->idx;
#define cur_offset (ctx->idx - idx0)
#define jmp_offset (out_offset - (cur_offset))
	size_t off;

	/* if (index >= array->map.max_entries)
	 *     goto out;
	 */
	off = offsetof(struct bpf_array, map.max_entries);
	emit_a64_mov_i64(tmp, off, ctx);
	emit(A64_LDR32(tmp, r2, tmp), ctx);
284
	emit(A64_MOV(0, r3, r3), ctx);
285
	emit(A64_CMP(0, r3, tmp), ctx);
286
	emit(A64_B_(A64_COND_CS, jmp_offset), ctx);
287 288 289 290 291 292 293

	/* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
	 *     goto out;
	 * tail_call_cnt++;
	 */
	emit_a64_mov_i64(tmp, MAX_TAIL_CALL_CNT, ctx);
	emit(A64_CMP(1, tcc, tmp), ctx);
294
	emit(A64_B_(A64_COND_HI, jmp_offset), ctx);
295 296 297 298 299 300 301 302
	emit(A64_ADD_I(1, tcc, tcc, 1), ctx);

	/* prog = array->ptrs[index];
	 * if (prog == NULL)
	 *     goto out;
	 */
	off = offsetof(struct bpf_array, ptrs);
	emit_a64_mov_i64(tmp, off, ctx);
303 304 305
	emit(A64_ADD(1, tmp, r2, tmp), ctx);
	emit(A64_LSL(1, prg, r3, 3), ctx);
	emit(A64_LDR64(prg, tmp, prg), ctx);
306 307
	emit(A64_CBZ(1, prg, jmp_offset), ctx);

308
	/* goto *(prog->bpf_func + prologue_offset); */
309 310 311 312
	off = offsetof(struct bpf_prog, bpf_func);
	emit_a64_mov_i64(tmp, off, ctx);
	emit(A64_LDR64(tmp, prg, tmp), ctx);
	emit(A64_ADD_I(1, tmp, tmp, sizeof(u32) * PROLOGUE_OFFSET), ctx);
313
	emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
314 315 316 317 318 319 320 321 322 323 324 325 326
	emit(A64_BR(tmp), ctx);

	/* out: */
	if (out_offset == -1)
		out_offset = cur_offset;
	if (cur_offset != out_offset) {
		pr_err_once("tail_call out_offset = %d, expected %d!\n",
			    cur_offset, out_offset);
		return -1;
	}
	return 0;
#undef cur_offset
#undef jmp_offset
Z
Zi Shen Lim 已提交
327 328 329 330 331 332 333 334 335 336 337 338
}

static void build_epilogue(struct jit_ctx *ctx)
{
	const u8 r0 = bpf2a64[BPF_REG_0];
	const u8 r6 = bpf2a64[BPF_REG_6];
	const u8 r7 = bpf2a64[BPF_REG_7];
	const u8 r8 = bpf2a64[BPF_REG_8];
	const u8 r9 = bpf2a64[BPF_REG_9];
	const u8 fp = bpf2a64[BPF_REG_FP];

	/* We're done with BPF stack */
339
	emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
Z
Zi Shen Lim 已提交
340

341 342 343
	/* Restore fs (x25) and x26 */
	emit(A64_POP(fp, A64_R(26), A64_SP), ctx);

Z
Zi Shen Lim 已提交
344 345 346 347
	/* Restore callee-saved register */
	emit(A64_POP(r8, r9, A64_SP), ctx);
	emit(A64_POP(r6, r7, A64_SP), ctx);

348 349
	/* Restore FP/LR registers */
	emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx);
Z
Zi Shen Lim 已提交
350 351 352 353 354 355 356

	/* Set return value */
	emit(A64_MOV(1, A64_R(0), r0), ctx);

	emit(A64_RET(A64_LR), ctx);
}

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
#define BPF_FIXUP_OFFSET_MASK	GENMASK(26, 0)
#define BPF_FIXUP_REG_MASK	GENMASK(31, 27)

int arm64_bpf_fixup_exception(const struct exception_table_entry *ex,
			      struct pt_regs *regs)
{
	off_t offset = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup);
	int dst_reg = FIELD_GET(BPF_FIXUP_REG_MASK, ex->fixup);

	regs->regs[dst_reg] = 0;
	regs->pc = (unsigned long)&ex->fixup - offset;
	return 1;
}

/* For accesses to BTF pointers, add an entry to the exception table */
static int add_exception_handler(const struct bpf_insn *insn,
				 struct jit_ctx *ctx,
				 int dst_reg)
{
	off_t offset;
	unsigned long pc;
	struct exception_table_entry *ex;

	if (!ctx->image)
		/* First pass */
		return 0;

	if (BPF_MODE(insn->code) != BPF_PROBE_MEM)
		return 0;

	if (!ctx->prog->aux->extable ||
	    WARN_ON_ONCE(ctx->exentry_idx >= ctx->prog->aux->num_exentries))
		return -EINVAL;

	ex = &ctx->prog->aux->extable[ctx->exentry_idx];
	pc = (unsigned long)&ctx->image[ctx->idx - 1];

	offset = pc - (long)&ex->insn;
	if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN))
		return -ERANGE;
	ex->insn = offset;

	/*
	 * Since the extable follows the program, the fixup offset is always
	 * negative and limited to BPF_JIT_REGION_SIZE. Store a positive value
	 * to keep things simple, and put the destination register in the upper
	 * bits. We don't need to worry about buildtime or runtime sort
	 * modifying the upper bits because the table is already sorted, and
	 * isn't part of the main exception table.
	 */
	offset = (long)&ex->fixup - (pc + AARCH64_INSN_SIZE);
	if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, offset))
		return -ERANGE;

	ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, offset) |
		    FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);

	ctx->exentry_idx++;
	return 0;
}

418 419 420 421 422 423
/* JITs an eBPF instruction.
 * Returns:
 * 0  - successfully JITed an 8-byte eBPF instruction.
 * >0 - successfully JITed a 16-byte eBPF instruction.
 * <0 - failed to JIT.
 */
424 425
static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
		      bool extra_pass)
Z
Zi Shen Lim 已提交
426 427 428 429 430 431
{
	const u8 code = insn->code;
	const u8 dst = bpf2a64[insn->dst_reg];
	const u8 src = bpf2a64[insn->src_reg];
	const u8 tmp = bpf2a64[TMP_REG_1];
	const u8 tmp2 = bpf2a64[TMP_REG_2];
432
	const u8 tmp3 = bpf2a64[TMP_REG_3];
Z
Zi Shen Lim 已提交
433 434 435
	const s16 off = insn->off;
	const s32 imm = insn->imm;
	const int i = insn - ctx->prog->insnsi;
436 437
	const bool is64 = BPF_CLASS(code) == BPF_ALU64 ||
			  BPF_CLASS(code) == BPF_JMP;
438
	const bool isdw = BPF_SIZE(code) == BPF_DW;
439
	u8 jmp_cond, reg;
Z
Zi Shen Lim 已提交
440
	s32 jmp_offset;
441
	u32 a64_insn;
442
	int ret;
Z
Zi Shen Lim 已提交
443

Z
Zi Shen Lim 已提交
444 445 446 447 448 449 450 451 452 453 454
#define check_imm(bits, imm) do {				\
	if ((((imm) > 0) && ((imm) >> (bits))) ||		\
	    (((imm) < 0) && (~(imm) >> (bits)))) {		\
		pr_info("[%2d] imm=%d(0x%x) out of range\n",	\
			i, imm, imm);				\
		return -EINVAL;					\
	}							\
} while (0)
#define check_imm19(imm) check_imm(19, imm)
#define check_imm26(imm) check_imm(26, imm)

Z
Zi Shen Lim 已提交
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
	switch (code) {
	/* dst = src */
	case BPF_ALU | BPF_MOV | BPF_X:
	case BPF_ALU64 | BPF_MOV | BPF_X:
		emit(A64_MOV(is64, dst, src), ctx);
		break;
	/* dst = dst OP src */
	case BPF_ALU | BPF_ADD | BPF_X:
	case BPF_ALU64 | BPF_ADD | BPF_X:
		emit(A64_ADD(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_SUB | BPF_X:
	case BPF_ALU64 | BPF_SUB | BPF_X:
		emit(A64_SUB(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_AND | BPF_X:
	case BPF_ALU64 | BPF_AND | BPF_X:
		emit(A64_AND(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_OR | BPF_X:
	case BPF_ALU64 | BPF_OR | BPF_X:
		emit(A64_ORR(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_XOR | BPF_X:
	case BPF_ALU64 | BPF_XOR | BPF_X:
		emit(A64_EOR(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_MUL | BPF_X:
	case BPF_ALU64 | BPF_MUL | BPF_X:
		emit(A64_MUL(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_DIV | BPF_X:
	case BPF_ALU64 | BPF_DIV | BPF_X:
	case BPF_ALU | BPF_MOD | BPF_X:
	case BPF_ALU64 | BPF_MOD | BPF_X:
Z
Zi Shen Lim 已提交
490 491 492 493 494 495
		switch (BPF_OP(code)) {
		case BPF_DIV:
			emit(A64_UDIV(is64, dst, dst, src), ctx);
			break;
		case BPF_MOD:
			emit(A64_UDIV(is64, tmp, dst, src), ctx);
496
			emit(A64_MSUB(is64, dst, dst, tmp, src), ctx);
Z
Zi Shen Lim 已提交
497 498
			break;
		}
Z
Zi Shen Lim 已提交
499
		break;
500 501 502 503 504 505 506 507 508 509 510 511
	case BPF_ALU | BPF_LSH | BPF_X:
	case BPF_ALU64 | BPF_LSH | BPF_X:
		emit(A64_LSLV(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_RSH | BPF_X:
	case BPF_ALU64 | BPF_RSH | BPF_X:
		emit(A64_LSRV(is64, dst, dst, src), ctx);
		break;
	case BPF_ALU | BPF_ARSH | BPF_X:
	case BPF_ALU64 | BPF_ARSH | BPF_X:
		emit(A64_ASRV(is64, dst, dst, src), ctx);
		break;
Z
Zi Shen Lim 已提交
512 513 514 515 516 517 518 519 520 521
	/* dst = -dst */
	case BPF_ALU | BPF_NEG:
	case BPF_ALU64 | BPF_NEG:
		emit(A64_NEG(is64, dst, dst), ctx);
		break;
	/* dst = BSWAP##imm(dst) */
	case BPF_ALU | BPF_END | BPF_FROM_LE:
	case BPF_ALU | BPF_END | BPF_FROM_BE:
#ifdef CONFIG_CPU_BIG_ENDIAN
		if (BPF_SRC(code) == BPF_FROM_BE)
522
			goto emit_bswap_uxt;
Z
Zi Shen Lim 已提交
523 524
#else /* !CONFIG_CPU_BIG_ENDIAN */
		if (BPF_SRC(code) == BPF_FROM_LE)
525
			goto emit_bswap_uxt;
Z
Zi Shen Lim 已提交
526 527 528 529
#endif
		switch (imm) {
		case 16:
			emit(A64_REV16(is64, dst, dst), ctx);
530 531
			/* zero-extend 16 bits into 64 bits */
			emit(A64_UXTH(is64, dst, dst), ctx);
Z
Zi Shen Lim 已提交
532 533 534
			break;
		case 32:
			emit(A64_REV32(is64, dst, dst), ctx);
535
			/* upper 32 bits already cleared */
Z
Zi Shen Lim 已提交
536 537 538 539 540 541
			break;
		case 64:
			emit(A64_REV64(dst, dst), ctx);
			break;
		}
		break;
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
emit_bswap_uxt:
		switch (imm) {
		case 16:
			/* zero-extend 16 bits into 64 bits */
			emit(A64_UXTH(is64, dst, dst), ctx);
			break;
		case 32:
			/* zero-extend 32 bits into 64 bits */
			emit(A64_UXTW(is64, dst, dst), ctx);
			break;
		case 64:
			/* nop */
			break;
		}
		break;
Z
Zi Shen Lim 已提交
557 558 559 560 561 562 563 564
	/* dst = imm */
	case BPF_ALU | BPF_MOV | BPF_K:
	case BPF_ALU64 | BPF_MOV | BPF_K:
		emit_a64_mov_i(is64, dst, imm, ctx);
		break;
	/* dst = dst OP imm */
	case BPF_ALU | BPF_ADD | BPF_K:
	case BPF_ALU64 | BPF_ADD | BPF_K:
565 566 567 568 569 570 571 572
		if (is_addsub_imm(imm)) {
			emit(A64_ADD_I(is64, dst, dst, imm), ctx);
		} else if (is_addsub_imm(-imm)) {
			emit(A64_SUB_I(is64, dst, dst, -imm), ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_ADD(is64, dst, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
573 574 575
		break;
	case BPF_ALU | BPF_SUB | BPF_K:
	case BPF_ALU64 | BPF_SUB | BPF_K:
576 577 578 579 580 581 582 583
		if (is_addsub_imm(imm)) {
			emit(A64_SUB_I(is64, dst, dst, imm), ctx);
		} else if (is_addsub_imm(-imm)) {
			emit(A64_ADD_I(is64, dst, dst, -imm), ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_SUB(is64, dst, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
584 585 586
		break;
	case BPF_ALU | BPF_AND | BPF_K:
	case BPF_ALU64 | BPF_AND | BPF_K:
587 588 589 590 591 592 593
		a64_insn = A64_AND_I(is64, dst, dst, imm);
		if (a64_insn != AARCH64_BREAK_FAULT) {
			emit(a64_insn, ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_AND(is64, dst, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
594 595 596
		break;
	case BPF_ALU | BPF_OR | BPF_K:
	case BPF_ALU64 | BPF_OR | BPF_K:
597 598 599 600 601 602 603
		a64_insn = A64_ORR_I(is64, dst, dst, imm);
		if (a64_insn != AARCH64_BREAK_FAULT) {
			emit(a64_insn, ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_ORR(is64, dst, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
604 605 606
		break;
	case BPF_ALU | BPF_XOR | BPF_K:
	case BPF_ALU64 | BPF_XOR | BPF_K:
607 608 609 610 611 612 613
		a64_insn = A64_EOR_I(is64, dst, dst, imm);
		if (a64_insn != AARCH64_BREAK_FAULT) {
			emit(a64_insn, ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_EOR(is64, dst, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
		break;
	case BPF_ALU | BPF_MUL | BPF_K:
	case BPF_ALU64 | BPF_MUL | BPF_K:
		emit_a64_mov_i(is64, tmp, imm, ctx);
		emit(A64_MUL(is64, dst, dst, tmp), ctx);
		break;
	case BPF_ALU | BPF_DIV | BPF_K:
	case BPF_ALU64 | BPF_DIV | BPF_K:
		emit_a64_mov_i(is64, tmp, imm, ctx);
		emit(A64_UDIV(is64, dst, dst, tmp), ctx);
		break;
	case BPF_ALU | BPF_MOD | BPF_K:
	case BPF_ALU64 | BPF_MOD | BPF_K:
		emit_a64_mov_i(is64, tmp2, imm, ctx);
		emit(A64_UDIV(is64, tmp, dst, tmp2), ctx);
629
		emit(A64_MSUB(is64, dst, dst, tmp, tmp2), ctx);
Z
Zi Shen Lim 已提交
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
		break;
	case BPF_ALU | BPF_LSH | BPF_K:
	case BPF_ALU64 | BPF_LSH | BPF_K:
		emit(A64_LSL(is64, dst, dst, imm), ctx);
		break;
	case BPF_ALU | BPF_RSH | BPF_K:
	case BPF_ALU64 | BPF_RSH | BPF_K:
		emit(A64_LSR(is64, dst, dst, imm), ctx);
		break;
	case BPF_ALU | BPF_ARSH | BPF_K:
	case BPF_ALU64 | BPF_ARSH | BPF_K:
		emit(A64_ASR(is64, dst, dst, imm), ctx);
		break;

	/* JUMP off */
	case BPF_JMP | BPF_JA:
646
		jmp_offset = bpf2a64_offset(i, off, ctx);
Z
Zi Shen Lim 已提交
647 648 649 650 651 652
		check_imm26(jmp_offset);
		emit(A64_B(jmp_offset), ctx);
		break;
	/* IF (dst COND src) JUMP off */
	case BPF_JMP | BPF_JEQ | BPF_X:
	case BPF_JMP | BPF_JGT | BPF_X:
653
	case BPF_JMP | BPF_JLT | BPF_X:
Z
Zi Shen Lim 已提交
654
	case BPF_JMP | BPF_JGE | BPF_X:
655
	case BPF_JMP | BPF_JLE | BPF_X:
Z
Zi Shen Lim 已提交
656 657
	case BPF_JMP | BPF_JNE | BPF_X:
	case BPF_JMP | BPF_JSGT | BPF_X:
658
	case BPF_JMP | BPF_JSLT | BPF_X:
Z
Zi Shen Lim 已提交
659
	case BPF_JMP | BPF_JSGE | BPF_X:
660
	case BPF_JMP | BPF_JSLE | BPF_X:
661 662 663 664 665 666 667 668 669 670 671
	case BPF_JMP32 | BPF_JEQ | BPF_X:
	case BPF_JMP32 | BPF_JGT | BPF_X:
	case BPF_JMP32 | BPF_JLT | BPF_X:
	case BPF_JMP32 | BPF_JGE | BPF_X:
	case BPF_JMP32 | BPF_JLE | BPF_X:
	case BPF_JMP32 | BPF_JNE | BPF_X:
	case BPF_JMP32 | BPF_JSGT | BPF_X:
	case BPF_JMP32 | BPF_JSLT | BPF_X:
	case BPF_JMP32 | BPF_JSGE | BPF_X:
	case BPF_JMP32 | BPF_JSLE | BPF_X:
		emit(A64_CMP(is64, dst, src), ctx);
Z
Zi Shen Lim 已提交
672
emit_cond_jmp:
673
		jmp_offset = bpf2a64_offset(i, off, ctx);
Z
Zi Shen Lim 已提交
674 675 676 677 678 679 680 681
		check_imm19(jmp_offset);
		switch (BPF_OP(code)) {
		case BPF_JEQ:
			jmp_cond = A64_COND_EQ;
			break;
		case BPF_JGT:
			jmp_cond = A64_COND_HI;
			break;
682 683 684
		case BPF_JLT:
			jmp_cond = A64_COND_CC;
			break;
Z
Zi Shen Lim 已提交
685 686 687
		case BPF_JGE:
			jmp_cond = A64_COND_CS;
			break;
688 689 690
		case BPF_JLE:
			jmp_cond = A64_COND_LS;
			break;
Z
Zi Shen Lim 已提交
691
		case BPF_JSET:
Z
Zi Shen Lim 已提交
692 693 694 695 696 697
		case BPF_JNE:
			jmp_cond = A64_COND_NE;
			break;
		case BPF_JSGT:
			jmp_cond = A64_COND_GT;
			break;
698 699 700
		case BPF_JSLT:
			jmp_cond = A64_COND_LT;
			break;
Z
Zi Shen Lim 已提交
701 702 703
		case BPF_JSGE:
			jmp_cond = A64_COND_GE;
			break;
704 705 706
		case BPF_JSLE:
			jmp_cond = A64_COND_LE;
			break;
Z
Zi Shen Lim 已提交
707 708 709 710 711 712
		default:
			return -EFAULT;
		}
		emit(A64_B_(jmp_cond, jmp_offset), ctx);
		break;
	case BPF_JMP | BPF_JSET | BPF_X:
713 714
	case BPF_JMP32 | BPF_JSET | BPF_X:
		emit(A64_TST(is64, dst, src), ctx);
Z
Zi Shen Lim 已提交
715 716 717 718
		goto emit_cond_jmp;
	/* IF (dst COND imm) JUMP off */
	case BPF_JMP | BPF_JEQ | BPF_K:
	case BPF_JMP | BPF_JGT | BPF_K:
719
	case BPF_JMP | BPF_JLT | BPF_K:
Z
Zi Shen Lim 已提交
720
	case BPF_JMP | BPF_JGE | BPF_K:
721
	case BPF_JMP | BPF_JLE | BPF_K:
Z
Zi Shen Lim 已提交
722 723
	case BPF_JMP | BPF_JNE | BPF_K:
	case BPF_JMP | BPF_JSGT | BPF_K:
724
	case BPF_JMP | BPF_JSLT | BPF_K:
Z
Zi Shen Lim 已提交
725
	case BPF_JMP | BPF_JSGE | BPF_K:
726
	case BPF_JMP | BPF_JSLE | BPF_K:
727 728 729 730 731 732 733 734 735 736
	case BPF_JMP32 | BPF_JEQ | BPF_K:
	case BPF_JMP32 | BPF_JGT | BPF_K:
	case BPF_JMP32 | BPF_JLT | BPF_K:
	case BPF_JMP32 | BPF_JGE | BPF_K:
	case BPF_JMP32 | BPF_JLE | BPF_K:
	case BPF_JMP32 | BPF_JNE | BPF_K:
	case BPF_JMP32 | BPF_JSGT | BPF_K:
	case BPF_JMP32 | BPF_JSLT | BPF_K:
	case BPF_JMP32 | BPF_JSGE | BPF_K:
	case BPF_JMP32 | BPF_JSLE | BPF_K:
737 738 739 740 741 742 743 744
		if (is_addsub_imm(imm)) {
			emit(A64_CMP_I(is64, dst, imm), ctx);
		} else if (is_addsub_imm(-imm)) {
			emit(A64_CMN_I(is64, dst, -imm), ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_CMP(is64, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
745 746
		goto emit_cond_jmp;
	case BPF_JMP | BPF_JSET | BPF_K:
747
	case BPF_JMP32 | BPF_JSET | BPF_K:
748 749 750 751 752 753 754
		a64_insn = A64_TST_I(is64, dst, imm);
		if (a64_insn != AARCH64_BREAK_FAULT) {
			emit(a64_insn, ctx);
		} else {
			emit_a64_mov_i(is64, tmp, imm, ctx);
			emit(A64_TST(is64, dst, tmp), ctx);
		}
Z
Zi Shen Lim 已提交
755 756 757 758 759
		goto emit_cond_jmp;
	/* function call */
	case BPF_JMP | BPF_CALL:
	{
		const u8 r0 = bpf2a64[BPF_REG_0];
760 761
		bool func_addr_fixed;
		u64 func_addr;
Z
Zi Shen Lim 已提交
762

763 764 765 766
		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
					    &func_addr, &func_addr_fixed);
		if (ret < 0)
			return ret;
767
		emit_addr_mov_i64(tmp, func_addr, ctx);
Z
Zi Shen Lim 已提交
768 769 770 771
		emit(A64_BLR(tmp), ctx);
		emit(A64_MOV(1, r0, A64_R(0)), ctx);
		break;
	}
772
	/* tail call */
773
	case BPF_JMP | BPF_TAIL_CALL:
774 775 776
		if (emit_bpf_tail_call(ctx))
			return -EFAULT;
		break;
Z
Zi Shen Lim 已提交
777 778
	/* function return */
	case BPF_JMP | BPF_EXIT:
779 780
		/* Optimization: when last instruction is EXIT,
		   simply fallthrough to epilogue. */
Z
Zi Shen Lim 已提交
781 782 783 784 785 786 787
		if (i == ctx->prog->len - 1)
			break;
		jmp_offset = epilogue_offset(ctx);
		check_imm26(jmp_offset);
		emit(A64_B(jmp_offset), ctx);
		break;

788 789 790 791 792 793
	/* dst = imm64 */
	case BPF_LD | BPF_IMM | BPF_DW:
	{
		const struct bpf_insn insn1 = insn[1];
		u64 imm64;

794
		imm64 = (u64)insn1.imm << 32 | (u32)imm;
795 796 797 798 799
		emit_a64_mov_i64(dst, imm64, ctx);

		return 1;
	}

Z
Zi Shen Lim 已提交
800 801 802 803 804
	/* LDX: dst = *(size *)(src + off) */
	case BPF_LDX | BPF_MEM | BPF_W:
	case BPF_LDX | BPF_MEM | BPF_H:
	case BPF_LDX | BPF_MEM | BPF_B:
	case BPF_LDX | BPF_MEM | BPF_DW:
805 806 807 808
	case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
	case BPF_LDX | BPF_PROBE_MEM | BPF_W:
	case BPF_LDX | BPF_PROBE_MEM | BPF_H:
	case BPF_LDX | BPF_PROBE_MEM | BPF_B:
Z
Zi Shen Lim 已提交
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
		emit_a64_mov_i(1, tmp, off, ctx);
		switch (BPF_SIZE(code)) {
		case BPF_W:
			emit(A64_LDR32(dst, src, tmp), ctx);
			break;
		case BPF_H:
			emit(A64_LDRH(dst, src, tmp), ctx);
			break;
		case BPF_B:
			emit(A64_LDRB(dst, src, tmp), ctx);
			break;
		case BPF_DW:
			emit(A64_LDR64(dst, src, tmp), ctx);
			break;
		}
824 825 826 827

		ret = add_exception_handler(insn, ctx, dst);
		if (ret)
			return ret;
Z
Zi Shen Lim 已提交
828 829 830 831 832 833 834
		break;

	/* ST: *(size *)(dst + off) = imm */
	case BPF_ST | BPF_MEM | BPF_W:
	case BPF_ST | BPF_MEM | BPF_H:
	case BPF_ST | BPF_MEM | BPF_B:
	case BPF_ST | BPF_MEM | BPF_DW:
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
		/* Load imm to a register then store it */
		emit_a64_mov_i(1, tmp2, off, ctx);
		emit_a64_mov_i(1, tmp, imm, ctx);
		switch (BPF_SIZE(code)) {
		case BPF_W:
			emit(A64_STR32(tmp, dst, tmp2), ctx);
			break;
		case BPF_H:
			emit(A64_STRH(tmp, dst, tmp2), ctx);
			break;
		case BPF_B:
			emit(A64_STRB(tmp, dst, tmp2), ctx);
			break;
		case BPF_DW:
			emit(A64_STR64(tmp, dst, tmp2), ctx);
			break;
		}
		break;
Z
Zi Shen Lim 已提交
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874

	/* STX: *(size *)(dst + off) = src */
	case BPF_STX | BPF_MEM | BPF_W:
	case BPF_STX | BPF_MEM | BPF_H:
	case BPF_STX | BPF_MEM | BPF_B:
	case BPF_STX | BPF_MEM | BPF_DW:
		emit_a64_mov_i(1, tmp, off, ctx);
		switch (BPF_SIZE(code)) {
		case BPF_W:
			emit(A64_STR32(src, dst, tmp), ctx);
			break;
		case BPF_H:
			emit(A64_STRH(src, dst, tmp), ctx);
			break;
		case BPF_B:
			emit(A64_STRB(src, dst, tmp), ctx);
			break;
		case BPF_DW:
			emit(A64_STR64(src, dst, tmp), ctx);
			break;
		}
		break;
875

876 877 878 879 880 881 882 883 884 885 886 887
	case BPF_STX | BPF_ATOMIC | BPF_W:
	case BPF_STX | BPF_ATOMIC | BPF_DW:
		if (insn->imm != BPF_ADD) {
			pr_err_once("unknown atomic op code %02x\n", insn->imm);
			return -EINVAL;
		}

		/* STX XADD: lock *(u32 *)(dst + off) += src
		 * and
		 * STX XADD: lock *(u64 *)(dst + off) += src
		 */

888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
		if (!off) {
			reg = dst;
		} else {
			emit_a64_mov_i(1, tmp, off, ctx);
			emit(A64_ADD(1, tmp, tmp, dst), ctx);
			reg = tmp;
		}
		if (cpus_have_cap(ARM64_HAS_LSE_ATOMICS)) {
			emit(A64_STADD(isdw, reg, src), ctx);
		} else {
			emit(A64_LDXR(isdw, tmp2, reg), ctx);
			emit(A64_ADD(isdw, tmp2, tmp2, src), ctx);
			emit(A64_STXR(isdw, tmp2, reg, tmp3), ctx);
			jmp_offset = -3;
			check_imm19(jmp_offset);
			emit(A64_CBNZ(0, tmp3, jmp_offset), ctx);
		}
905
		break;
Z
Zi Shen Lim 已提交
906 907 908 909 910 911 912 913 914

	default:
		pr_err_once("unknown opcode %02x\n", code);
		return -EINVAL;
	}

	return 0;
}

915
static int build_body(struct jit_ctx *ctx, bool extra_pass)
Z
Zi Shen Lim 已提交
916 917 918 919
{
	const struct bpf_prog *prog = ctx->prog;
	int i;

920 921 922 923 924 925 926 927 928
	/*
	 * - offset[0] offset of the end of prologue,
	 *   start of the 1st instruction.
	 * - offset[1] - offset of the end of 1st instruction,
	 *   start of the 2nd instruction
	 * [....]
	 * - offset[3] - offset of the end of 3rd instruction,
	 *   start of 4th instruction
	 */
Z
Zi Shen Lim 已提交
929 930 931 932
	for (i = 0; i < prog->len; i++) {
		const struct bpf_insn *insn = &prog->insnsi[i];
		int ret;

933 934
		if (ctx->image == NULL)
			ctx->offset[i] = ctx->idx;
935
		ret = build_insn(insn, ctx, extra_pass);
936 937
		if (ret > 0) {
			i++;
938 939
			if (ctx->image == NULL)
				ctx->offset[i] = ctx->idx;
940 941
			continue;
		}
Z
Zi Shen Lim 已提交
942 943 944
		if (ret)
			return ret;
	}
945 946 947 948 949 950 951
	/*
	 * offset is allocated with prog->len + 1 so fill in
	 * the last element with the offset after the last
	 * instruction (end of program)
	 */
	if (ctx->image == NULL)
		ctx->offset[i] = ctx->idx;
Z
Zi Shen Lim 已提交
952 953 954 955

	return 0;
}

956 957 958 959 960 961 962 963 964 965 966
static int validate_code(struct jit_ctx *ctx)
{
	int i;

	for (i = 0; i < ctx->idx; i++) {
		u32 a64_insn = le32_to_cpu(ctx->image[i]);

		if (a64_insn == AARCH64_BREAK_FAULT)
			return -1;
	}

967 968 969
	if (WARN_ON_ONCE(ctx->exentry_idx != ctx->prog->aux->num_exentries))
		return -1;

970 971 972
	return 0;
}

Z
Zi Shen Lim 已提交
973 974 975 976 977
static inline void bpf_flush_icache(void *start, void *end)
{
	flush_icache_range((unsigned long)start, (unsigned long)end);
}

978 979 980 981 982 983
struct arm64_jit_data {
	struct bpf_binary_header *header;
	u8 *image;
	struct jit_ctx ctx;
};

984
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
Z
Zi Shen Lim 已提交
985
{
986
	int image_size, prog_size, extable_size;
987
	struct bpf_prog *tmp, *orig_prog = prog;
988
	struct bpf_binary_header *header;
989
	struct arm64_jit_data *jit_data;
990
	bool was_classic = bpf_prog_was_classic(prog);
991
	bool tmp_blinded = false;
992
	bool extra_pass = false;
Z
Zi Shen Lim 已提交
993
	struct jit_ctx ctx;
994
	u8 *image_ptr;
Z
Zi Shen Lim 已提交
995

996
	if (!prog->jit_requested)
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
		return orig_prog;

	tmp = bpf_jit_blind_constants(prog);
	/* If blinding was requested and we failed during blinding,
	 * we must fall back to the interpreter.
	 */
	if (IS_ERR(tmp))
		return orig_prog;
	if (tmp != prog) {
		tmp_blinded = true;
		prog = tmp;
	}
Z
Zi Shen Lim 已提交
1009

1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
	jit_data = prog->aux->jit_data;
	if (!jit_data) {
		jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL);
		if (!jit_data) {
			prog = orig_prog;
			goto out;
		}
		prog->aux->jit_data = jit_data;
	}
	if (jit_data->ctx.offset) {
		ctx = jit_data->ctx;
		image_ptr = jit_data->image;
		header = jit_data->header;
		extra_pass = true;
1024
		prog_size = sizeof(u32) * ctx.idx;
1025 1026
		goto skip_init_ctx;
	}
Z
Zi Shen Lim 已提交
1027 1028 1029
	memset(&ctx, 0, sizeof(ctx));
	ctx.prog = prog;

1030
	ctx.offset = kcalloc(prog->len + 1, sizeof(int), GFP_KERNEL);
1031 1032
	if (ctx.offset == NULL) {
		prog = orig_prog;
1033
		goto out_off;
1034
	}
Z
Zi Shen Lim 已提交
1035 1036 1037

	/* 1. Initial fake pass to compute ctx->idx. */

1038
	/* Fake pass to fill in ctx->offset. */
1039
	if (build_body(&ctx, extra_pass)) {
1040 1041 1042
		prog = orig_prog;
		goto out_off;
	}
Z
Zi Shen Lim 已提交
1043

1044
	if (build_prologue(&ctx, was_classic)) {
1045 1046 1047
		prog = orig_prog;
		goto out_off;
	}
1048 1049

	ctx.epilogue_offset = ctx.idx;
Z
Zi Shen Lim 已提交
1050 1051
	build_epilogue(&ctx);

1052 1053 1054
	extable_size = prog->aux->num_exentries *
		sizeof(struct exception_table_entry);

Z
Zi Shen Lim 已提交
1055
	/* Now we know the actual image size. */
1056 1057
	prog_size = sizeof(u32) * ctx.idx;
	image_size = prog_size + extable_size;
1058 1059
	header = bpf_jit_binary_alloc(image_size, &image_ptr,
				      sizeof(u32), jit_fill_hole);
1060 1061 1062 1063
	if (header == NULL) {
		prog = orig_prog;
		goto out_off;
	}
Z
Zi Shen Lim 已提交
1064 1065 1066

	/* 2. Now, the actual pass. */

1067
	ctx.image = (__le32 *)image_ptr;
1068 1069
	if (extable_size)
		prog->aux->extable = (void *)image_ptr + prog_size;
1070
skip_init_ctx:
Z
Zi Shen Lim 已提交
1071
	ctx.idx = 0;
1072
	ctx.exentry_idx = 0;
1073

1074
	build_prologue(&ctx, was_classic);
Z
Zi Shen Lim 已提交
1075

1076
	if (build_body(&ctx, extra_pass)) {
1077
		bpf_jit_binary_free(header);
1078 1079
		prog = orig_prog;
		goto out_off;
1080
	}
Z
Zi Shen Lim 已提交
1081 1082 1083

	build_epilogue(&ctx);

1084 1085 1086
	/* 3. Extra pass to validate JITed code. */
	if (validate_code(&ctx)) {
		bpf_jit_binary_free(header);
1087 1088
		prog = orig_prog;
		goto out_off;
1089 1090
	}

Z
Zi Shen Lim 已提交
1091 1092
	/* And we're done. */
	if (bpf_jit_enable > 1)
1093
		bpf_jit_dump(prog->len, prog_size, 2, ctx.image);
Z
Zi Shen Lim 已提交
1094

1095
	bpf_flush_icache(header, ctx.image + ctx.idx);
1096

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
	if (!prog->is_func || extra_pass) {
		if (extra_pass && ctx.idx != jit_data->ctx.idx) {
			pr_err_once("multi-func JIT bug %d != %d\n",
				    ctx.idx, jit_data->ctx.idx);
			bpf_jit_binary_free(header);
			prog->bpf_func = NULL;
			prog->jited = 0;
			goto out_off;
		}
		bpf_jit_binary_lock_ro(header);
	} else {
		jit_data->ctx = ctx;
		jit_data->image = image_ptr;
		jit_data->header = header;
	}
Z
Zi Shen Lim 已提交
1112
	prog->bpf_func = (void *)ctx.image;
1113
	prog->jited = 1;
1114
	prog->jited_len = prog_size;
1115

1116
	if (!prog->is_func || extra_pass) {
1117
		bpf_prog_fill_jited_linfo(prog, ctx.offset + 1);
1118
out_off:
1119 1120 1121 1122
		kfree(ctx.offset);
		kfree(jit_data);
		prog->aux->jit_data = NULL;
	}
1123 1124 1125 1126
out:
	if (tmp_blinded)
		bpf_jit_prog_release_other(prog, prog == orig_prog ?
					   tmp : orig_prog);
1127
	return prog;
Z
Zi Shen Lim 已提交
1128
}
1129 1130 1131 1132 1133

void *bpf_jit_alloc_exec(unsigned long size)
{
	return __vmalloc_node_range(size, PAGE_SIZE, BPF_JIT_REGION_START,
				    BPF_JIT_REGION_END, GFP_KERNEL,
1134
				    PAGE_KERNEL, 0, NUMA_NO_NODE,
1135 1136 1137 1138 1139 1140 1141
				    __builtin_return_address(0));
}

void bpf_jit_free_exec(void *addr)
{
	return vfree(addr);
}