Skip to content

Commit

Permalink
From patchwork series 372260
Browse files Browse the repository at this point in the history
  • Loading branch information
Fox Snowpatch committed Sep 8, 2023
1 parent d774975 commit e92c9b3
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 63 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/include/asm/code-patching.h
Expand Up @@ -74,6 +74,7 @@ int create_cond_branch(ppc_inst_t *instr, const u32 *addr,
int patch_branch(u32 *addr, unsigned long target, int flags);
int patch_instruction(u32 *addr, ppc_inst_t instr);
int raw_patch_instruction(u32 *addr, ppc_inst_t instr);
int patch_instructions(void *addr, void *code, size_t len, bool fill_insn);

static inline unsigned long patch_site_addr(s32 *site)
{
Expand Down
94 changes: 79 additions & 15 deletions arch/powerpc/lib/code-patching.c
Expand Up @@ -278,20 +278,25 @@ static void unmap_patch_area(unsigned long addr)
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
}

static int __do_patch_instruction_mm(u32 *addr, ppc_inst_t instr)
/*
* A page is mapped and instructions that fit the page are patched.
* Assumes 'len' to be (PAGE_SIZE - offset_in_page(addr)) or below.
*/
static int __do_patch_instructions_mm(u32 *addr, void *code, size_t len, bool fill_insn)
{
int err;
u32 *patch_addr;
unsigned long text_poke_addr;
pte_t *pte;
unsigned long pfn = get_patch_pfn(addr);
struct mm_struct *patching_mm;
struct mm_struct *orig_mm;
ppc_inst_t instr;
void *patch_addr;
spinlock_t *ptl;
int ilen, err;

patching_mm = __this_cpu_read(cpu_patching_context.mm);
text_poke_addr = __this_cpu_read(cpu_patching_context.addr);
patch_addr = (u32 *)(text_poke_addr + offset_in_page(addr));
patch_addr = (void *)(text_poke_addr + offset_in_page(addr));

pte = get_locked_pte(patching_mm, text_poke_addr, &ptl);
if (!pte)
Expand All @@ -307,11 +312,22 @@ static int __do_patch_instruction_mm(u32 *addr, ppc_inst_t instr)

orig_mm = start_using_temp_mm(patching_mm);

err = __patch_instruction(addr, instr, patch_addr);
while (len > 0) {
instr = ppc_inst_read(code);
ilen = ppc_inst_len(instr);
err = __patch_instruction(addr, instr, patch_addr);
/* hwsync performed by __patch_instruction (sync) if successful */
if (err) {
mb(); /* sync */
break;
}

/* hwsync performed by __patch_instruction (sync) if successful */
if (err)
mb(); /* sync */
len -= ilen;
patch_addr = patch_addr + ilen;
addr = (void *)addr + ilen;
if (!fill_insn)
code = code + ilen;
}

/* context synchronisation performed by __patch_instruction (isync or exception) */
stop_using_temp_mm(patching_mm, orig_mm);
Expand All @@ -328,24 +344,41 @@ static int __do_patch_instruction_mm(u32 *addr, ppc_inst_t instr)
return err;
}

static int __do_patch_instruction(u32 *addr, ppc_inst_t instr)
/*
* A page is mapped and instructions that fit the page are patched.
* Assumes 'len' to be (PAGE_SIZE - offset_in_page(addr)) or below.
*/
static int __do_patch_instructions(u32 *addr, void *code, size_t len, bool fill_insn)
{
int err;
u32 *patch_addr;
unsigned long text_poke_addr;
pte_t *pte;
unsigned long pfn = get_patch_pfn(addr);
void *patch_addr;
ppc_inst_t instr;
int ilen, err;

text_poke_addr = (unsigned long)__this_cpu_read(cpu_patching_context.addr) & PAGE_MASK;
patch_addr = (u32 *)(text_poke_addr + offset_in_page(addr));
patch_addr = (void *)(text_poke_addr + offset_in_page(addr));

pte = __this_cpu_read(cpu_patching_context.pte);
__set_pte_at(&init_mm, text_poke_addr, pte, pfn_pte(pfn, PAGE_KERNEL), 0);
/* See ptesync comment in radix__set_pte_at() */
if (radix_enabled())
asm volatile("ptesync": : :"memory");

err = __patch_instruction(addr, instr, patch_addr);
while (len > 0) {
instr = ppc_inst_read(code);
ilen = ppc_inst_len(instr);
err = __patch_instruction(addr, instr, patch_addr);
if (err)
break;

len -= ilen;
patch_addr = patch_addr + ilen;
addr = (void *)addr + ilen;
if (!fill_insn)
code = code + ilen;
}

pte_clear(&init_mm, text_poke_addr, pte);
flush_tlb_kernel_range(text_poke_addr, text_poke_addr + PAGE_SIZE);
Expand All @@ -369,15 +402,46 @@ int patch_instruction(u32 *addr, ppc_inst_t instr)

local_irq_save(flags);
if (mm_patch_enabled())
err = __do_patch_instruction_mm(addr, instr);
err = __do_patch_instructions_mm(addr, &instr, ppc_inst_len(instr), false);
else
err = __do_patch_instruction(addr, instr);
err = __do_patch_instructions(addr, &instr, ppc_inst_len(instr), false);
local_irq_restore(flags);

return err;
}
NOKPROBE_SYMBOL(patch_instruction);

/*
* Patch 'addr' with 'len' bytes of instructions from 'code'.
*/
int patch_instructions(void *addr, void *code, size_t len, bool fill_insn)
{
unsigned long flags;
size_t plen;
int err;

while (len > 0) {
plen = min_t(size_t, PAGE_SIZE - offset_in_page(addr), len);

local_irq_save(flags);
if (mm_patch_enabled())
err = __do_patch_instructions_mm(addr, code, plen, fill_insn);
else
err = __do_patch_instructions(addr, code, plen, fill_insn);
local_irq_restore(flags);
if (err)
break;

len -= plen;
addr = addr + plen;
if (!fill_insn)
code = code + plen;
}

return err;
}
NOKPROBE_SYMBOL(patch_instructions);

int patch_branch(u32 *addr, unsigned long target, int flags)
{
ppc_inst_t instr;
Expand Down
12 changes: 5 additions & 7 deletions arch/powerpc/net/bpf_jit.h
Expand Up @@ -36,9 +36,6 @@
EMIT(PPC_RAW_BRANCH(offset)); \
} while (0)

/* bl (unconditional 'branch' with link) */
#define PPC_BL(dest) EMIT(PPC_RAW_BL((dest) - (unsigned long)(image + ctx->idx)))

/* "cond" here covers BO:BI fields. */
#define PPC_BCC_SHORT(cond, dest) \
do { \
Expand Down Expand Up @@ -169,16 +166,17 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
}

void bpf_jit_init_reg_mapping(struct codegen_context *ctx);
int bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,
u32 *addrs, int pass, bool extra_pass);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
void bpf_jit_realloc_regs(struct codegen_context *ctx);
int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr);

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);
int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, u32 *fimage, int pass,
struct codegen_context *ctx, int insn_idx,
int jmp_off, int dst_reg);

#endif

Expand Down

0 comments on commit e92c9b3

Please sign in to comment.