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 LOAD_PACA_TOC()
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_INT_FRAME_REGS
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_INT_FRAME_REGS
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

source code of linux/arch/powerpc/kernel/optprobes_head.S