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