| /* 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: |