162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * eBPF JIT compiler 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2016 Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> 662306a36Sopenharmony_ci * IBM Corporation 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on the powerpc classic BPF JIT compiler by Matt Evans 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/moduleloader.h> 1162306a36Sopenharmony_ci#include <asm/cacheflush.h> 1262306a36Sopenharmony_ci#include <asm/asm-compat.h> 1362306a36Sopenharmony_ci#include <linux/netdevice.h> 1462306a36Sopenharmony_ci#include <linux/filter.h> 1562306a36Sopenharmony_ci#include <linux/if_vlan.h> 1662306a36Sopenharmony_ci#include <asm/kprobes.h> 1762306a36Sopenharmony_ci#include <linux/bpf.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "bpf_jit.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void bpf_jit_fill_ill_insns(void *area, unsigned int size) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci memset32(area, BREAKPOINT_INSTRUCTION, size / 4); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci if (!exit_addr || is_offset_in_branch_range(exit_addr - (ctx->idx * 4))) { 2962306a36Sopenharmony_ci PPC_JMP(exit_addr); 3062306a36Sopenharmony_ci } else if (ctx->alt_exit_addr) { 3162306a36Sopenharmony_ci if (WARN_ON(!is_offset_in_branch_range((long)ctx->alt_exit_addr - (ctx->idx * 4)))) 3262306a36Sopenharmony_ci return -1; 3362306a36Sopenharmony_ci PPC_JMP(ctx->alt_exit_addr); 3462306a36Sopenharmony_ci } else { 3562306a36Sopenharmony_ci ctx->alt_exit_addr = ctx->idx * 4; 3662306a36Sopenharmony_ci bpf_jit_build_epilogue(image, ctx); 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct powerpc64_jit_data { 4362306a36Sopenharmony_ci struct bpf_binary_header *header; 4462306a36Sopenharmony_ci u32 *addrs; 4562306a36Sopenharmony_ci u8 *image; 4662306a36Sopenharmony_ci u32 proglen; 4762306a36Sopenharmony_ci struct codegen_context ctx; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cibool bpf_jit_needs_zext(void) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return true; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci u32 proglen; 5862306a36Sopenharmony_ci u32 alloclen; 5962306a36Sopenharmony_ci u8 *image = NULL; 6062306a36Sopenharmony_ci u32 *code_base; 6162306a36Sopenharmony_ci u32 *addrs; 6262306a36Sopenharmony_ci struct powerpc64_jit_data *jit_data; 6362306a36Sopenharmony_ci struct codegen_context cgctx; 6462306a36Sopenharmony_ci int pass; 6562306a36Sopenharmony_ci int flen; 6662306a36Sopenharmony_ci struct bpf_binary_header *bpf_hdr; 6762306a36Sopenharmony_ci struct bpf_prog *org_fp = fp; 6862306a36Sopenharmony_ci struct bpf_prog *tmp_fp; 6962306a36Sopenharmony_ci bool bpf_blinded = false; 7062306a36Sopenharmony_ci bool extra_pass = false; 7162306a36Sopenharmony_ci u32 extable_len; 7262306a36Sopenharmony_ci u32 fixup_len; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!fp->jit_requested) 7562306a36Sopenharmony_ci return org_fp; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci tmp_fp = bpf_jit_blind_constants(org_fp); 7862306a36Sopenharmony_ci if (IS_ERR(tmp_fp)) 7962306a36Sopenharmony_ci return org_fp; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (tmp_fp != org_fp) { 8262306a36Sopenharmony_ci bpf_blinded = true; 8362306a36Sopenharmony_ci fp = tmp_fp; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci jit_data = fp->aux->jit_data; 8762306a36Sopenharmony_ci if (!jit_data) { 8862306a36Sopenharmony_ci jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL); 8962306a36Sopenharmony_ci if (!jit_data) { 9062306a36Sopenharmony_ci fp = org_fp; 9162306a36Sopenharmony_ci goto out; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci fp->aux->jit_data = jit_data; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci flen = fp->len; 9762306a36Sopenharmony_ci addrs = jit_data->addrs; 9862306a36Sopenharmony_ci if (addrs) { 9962306a36Sopenharmony_ci cgctx = jit_data->ctx; 10062306a36Sopenharmony_ci image = jit_data->image; 10162306a36Sopenharmony_ci bpf_hdr = jit_data->header; 10262306a36Sopenharmony_ci proglen = jit_data->proglen; 10362306a36Sopenharmony_ci extra_pass = true; 10462306a36Sopenharmony_ci /* During extra pass, ensure index is reset before repopulating extable entries */ 10562306a36Sopenharmony_ci cgctx.exentry_idx = 0; 10662306a36Sopenharmony_ci goto skip_init_ctx; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL); 11062306a36Sopenharmony_ci if (addrs == NULL) { 11162306a36Sopenharmony_ci fp = org_fp; 11262306a36Sopenharmony_ci goto out_addrs; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci memset(&cgctx, 0, sizeof(struct codegen_context)); 11662306a36Sopenharmony_ci bpf_jit_init_reg_mapping(&cgctx); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Make sure that the stack is quadword aligned. */ 11962306a36Sopenharmony_ci cgctx.stack_size = round_up(fp->aux->stack_depth, 16); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* Scouting faux-generate pass 0 */ 12262306a36Sopenharmony_ci if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0, false)) { 12362306a36Sopenharmony_ci /* We hit something illegal or unsupported. */ 12462306a36Sopenharmony_ci fp = org_fp; 12562306a36Sopenharmony_ci goto out_addrs; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* 12962306a36Sopenharmony_ci * If we have seen a tail call, we need a second pass. 13062306a36Sopenharmony_ci * This is because bpf_jit_emit_common_epilogue() is called 13162306a36Sopenharmony_ci * from bpf_jit_emit_tail_call() with a not yet stable ctx->seen. 13262306a36Sopenharmony_ci * We also need a second pass if we ended up with too large 13362306a36Sopenharmony_ci * a program so as to ensure BPF_EXIT branches are in range. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) { 13662306a36Sopenharmony_ci cgctx.idx = 0; 13762306a36Sopenharmony_ci if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0, false)) { 13862306a36Sopenharmony_ci fp = org_fp; 13962306a36Sopenharmony_ci goto out_addrs; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci bpf_jit_realloc_regs(&cgctx); 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * Pretend to build prologue, given the features we've seen. This will 14662306a36Sopenharmony_ci * update ctgtx.idx as it pretends to output instructions, then we can 14762306a36Sopenharmony_ci * calculate total size from idx. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci bpf_jit_build_prologue(0, &cgctx); 15062306a36Sopenharmony_ci addrs[fp->len] = cgctx.idx * 4; 15162306a36Sopenharmony_ci bpf_jit_build_epilogue(0, &cgctx); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci fixup_len = fp->aux->num_exentries * BPF_FIXUP_LEN * 4; 15462306a36Sopenharmony_ci extable_len = fp->aux->num_exentries * sizeof(struct exception_table_entry); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci proglen = cgctx.idx * 4; 15762306a36Sopenharmony_ci alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, bpf_jit_fill_ill_insns); 16062306a36Sopenharmony_ci if (!bpf_hdr) { 16162306a36Sopenharmony_ci fp = org_fp; 16262306a36Sopenharmony_ci goto out_addrs; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (extable_len) 16662306a36Sopenharmony_ci fp->aux->extable = (void *)image + FUNCTION_DESCR_SIZE + proglen + fixup_len; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciskip_init_ctx: 16962306a36Sopenharmony_ci code_base = (u32 *)(image + FUNCTION_DESCR_SIZE); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Code generation passes 1-2 */ 17262306a36Sopenharmony_ci for (pass = 1; pass < 3; pass++) { 17362306a36Sopenharmony_ci /* Now build the prologue, body code & epilogue for real. */ 17462306a36Sopenharmony_ci cgctx.idx = 0; 17562306a36Sopenharmony_ci cgctx.alt_exit_addr = 0; 17662306a36Sopenharmony_ci bpf_jit_build_prologue(code_base, &cgctx); 17762306a36Sopenharmony_ci if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass, extra_pass)) { 17862306a36Sopenharmony_ci bpf_jit_binary_free(bpf_hdr); 17962306a36Sopenharmony_ci fp = org_fp; 18062306a36Sopenharmony_ci goto out_addrs; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci bpf_jit_build_epilogue(code_base, &cgctx); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (bpf_jit_enable > 1) 18562306a36Sopenharmony_ci pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass, 18662306a36Sopenharmony_ci proglen - (cgctx.idx * 4), cgctx.seen); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (bpf_jit_enable > 1) 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Note that we output the base address of the code_base 19262306a36Sopenharmony_ci * rather than image, since opcodes are in code_base. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci bpf_jit_dump(flen, proglen, pass, code_base); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#ifdef CONFIG_PPC64_ELF_ABI_V1 19762306a36Sopenharmony_ci /* Function descriptor nastiness: Address + TOC */ 19862306a36Sopenharmony_ci ((u64 *)image)[0] = (u64)code_base; 19962306a36Sopenharmony_ci ((u64 *)image)[1] = local_paca->kernel_toc; 20062306a36Sopenharmony_ci#endif 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci fp->bpf_func = (void *)image; 20362306a36Sopenharmony_ci fp->jited = 1; 20462306a36Sopenharmony_ci fp->jited_len = proglen + FUNCTION_DESCR_SIZE; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + bpf_hdr->size); 20762306a36Sopenharmony_ci if (!fp->is_func || extra_pass) { 20862306a36Sopenharmony_ci bpf_jit_binary_lock_ro(bpf_hdr); 20962306a36Sopenharmony_ci bpf_prog_fill_jited_linfo(fp, addrs); 21062306a36Sopenharmony_ciout_addrs: 21162306a36Sopenharmony_ci kfree(addrs); 21262306a36Sopenharmony_ci kfree(jit_data); 21362306a36Sopenharmony_ci fp->aux->jit_data = NULL; 21462306a36Sopenharmony_ci } else { 21562306a36Sopenharmony_ci jit_data->addrs = addrs; 21662306a36Sopenharmony_ci jit_data->ctx = cgctx; 21762306a36Sopenharmony_ci jit_data->proglen = proglen; 21862306a36Sopenharmony_ci jit_data->image = image; 21962306a36Sopenharmony_ci jit_data->header = bpf_hdr; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciout: 22362306a36Sopenharmony_ci if (bpf_blinded) 22462306a36Sopenharmony_ci bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return fp; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* 23062306a36Sopenharmony_ci * The caller should check for (BPF_MODE(code) == BPF_PROBE_MEM) before calling 23162306a36Sopenharmony_ci * this function, as this only applies to BPF_PROBE_MEM, for now. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ciint bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct codegen_context *ctx, 23462306a36Sopenharmony_ci int insn_idx, int jmp_off, int dst_reg) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci off_t offset; 23762306a36Sopenharmony_ci unsigned long pc; 23862306a36Sopenharmony_ci struct exception_table_entry *ex; 23962306a36Sopenharmony_ci u32 *fixup; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* Populate extable entries only in the last pass */ 24262306a36Sopenharmony_ci if (pass != 2) 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!fp->aux->extable || 24662306a36Sopenharmony_ci WARN_ON_ONCE(ctx->exentry_idx >= fp->aux->num_exentries)) 24762306a36Sopenharmony_ci return -EINVAL; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci pc = (unsigned long)&image[insn_idx]; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci fixup = (void *)fp->aux->extable - 25262306a36Sopenharmony_ci (fp->aux->num_exentries * BPF_FIXUP_LEN * 4) + 25362306a36Sopenharmony_ci (ctx->exentry_idx * BPF_FIXUP_LEN * 4); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci fixup[0] = PPC_RAW_LI(dst_reg, 0); 25662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PPC32)) 25762306a36Sopenharmony_ci fixup[1] = PPC_RAW_LI(dst_reg - 1, 0); /* clear higher 32-bit register too */ 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci fixup[BPF_FIXUP_LEN - 1] = 26062306a36Sopenharmony_ci PPC_RAW_BRANCH((long)(pc + jmp_off) - (long)&fixup[BPF_FIXUP_LEN - 1]); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci ex = &fp->aux->extable[ctx->exentry_idx]; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci offset = pc - (long)&ex->insn; 26562306a36Sopenharmony_ci if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) 26662306a36Sopenharmony_ci return -ERANGE; 26762306a36Sopenharmony_ci ex->insn = offset; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci offset = (long)fixup - (long)&ex->fixup; 27062306a36Sopenharmony_ci if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) 27162306a36Sopenharmony_ci return -ERANGE; 27262306a36Sopenharmony_ci ex->fixup = offset; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ctx->exentry_idx++; 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 277