|  | /* | 
|  | * 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,PACAIRQSOFTMASK(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: |