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#ifdef CONFIG_PPC64
13#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base)
14#define REST_30GPRS(base) REST_GPRS(2, 31, base)
15#define TEMPLATE_FOR_IMM_LOAD_INSNS	nop; nop; nop; nop; nop
16#else
17#define SAVE_30GPRS(base) stmw	r2, GPR2(base)
18#define REST_30GPRS(base) lmw	r2, GPR2(base)
19#define TEMPLATE_FOR_IMM_LOAD_INSNS	nop; nop; nop
20#endif
21
22#define	OPT_SLOT_SIZE	65536
23
24	.balign	4
25
26	/*
27	 * Reserve an area to allocate slots for detour buffer.
28	 * This is part of .text section (rather than vmalloc area)
29	 * as this needs to be within 32MB of the probed address.
30	 */
31	.global optinsn_slot
32optinsn_slot:
33	.space	OPT_SLOT_SIZE
34
35	/*
36	 * Optprobe template:
37	 * This template gets copied into one of the slots in optinsn_slot
38	 * and gets fixed up with real optprobe structures et al.
39	 */
40	.global optprobe_template_entry
41optprobe_template_entry:
42	/* Create an in-memory pt_regs */
43	PPC_STLU	r1,-INT_FRAME_SIZE(r1)
44	SAVE_GPR(0,r1)
45	/* Save the previous SP into stack */
46	addi	r0,r1,INT_FRAME_SIZE
47	PPC_STL	r0,GPR1(r1)
48	SAVE_30GPRS(r1)
49	/* Save SPRS */
50	mfmsr	r5
51	PPC_STL	r5,_MSR(r1)
52	li	r5,0x700
53	PPC_STL	r5,_TRAP(r1)
54	li	r5,0
55	PPC_STL	r5,ORIG_GPR3(r1)
56	PPC_STL	r5,RESULT(r1)
57	mfctr	r5
58	PPC_STL	r5,_CTR(r1)
59	mflr	r5
60	PPC_STL	r5,_LINK(r1)
61	mfspr	r5,SPRN_XER
62	PPC_STL	r5,_XER(r1)
63	mfcr	r5
64	PPC_STL	r5,_CCR(r1)
65#ifdef CONFIG_PPC64
66	lbz     r5,PACAIRQSOFTMASK(r13)
67	std     r5,SOFTE(r1)
68#endif
69
70	/*
71	 * We may get here from a module, so load the kernel TOC in r2.
72	 * The original TOC gets restored when pt_regs is restored
73	 * further below.
74	 */
75#ifdef CONFIG_PPC64
76	ld	r2,PACATOC(r13)
77#endif
78
79	.global optprobe_template_op_address
80optprobe_template_op_address:
81	/*
82	 * Parameters to optimized_callback():
83	 * 1. optimized_kprobe structure in r3
84	 */
85	TEMPLATE_FOR_IMM_LOAD_INSNS
86
87	/* 2. pt_regs pointer in r4 */
88	addi	r4,r1,STACK_FRAME_OVERHEAD
89
90	.global optprobe_template_call_handler
91optprobe_template_call_handler:
92	/* Branch to optimized_callback() */
93	nop
94
95	/*
96	 * Parameters for instruction emulation:
97	 * 1. Pass SP in register r3.
98	 */
99	addi	r3,r1,STACK_FRAME_OVERHEAD
100
101	.global optprobe_template_insn
102optprobe_template_insn:
103	/* 2, Pass instruction to be emulated in r4 */
104	TEMPLATE_FOR_IMM_LOAD_INSNS
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	PPC_LL	r5,_MSR(r1)
116	mtmsr	r5
117	PPC_LL	r5,_CTR(r1)
118	mtctr	r5
119	PPC_LL	r5,_LINK(r1)
120	mtlr	r5
121	PPC_LL	r5,_XER(r1)
122	mtxer	r5
123	PPC_LL	r5,_CCR(r1)
124	mtcr	r5
125	REST_GPR(0,r1)
126	REST_30GPRS(r1)
127	/* Restore the previous SP */
128	addi	r1,r1,INT_FRAME_SIZE
129
130	.global optprobe_template_ret
131optprobe_template_ret:
132	/* ... and jump back from trampoline */
133	nop
134
135	.global optprobe_template_end
136optprobe_template_end:
137