summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/optprobes_head.S
blob: 35932f45fb4ecb6190303619993517e8a2438c76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Code to prepare detour buffer for optprobes in Kernel.
 *
 * Copyright 2017, Anju T, IBM Corp.
 */

#include <asm/ppc_asm.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>

#ifdef CONFIG_PPC64
#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base)
#define REST_30GPRS(base) REST_GPRS(2, 31, base)
#define TEMPLATE_FOR_IMM_LOAD_INSNS	nop; nop; nop; nop; nop
#else
#define SAVE_30GPRS(base) stmw	r2, GPR2(base)
#define REST_30GPRS(base) lmw	r2, GPR2(base)
#define TEMPLATE_FOR_IMM_LOAD_INSNS	nop; nop; nop
#endif

#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 */
	PPC_STLU	r1,-INT_FRAME_SIZE(r1)
	SAVE_GPR(0,r1)
	/* Save the previous SP into stack */
	addi	r0,r1,INT_FRAME_SIZE
	PPC_STL	r0,GPR1(r1)
	SAVE_30GPRS(r1)
	/* Save SPRS */
	mfmsr	r5
	PPC_STL	r5,_MSR(r1)
	li	r5,0x700
	PPC_STL	r5,_TRAP(r1)
	li	r5,0
	PPC_STL	r5,ORIG_GPR3(r1)
	PPC_STL	r5,RESULT(r1)
	mfctr	r5
	PPC_STL	r5,_CTR(r1)
	mflr	r5
	PPC_STL	r5,_LINK(r1)
	mfspr	r5,SPRN_XER
	PPC_STL	r5,_XER(r1)
	mfcr	r5
	PPC_STL	r5,_CCR(r1)
#ifdef CONFIG_PPC64
	lbz     r5,PACAIRQSOFTMASK(r13)
	std     r5,SOFTE(r1)
#endif

	/*
	 * 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.
	 */
#ifdef CONFIG_PPC64
	LOAD_PACA_TOC()
#endif

	.global optprobe_template_op_address
optprobe_template_op_address:
	/*
	 * Parameters to optimized_callback():
	 * 1. optimized_kprobe structure in r3
	 */
	TEMPLATE_FOR_IMM_LOAD_INSNS

	/* 2. pt_regs pointer in r4 */
	addi	r4,r1,STACK_INT_FRAME_REGS

	.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_INT_FRAME_REGS

	.global optprobe_template_insn
optprobe_template_insn:
	/* 2, Pass instruction to be emulated in r4 */
	TEMPLATE_FOR_IMM_LOAD_INSNS

	.global optprobe_template_call_emulate
optprobe_template_call_emulate:
	/* Branch to emulate_step()  */
	nop

	/*
	 * All done.
	 * Now, restore the registers...
	 */
	PPC_LL	r5,_MSR(r1)
	mtmsr	r5
	PPC_LL	r5,_CTR(r1)
	mtctr	r5
	PPC_LL	r5,_LINK(r1)
	mtlr	r5
	PPC_LL	r5,_XER(r1)
	mtxer	r5
	PPC_LL	r5,_CCR(r1)
	mtcr	r5
	REST_GPR(0,r1)
	REST_30GPRS(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: