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