Re: [PATCH RFC 1/6] perf/x86: Add perf text poke event

From: Peter Zijlstra
Date: Fri Nov 01 2019 - 06:09:14 EST


On Fri, Nov 01, 2019 at 11:04:40AM +0100, Peter Zijlstra wrote:

> I'm thinking something along the lines of:
>
> static uintptr_t nosync_addr;
> static u32 nosync_insn;
>
> int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn)
> {
> const u32 break = // some_breakpoint_insn;
> uintptr_t tp = (uintptr_t)addr;
> int ret;
>
> lockdep_assert_held(&text_mutex);
>
> /* A64 instructions must be word aligned */
> if (tp & 0x3)
> return -EINVAL;
>
> if (perf_text_poke_update_enabled()) {
>
> nosync_insn = insn;
> smp_store_release(&nosync_addr, tp);
>
> ret = aarch64_insn_write(addr, break);
> if (ret == 0)
> __flush_icache_range(tp, tp + AARCH64_INSN_SIZE);
>
> perf_event_text_poke(....);
> }
>
> ret = aarch64_insn_write(addr, insn);
> if (ret == 0)
> __flush_icache_range(tp, tp + AARCH64_INSN_SIZE);

// barrier that guarantees iflush completion ? dsb(osh) ?

WRITE_ONCE(nosync_addr, NULL);

> return ret;
> }
>
> And have the 'break' handler do:
>
> aarch64_insn_break_handler(struct pt_regs *regs)
> {
> unsigned long addr = smp_load_acquire(&nosync_addr);
> u32 insn = nosync_insn;
>
> if (regs->ip != addr)
> return;
>
> // emulate @insn
> }
>
> I understood from Will the whole nosync scheme only works for a limited
> set of instructions, but you only have to implement emulation for the
> actual instructions used of course.
>
> (which is what we do on x86)
>
> Does this sound workable?