diff options
Diffstat (limited to 'arch/powerpc/kernel/optprobes_head.S')
-rw-r--r-- | arch/powerpc/kernel/optprobes_head.S | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/optprobes_head.S b/arch/powerpc/kernel/optprobes_head.S new file mode 100644 index 0000000000..35932f45fb --- /dev/null +++ b/arch/powerpc/kernel/optprobes_head.S @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Code to prepare detour buffer for optprobes in Kernel. + * + * Copyright 2017, Anju T, IBM Corp. + */ + +#include <asm/ppc_asm.h> +#include <asm/ptrace.h> +#include <asm/asm-offsets.h> + +#ifdef CONFIG_PPC64 +#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base) +#define REST_30GPRS(base) REST_GPRS(2, 31, base) +#define TEMPLATE_FOR_IMM_LOAD_INSNS nop; nop; nop; nop; nop +#else +#define SAVE_30GPRS(base) stmw r2, GPR2(base) +#define REST_30GPRS(base) lmw r2, GPR2(base) +#define TEMPLATE_FOR_IMM_LOAD_INSNS nop; nop; nop +#endif + +#define OPT_SLOT_SIZE 65536 + + .balign 4 + + /* + * Reserve an area to allocate slots for detour buffer. + * This is part of .text section (rather than vmalloc area) + * as this needs to be within 32MB of the probed address. + */ + .global optinsn_slot +optinsn_slot: + .space OPT_SLOT_SIZE + + /* + * Optprobe template: + * This template gets copied into one of the slots in optinsn_slot + * and gets fixed up with real optprobe structures et al. + */ + .global optprobe_template_entry +optprobe_template_entry: + /* Create an in-memory pt_regs */ + PPC_STLU r1,-INT_FRAME_SIZE(r1) + SAVE_GPR(0,r1) + /* Save the previous SP into stack */ + addi r0,r1,INT_FRAME_SIZE + PPC_STL r0,GPR1(r1) + SAVE_30GPRS(r1) + /* Save SPRS */ + mfmsr r5 + PPC_STL r5,_MSR(r1) + li r5,0x700 + PPC_STL r5,_TRAP(r1) + li r5,0 + PPC_STL r5,ORIG_GPR3(r1) + PPC_STL r5,RESULT(r1) + mfctr r5 + PPC_STL r5,_CTR(r1) + mflr r5 + PPC_STL r5,_LINK(r1) + mfspr r5,SPRN_XER + PPC_STL r5,_XER(r1) + mfcr r5 + PPC_STL r5,_CCR(r1) +#ifdef CONFIG_PPC64 + lbz r5,PACAIRQSOFTMASK(r13) + std r5,SOFTE(r1) +#endif + + /* + * We may get here from a module, so load the kernel TOC in r2. + * The original TOC gets restored when pt_regs is restored + * further below. + */ +#ifdef CONFIG_PPC64 + LOAD_PACA_TOC() +#endif + + .global optprobe_template_op_address +optprobe_template_op_address: + /* + * Parameters to optimized_callback(): + * 1. optimized_kprobe structure in r3 + */ + TEMPLATE_FOR_IMM_LOAD_INSNS + + /* 2. pt_regs pointer in r4 */ + addi r4,r1,STACK_INT_FRAME_REGS + + .global optprobe_template_call_handler +optprobe_template_call_handler: + /* Branch to optimized_callback() */ + nop + + /* + * Parameters for instruction emulation: + * 1. Pass SP in register r3. + */ + addi r3,r1,STACK_INT_FRAME_REGS + + .global optprobe_template_insn +optprobe_template_insn: + /* 2, Pass instruction to be emulated in r4 */ + TEMPLATE_FOR_IMM_LOAD_INSNS + + .global optprobe_template_call_emulate +optprobe_template_call_emulate: + /* Branch to emulate_step() */ + nop + + /* + * All done. + * Now, restore the registers... + */ + PPC_LL r5,_MSR(r1) + mtmsr r5 + PPC_LL r5,_CTR(r1) + mtctr r5 + PPC_LL r5,_LINK(r1) + mtlr r5 + PPC_LL r5,_XER(r1) + mtxer r5 + PPC_LL r5,_CCR(r1) + mtcr r5 + REST_GPR(0,r1) + REST_30GPRS(r1) + /* Restore the previous SP */ + addi r1,r1,INT_FRAME_SIZE + + .global optprobe_template_ret +optprobe_template_ret: + /* ... and jump back from trampoline */ + nop + + .global optprobe_template_end +optprobe_template_end: |