123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * eBPF JIT compiler
- *
- * Copyright 2016 Naveen N. Rao <[email protected]>
- * IBM Corporation
- *
- * Based on the powerpc classic BPF JIT compiler by Matt Evans
- */
- #include <linux/moduleloader.h>
- #include <asm/cacheflush.h>
- #include <asm/asm-compat.h>
- #include <linux/netdevice.h>
- #include <linux/filter.h>
- #include <linux/if_vlan.h>
- #include <asm/kprobes.h>
- #include <linux/bpf.h>
- #include "bpf_jit.h"
- static void bpf_jit_fill_ill_insns(void *area, unsigned int size)
- {
- memset32(area, BREAKPOINT_INSTRUCTION, size / 4);
- }
- /* 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, j, ret;
- for (i = 0; i < fp->len; i++) {
- /*
- * During the extra pass, only the branch target addresses for
- * the subprog calls need to be fixed. All other instructions
- * can left untouched.
- *
- * The JITed image length does not change because we already
- * ensure that the JITed instruction sequence for these calls
- * are of fixed length by padding them with NOPs.
- */
- if (insn[i].code == (BPF_JMP | BPF_CALL) &&
- insn[i].src_reg == BPF_PSEUDO_CALL) {
- ret = bpf_jit_get_func_addr(fp, &insn[i], true,
- &func_addr,
- &func_addr_fixed);
- if (ret < 0)
- return ret;
- /*
- * Save ctx->idx as this would currently point to the
- * end of the JITed image and set it to the offset of
- * the instruction sequence corresponding to the
- * subprog call temporarily.
- */
- tmp_idx = ctx->idx;
- ctx->idx = addrs[i] / 4;
- ret = bpf_jit_emit_func_call_rel(image, ctx, func_addr);
- if (ret)
- return ret;
- /*
- * Restore ctx->idx here. This is safe as the length
- * 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(bpf_to_ppc(insn[i].dst_reg) - 1, (u32)insn[i + 1].imm);
- PPC_LI32(bpf_to_ppc(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(bpf_to_ppc(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++;
- }
- }
- return 0;
- }
- int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr)
- {
- if (!exit_addr || is_offset_in_branch_range(exit_addr - (ctx->idx * 4))) {
- PPC_JMP(exit_addr);
- } else if (ctx->alt_exit_addr) {
- if (WARN_ON(!is_offset_in_branch_range((long)ctx->alt_exit_addr - (ctx->idx * 4))))
- return -1;
- PPC_JMP(ctx->alt_exit_addr);
- } else {
- ctx->alt_exit_addr = ctx->idx * 4;
- bpf_jit_build_epilogue(image, ctx);
- }
- return 0;
- }
- struct powerpc64_jit_data {
- struct bpf_binary_header *header;
- u32 *addrs;
- u8 *image;
- u32 proglen;
- struct codegen_context ctx;
- };
- bool bpf_jit_needs_zext(void)
- {
- return true;
- }
- struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
- {
- u32 proglen;
- u32 alloclen;
- u8 *image = NULL;
- u32 *code_base;
- u32 *addrs;
- struct powerpc64_jit_data *jit_data;
- struct codegen_context cgctx;
- int pass;
- int flen;
- struct bpf_binary_header *bpf_hdr;
- struct bpf_prog *org_fp = 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;
- tmp_fp = bpf_jit_blind_constants(org_fp);
- if (IS_ERR(tmp_fp))
- return org_fp;
- if (tmp_fp != org_fp) {
- bpf_blinded = true;
- fp = tmp_fp;
- }
- jit_data = fp->aux->jit_data;
- if (!jit_data) {
- jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL);
- if (!jit_data) {
- fp = org_fp;
- goto out;
- }
- fp->aux->jit_data = jit_data;
- }
- flen = fp->len;
- addrs = jit_data->addrs;
- if (addrs) {
- cgctx = jit_data->ctx;
- image = jit_data->image;
- bpf_hdr = jit_data->header;
- proglen = jit_data->proglen;
- extra_pass = true;
- goto skip_init_ctx;
- }
- addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL);
- if (addrs == NULL) {
- fp = org_fp;
- goto out_addrs;
- }
- memset(&cgctx, 0, sizeof(struct codegen_context));
- bpf_jit_init_reg_mapping(&cgctx);
- /* Make sure that the stack is quadword aligned. */
- cgctx.stack_size = round_up(fp->aux->stack_depth, 16);
- /* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
- /* We hit something illegal or unsupported. */
- fp = org_fp;
- goto out_addrs;
- }
- /*
- * If we have seen a tail call, we need a second pass.
- * This is because bpf_jit_emit_common_epilogue() is called
- * from bpf_jit_emit_tail_call() with a not yet stable ctx->seen.
- * We also need a second pass if we ended up with too large
- * a program so as to ensure BPF_EXIT branches are in range.
- */
- if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
- cgctx.idx = 0;
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
- fp = org_fp;
- goto out_addrs;
- }
- }
- bpf_jit_realloc_regs(&cgctx);
- /*
- * Pretend to build prologue, given the features we've seen. This will
- * update ctgtx.idx as it pretends to output instructions, then we can
- * calculate total size from idx.
- */
- bpf_jit_build_prologue(0, &cgctx);
- addrs[fp->len] = cgctx.idx * 4;
- 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 + fixup_len + extable_len;
- bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, bpf_jit_fill_ill_insns);
- if (!bpf_hdr) {
- fp = org_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);
- if (extra_pass) {
- /*
- * Do not touch the prologue and epilogue as they will remain
- * unchanged. Only fix the branch target address for subprog
- * 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_addresses(fp, code_base, &cgctx, addrs);
- /* There is no need to perform the usual passes. */
- goto skip_codegen_passes;
- }
- /* Code generation passes 1-2 */
- for (pass = 1; pass < 3; pass++) {
- /* Now build the prologue, body code & epilogue for real. */
- cgctx.idx = 0;
- cgctx.alt_exit_addr = 0;
- bpf_jit_build_prologue(code_base, &cgctx);
- if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass)) {
- bpf_jit_binary_free(bpf_hdr);
- fp = org_fp;
- goto out_addrs;
- }
- bpf_jit_build_epilogue(code_base, &cgctx);
- if (bpf_jit_enable > 1)
- pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass,
- proglen - (cgctx.idx * 4), cgctx.seen);
- }
- skip_codegen_passes:
- if (bpf_jit_enable > 1)
- /*
- * Note that we output the base address of the code_base
- * rather than image, since opcodes are in code_base.
- */
- bpf_jit_dump(flen, proglen, pass, code_base);
- #ifdef CONFIG_PPC64_ELF_ABI_V1
- /* Function descriptor nastiness: Address + TOC */
- ((u64 *)image)[0] = (u64)code_base;
- ((u64 *)image)[1] = local_paca->kernel_toc;
- #endif
- fp->bpf_func = (void *)image;
- fp->jited = 1;
- fp->jited_len = proglen + FUNCTION_DESCR_SIZE;
- bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + bpf_hdr->size);
- if (!fp->is_func || extra_pass) {
- bpf_jit_binary_lock_ro(bpf_hdr);
- bpf_prog_fill_jited_linfo(fp, addrs);
- out_addrs:
- kfree(addrs);
- kfree(jit_data);
- fp->aux->jit_data = NULL;
- } else {
- jit_data->addrs = addrs;
- jit_data->ctx = cgctx;
- jit_data->proglen = proglen;
- jit_data->image = image;
- jit_data->header = bpf_hdr;
- }
- out:
- if (bpf_blinded)
- bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp);
- 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;
- }
|