| /* | |
| * Code to prepare detour buffer for optprobes in Kernel. | |
| * | |
| * Copyright 2017, Anju T, IBM Corp. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License | |
| * as published by the Free Software Foundation; either version | |
| * 2 of the License, or (at your option) any later version. | |
| */ | |
| #include <asm/ppc_asm.h> | |
| #include <asm/ptrace.h> | |
| #include <asm/asm-offsets.h> | |
| #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 */ | |
| stdu r1,-INT_FRAME_SIZE(r1) | |
| SAVE_GPR(0,r1) | |
| /* Save the previous SP into stack */ | |
| addi r0,r1,INT_FRAME_SIZE | |
| std r0,GPR1(r1) | |
| SAVE_10GPRS(2,r1) | |
| SAVE_10GPRS(12,r1) | |
| SAVE_10GPRS(22,r1) | |
| /* Save SPRS */ | |
| mfmsr r5 | |
| std r5,_MSR(r1) | |
| li r5,0x700 | |
| std r5,_TRAP(r1) | |
| li r5,0 | |
| std r5,ORIG_GPR3(r1) | |
| std r5,RESULT(r1) | |
| mfctr r5 | |
| std r5,_CTR(r1) | |
| mflr r5 | |
| std r5,_LINK(r1) | |
| mfspr r5,SPRN_XER | |
| std r5,_XER(r1) | |
| mfcr r5 | |
| std r5,_CCR(r1) | |
| lbz r5,PACASOFTIRQEN(r13) | |
| std r5,SOFTE(r1) | |
| /* | |
| * 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. | |
| */ | |
| ld r2,PACATOC(r13) | |
| .global optprobe_template_op_address | |
| optprobe_template_op_address: | |
| /* | |
| * Parameters to optimized_callback(): | |
| * 1. optimized_kprobe structure in r3 | |
| */ | |
| nop | |
| nop | |
| nop | |
| nop | |
| nop | |
| /* 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 */ | |
| nop | |
| nop | |
| .global optprobe_template_call_emulate | |
| optprobe_template_call_emulate: | |
| /* Branch to emulate_step() */ | |
| nop | |
| /* | |
| * All done. | |
| * Now, restore the registers... | |
| */ | |
| ld r5,_MSR(r1) | |
| mtmsr r5 | |
| ld r5,_CTR(r1) | |
| mtctr r5 | |
| ld r5,_LINK(r1) | |
| mtlr r5 | |
| ld r5,_XER(r1) | |
| mtxer r5 | |
| ld r5,_CCR(r1) | |
| mtcr r5 | |
| REST_GPR(0,r1) | |
| REST_10GPRS(2,r1) | |
| REST_10GPRS(12,r1) | |
| REST_10GPRS(22,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: |