1/*
2 * Code to prepare detour buffer for optprobes in Kernel.
3 *
4 * Copyright 2017, Anju T, IBM Corp.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <asm/ppc_asm.h>
13#include <asm/ptrace.h>
14#include <asm/asm-offsets.h>
15
16#define	OPT_SLOT_SIZE	65536
17
18	.balign	4
19
20	/*
21	 * Reserve an area to allocate slots for detour buffer.
22	 * This is part of .text section (rather than vmalloc area)
23	 * as this needs to be within 32MB of the probed address.
24	 */
25	.global optinsn_slot
26optinsn_slot:
27	.space	OPT_SLOT_SIZE
28
29	/*
30	 * Optprobe template:
31	 * This template gets copied into one of the slots in optinsn_slot
32	 * and gets fixed up with real optprobe structures et al.
33	 */
34	.global optprobe_template_entry
35optprobe_template_entry:
36	/* Create an in-memory pt_regs */
37	stdu	r1,-INT_FRAME_SIZE(r1)
38	SAVE_GPR(0,r1)
39	/* Save the previous SP into stack */
40	addi	r0,r1,INT_FRAME_SIZE
41	std	r0,GPR1(r1)
42	SAVE_10GPRS(2,r1)
43	SAVE_10GPRS(12,r1)
44	SAVE_10GPRS(22,r1)
45	/* Save SPRS */
46	mfmsr	r5
47	std	r5,_MSR(r1)
48	li	r5,0x700
49	std	r5,_TRAP(r1)
50	li	r5,0
51	std	r5,ORIG_GPR3(r1)
52	std	r5,RESULT(r1)
53	mfctr	r5
54	std	r5,_CTR(r1)
55	mflr	r5
56	std	r5,_LINK(r1)
57	mfspr	r5,SPRN_XER
58	std	r5,_XER(r1)
59	mfcr	r5
60	std	r5,_CCR(r1)
61	lbz     r5,PACASOFTIRQEN(r13)
62	std     r5,SOFTE(r1)
63	mfdar	r5
64	std	r5,_DAR(r1)
65	mfdsisr	r5
66	std	r5,_DSISR(r1)
67
68	/*
69	 * We may get here from a module, so load the kernel TOC in r2.
70	 * The original TOC gets restored when pt_regs is restored
71	 * further below.
72	 */
73	ld	r2,PACATOC(r13)
74
75	.global optprobe_template_op_address
76optprobe_template_op_address:
77	/*
78	 * Parameters to optimized_callback():
79	 * 1. optimized_kprobe structure in r3
80	 */
81	nop
82	nop
83	nop
84	nop
85	nop
86	/* 2. pt_regs pointer in r4 */
87	addi	r4,r1,STACK_FRAME_OVERHEAD
88
89	.global optprobe_template_call_handler
90optprobe_template_call_handler:
91	/* Branch to optimized_callback() */
92	nop
93
94	/*
95	 * Parameters for instruction emulation:
96	 * 1. Pass SP in register r3.
97	 */
98	addi	r3,r1,STACK_FRAME_OVERHEAD
99
100	.global optprobe_template_insn
101optprobe_template_insn:
102	/* 2, Pass instruction to be emulated in r4 */
103	nop
104	nop
105
106	.global optprobe_template_call_emulate
107optprobe_template_call_emulate:
108	/* Branch to emulate_step()  */
109	nop
110
111	/*
112	 * All done.
113	 * Now, restore the registers...
114	 */
115	ld	r5,_MSR(r1)
116	mtmsr	r5
117	ld	r5,_CTR(r1)
118	mtctr	r5
119	ld	r5,_LINK(r1)
120	mtlr	r5
121	ld	r5,_XER(r1)
122	mtxer	r5
123	ld	r5,_CCR(r1)
124	mtcr	r5
125	ld	r5,_DAR(r1)
126	mtdar	r5
127	ld	r5,_DSISR(r1)
128	mtdsisr	r5
129	REST_GPR(0,r1)
130	REST_10GPRS(2,r1)
131	REST_10GPRS(12,r1)
132	REST_10GPRS(22,r1)
133	/* Restore the previous SP */
134	addi	r1,r1,INT_FRAME_SIZE
135
136	.global optprobe_template_ret
137optprobe_template_ret:
138	/* ... and jump back from trampoline */
139	nop
140
141	.global optprobe_template_end
142optprobe_template_end:
143