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 |
32 | optinsn_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 |
41 | optprobe_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 |
80 | optprobe_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 |
91 | optprobe_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 |
102 | optprobe_template_insn: |
103 | /* 2, Pass instruction to be emulated in r4 */ |
104 | TEMPLATE_FOR_IMM_LOAD_INSNS |
105 | |
106 | .global optprobe_template_call_emulate |
107 | optprobe_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 |
131 | optprobe_template_ret: |
132 | /* ... and jump back from trampoline */ |
133 | nop |
134 | |
135 | .global optprobe_template_end |
136 | optprobe_template_end: |
137 | |