| /* | 
 |  * 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) | 
 | 	mfdar	r5 | 
 | 	std	r5,_DAR(r1) | 
 | 	mfdsisr	r5 | 
 | 	std	r5,_DSISR(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 | 
 | 	ld	r5,_DAR(r1) | 
 | 	mtdar	r5 | 
 | 	ld	r5,_DSISR(r1) | 
 | 	mtdsisr	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: |