diff options
Diffstat (limited to 'arch/powerpc/net/bpf_jit_comp.c')
| -rw-r--r-- | arch/powerpc/net/bpf_jit_comp.c | 97 | 
1 files changed, 85 insertions, 12 deletions
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index 90ce75f0f1e2..56dd1f4e3e44 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -23,15 +23,15 @@ static void bpf_jit_fill_ill_insns(void *area, unsigned int size)  	memset32(area, BREAKPOINT_INSTRUCTION, size / 4);  } -/* Fix the branch target addresses for subprog calls */ -static int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image, -				       struct codegen_context *ctx, u32 *addrs) +/* Fix updated addresses (for subprog calls, ldimm64, et al) during extra pass */ +static int bpf_jit_fixup_addresses(struct bpf_prog *fp, u32 *image, +				   struct codegen_context *ctx, u32 *addrs)  {  	const struct bpf_insn *insn = fp->insnsi;  	bool func_addr_fixed;  	u64 func_addr;  	u32 tmp_idx; -	int i, ret; +	int i, j, ret;  	for (i = 0; i < fp->len; i++) {  		/* @@ -66,6 +66,23 @@ static int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image,  			 * of the JITed sequence remains unchanged.  			 */  			ctx->idx = tmp_idx; +		} else if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW)) { +			tmp_idx = ctx->idx; +			ctx->idx = addrs[i] / 4; +#ifdef CONFIG_PPC32 +			PPC_LI32(ctx->b2p[insn[i].dst_reg] - 1, (u32)insn[i + 1].imm); +			PPC_LI32(ctx->b2p[insn[i].dst_reg], (u32)insn[i].imm); +			for (j = ctx->idx - addrs[i] / 4; j < 4; j++) +				EMIT(PPC_RAW_NOP()); +#else +			func_addr = ((u64)(u32)insn[i].imm) | (((u64)(u32)insn[i + 1].imm) << 32); +			PPC_LI64(b2p[insn[i].dst_reg], func_addr); +			/* overwrite rest with nops */ +			for (j = ctx->idx - addrs[i] / 4; j < 5; j++) +				EMIT(PPC_RAW_NOP()); +#endif +			ctx->idx = tmp_idx; +			i++;  		}  	} @@ -101,6 +118,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)  	struct bpf_prog *tmp_fp;  	bool bpf_blinded = false;  	bool extra_pass = false; +	u32 extable_len; +	u32 fixup_len;  	if (!fp->jit_requested)  		return org_fp; @@ -131,7 +150,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)  		image = jit_data->image;  		bpf_hdr = jit_data->header;  		proglen = jit_data->proglen; -		alloclen = proglen + FUNCTION_DESCR_SIZE;  		extra_pass = true;  		goto skip_init_ctx;  	} @@ -149,7 +167,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)  	cgctx.stack_size = round_up(fp->aux->stack_depth, 16);  	/* Scouting faux-generate pass 0 */ -	if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) { +	if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {  		/* We hit something illegal or unsupported. */  		fp = org_fp;  		goto out_addrs; @@ -162,7 +180,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)  	 */  	if (cgctx.seen & SEEN_TAILCALL) {  		cgctx.idx = 0; -		if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) { +		if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {  			fp = org_fp;  			goto out_addrs;  		} @@ -177,8 +195,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)  	bpf_jit_build_prologue(0, &cgctx);  	bpf_jit_build_epilogue(0, &cgctx); +	fixup_len = fp->aux->num_exentries * BPF_FIXUP_LEN * 4; +	extable_len = fp->aux->num_exentries * sizeof(struct exception_table_entry); +  	proglen = cgctx.idx * 4; -	alloclen = proglen + FUNCTION_DESCR_SIZE; +	alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len;  	bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, bpf_jit_fill_ill_insns);  	if (!bpf_hdr) { @@ -186,6 +207,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)  		goto out_addrs;  	} +	if (extable_len) +		fp->aux->extable = (void *)image + FUNCTION_DESCR_SIZE + proglen + fixup_len; +  skip_init_ctx:  	code_base = (u32 *)(image + FUNCTION_DESCR_SIZE); @@ -193,13 +217,13 @@ skip_init_ctx:  		/*  		 * Do not touch the prologue and epilogue as they will remain  		 * unchanged. Only fix the branch target address for subprog -		 * calls in the body. +		 * calls in the body, and ldimm64 instructions.  		 *  		 * This does not change the offsets and lengths of the subprog  		 * call instruction sequences and hence, the size of the JITed  		 * image as well.  		 */ -		bpf_jit_fixup_subprog_calls(fp, code_base, &cgctx, addrs); +		bpf_jit_fixup_addresses(fp, code_base, &cgctx, addrs);  		/* There is no need to perform the usual passes. */  		goto skip_codegen_passes; @@ -210,7 +234,7 @@ skip_init_ctx:  		/* Now build the prologue, body code & epilogue for real. */  		cgctx.idx = 0;  		bpf_jit_build_prologue(code_base, &cgctx); -		if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, extra_pass)) { +		if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass)) {  			bpf_jit_binary_free(bpf_hdr);  			fp = org_fp;  			goto out_addrs; @@ -238,7 +262,7 @@ skip_codegen_passes:  	fp->bpf_func = (void *)image;  	fp->jited = 1; -	fp->jited_len = alloclen; +	fp->jited_len = proglen + FUNCTION_DESCR_SIZE;  	bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE));  	if (!fp->is_func || extra_pass) { @@ -262,3 +286,52 @@ out:  	return fp;  } + +/* + * The caller should check for (BPF_MODE(code) == BPF_PROBE_MEM) before calling + * this function, as this only applies to BPF_PROBE_MEM, for now. + */ +int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct codegen_context *ctx, +			  int insn_idx, int jmp_off, int dst_reg) +{ +	off_t offset; +	unsigned long pc; +	struct exception_table_entry *ex; +	u32 *fixup; + +	/* Populate extable entries only in the last pass */ +	if (pass != 2) +		return 0; + +	if (!fp->aux->extable || +	    WARN_ON_ONCE(ctx->exentry_idx >= fp->aux->num_exentries)) +		return -EINVAL; + +	pc = (unsigned long)&image[insn_idx]; + +	fixup = (void *)fp->aux->extable - +		(fp->aux->num_exentries * BPF_FIXUP_LEN * 4) + +		(ctx->exentry_idx * BPF_FIXUP_LEN * 4); + +	fixup[0] = PPC_RAW_LI(dst_reg, 0); +	if (IS_ENABLED(CONFIG_PPC32)) +		fixup[1] = PPC_RAW_LI(dst_reg - 1, 0); /* clear higher 32-bit register too */ + +	fixup[BPF_FIXUP_LEN - 1] = +		PPC_RAW_BRANCH((long)(pc + jmp_off) - (long)&fixup[BPF_FIXUP_LEN - 1]); + +	ex = &fp->aux->extable[ctx->exentry_idx]; + +	offset = pc - (long)&ex->insn; +	if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) +		return -ERANGE; +	ex->insn = offset; + +	offset = (long)fixup - (long)&ex->fixup; +	if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) +		return -ERANGE; +	ex->fixup = offset; + +	ctx->exentry_idx++; +	return 0; +}  |