1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2022 Loongson Technology Corporation Limited
4 */
5 #include <linux/cpumask.h>
6 #include <linux/export.h>
7 #include <linux/ftrace.h>
8 #include <linux/kallsyms.h>
9
10 #include <asm/inst.h>
11 #include <asm/loongson.h>
12 #include <asm/ptrace.h>
13 #include <asm/setup.h>
14 #include <asm/unwind.h>
15
16 extern const int unwind_hint_ade;
17 extern const int unwind_hint_ale;
18 extern const int unwind_hint_bp;
19 extern const int unwind_hint_fpe;
20 extern const int unwind_hint_fpu;
21 extern const int unwind_hint_lsx;
22 extern const int unwind_hint_lasx;
23 extern const int unwind_hint_lbt;
24 extern const int unwind_hint_ri;
25 extern const int unwind_hint_watch;
26
scan_handlers(unsigned long entry_offset)27 static inline bool scan_handlers(unsigned long entry_offset)
28 {
29 int idx, offset;
30
31 if (entry_offset >= EXCCODE_INT_START * VECSIZE)
32 return false;
33
34 idx = entry_offset / VECSIZE;
35 offset = entry_offset % VECSIZE;
36 switch (idx) {
37 case EXCCODE_ADE:
38 return offset == unwind_hint_ade;
39 case EXCCODE_ALE:
40 return offset == unwind_hint_ale;
41 case EXCCODE_BP:
42 return offset == unwind_hint_bp;
43 case EXCCODE_FPE:
44 return offset == unwind_hint_fpe;
45 case EXCCODE_FPDIS:
46 return offset == unwind_hint_fpu;
47 case EXCCODE_LSXDIS:
48 return offset == unwind_hint_lsx;
49 case EXCCODE_LASXDIS:
50 return offset == unwind_hint_lasx;
51 case EXCCODE_BTDIS:
52 return offset == unwind_hint_lbt;
53 case EXCCODE_INE:
54 return offset == unwind_hint_ri;
55 case EXCCODE_WATCH:
56 return offset == unwind_hint_watch;
57 default:
58 return false;
59 }
60 }
61
fix_exception(unsigned long pc)62 static inline bool fix_exception(unsigned long pc)
63 {
64 #if defined(CONFIG_NUMA) && !defined(CONFIG_PREEMPT_RT)
65 int cpu;
66
67 for_each_possible_cpu(cpu) {
68 if (!pcpu_handlers[cpu])
69 continue;
70 if (scan_handlers(pc - pcpu_handlers[cpu]))
71 return true;
72 }
73 #endif
74 return scan_handlers(pc - eentry);
75 }
76
77 /*
78 * As we meet ftrace_regs_entry, reset first flag like first doing
79 * tracing. Prologue analysis will stop soon because PC is at entry.
80 */
fix_ftrace(unsigned long pc)81 static inline bool fix_ftrace(unsigned long pc)
82 {
83 #ifdef CONFIG_DYNAMIC_FTRACE
84 return pc == (unsigned long)ftrace_call + LOONGARCH_INSN_SIZE;
85 #else
86 return false;
87 #endif
88 }
89
unwind_state_fixup(struct unwind_state * state)90 static inline bool unwind_state_fixup(struct unwind_state *state)
91 {
92 if (!fix_exception(state->pc) && !fix_ftrace(state->pc))
93 return false;
94
95 state->reset = true;
96 return true;
97 }
98
99 /*
100 * LoongArch function prologue is like follows,
101 * [instructions not use stack var]
102 * addi.d sp, sp, -imm
103 * st.d xx, sp, offset <- save callee saved regs and
104 * st.d yy, sp, offset save ra if function is nest.
105 * [others instructions]
106 */
unwind_by_prologue(struct unwind_state * state)107 static bool unwind_by_prologue(struct unwind_state *state)
108 {
109 long frame_ra = -1;
110 unsigned long frame_size = 0;
111 unsigned long size, offset, pc;
112 struct pt_regs *regs;
113 struct stack_info *info = &state->stack_info;
114 union loongarch_instruction *ip, *ip_end;
115
116 if (state->sp >= info->end || state->sp < info->begin)
117 return false;
118
119 if (state->reset) {
120 regs = (struct pt_regs *)state->sp;
121 state->first = true;
122 state->reset = false;
123 state->pc = regs->csr_era;
124 state->ra = regs->regs[1];
125 state->sp = regs->regs[3];
126 return true;
127 }
128
129 /*
130 * When first is not set, the PC is a return address in the previous frame.
131 * We need to adjust its value in case overflow to the next symbol.
132 */
133 pc = state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE);
134 if (!kallsyms_lookup_size_offset(pc, &size, &offset))
135 return false;
136
137 ip = (union loongarch_instruction *)(pc - offset);
138 ip_end = (union loongarch_instruction *)pc;
139
140 while (ip < ip_end) {
141 if (is_stack_alloc_ins(ip)) {
142 frame_size = (1 << 12) - ip->reg2i12_format.immediate;
143 ip++;
144 break;
145 }
146 ip++;
147 }
148
149 /*
150 * Can't find stack alloc action, PC may be in a leaf function. Only the
151 * first being true is reasonable, otherwise indicate analysis is broken.
152 */
153 if (!frame_size) {
154 if (state->first)
155 goto first;
156
157 return false;
158 }
159
160 while (ip < ip_end) {
161 if (is_ra_save_ins(ip)) {
162 frame_ra = ip->reg2i12_format.immediate;
163 break;
164 }
165 if (is_branch_ins(ip))
166 break;
167 ip++;
168 }
169
170 /* Can't find save $ra action, PC may be in a leaf function, too. */
171 if (frame_ra < 0) {
172 if (state->first) {
173 state->sp = state->sp + frame_size;
174 goto first;
175 }
176 return false;
177 }
178
179 state->pc = *(unsigned long *)(state->sp + frame_ra);
180 state->sp = state->sp + frame_size;
181 goto out;
182
183 first:
184 state->pc = state->ra;
185
186 out:
187 state->first = false;
188 return unwind_state_fixup(state) || __kernel_text_address(state->pc);
189 }
190
next_frame(struct unwind_state * state)191 static bool next_frame(struct unwind_state *state)
192 {
193 unsigned long pc;
194 struct pt_regs *regs;
195 struct stack_info *info = &state->stack_info;
196
197 if (unwind_done(state))
198 return false;
199
200 do {
201 if (unwind_by_prologue(state)) {
202 state->pc = unwind_graph_addr(state, state->pc, state->sp);
203 return true;
204 }
205
206 if (info->type == STACK_TYPE_IRQ && info->end == state->sp) {
207 regs = (struct pt_regs *)info->next_sp;
208 pc = regs->csr_era;
209
210 if (user_mode(regs) || !__kernel_text_address(pc))
211 goto out;
212
213 state->first = true;
214 state->pc = pc;
215 state->ra = regs->regs[1];
216 state->sp = regs->regs[3];
217 get_stack_info(state->sp, state->task, info);
218
219 return true;
220 }
221
222 state->sp = info->next_sp;
223
224 } while (!get_stack_info(state->sp, state->task, info));
225
226 out:
227 state->stack_info.type = STACK_TYPE_UNKNOWN;
228 return false;
229 }
230
unwind_get_return_address(struct unwind_state * state)231 unsigned long unwind_get_return_address(struct unwind_state *state)
232 {
233 return __unwind_get_return_address(state);
234 }
235 EXPORT_SYMBOL_GPL(unwind_get_return_address);
236
unwind_start(struct unwind_state * state,struct task_struct * task,struct pt_regs * regs)237 void unwind_start(struct unwind_state *state, struct task_struct *task,
238 struct pt_regs *regs)
239 {
240 __unwind_start(state, task, regs);
241 state->type = UNWINDER_PROLOGUE;
242 state->first = true;
243
244 /*
245 * The current PC is not kernel text address, we cannot find its
246 * relative symbol. Thus, prologue analysis will be broken. Luckily,
247 * we can use the default_next_frame().
248 */
249 if (!__kernel_text_address(state->pc)) {
250 state->type = UNWINDER_GUESS;
251 if (!unwind_done(state))
252 unwind_next_frame(state);
253 }
254 }
255 EXPORT_SYMBOL_GPL(unwind_start);
256
unwind_next_frame(struct unwind_state * state)257 bool unwind_next_frame(struct unwind_state *state)
258 {
259 return state->type == UNWINDER_PROLOGUE ?
260 next_frame(state) : default_next_frame(state);
261 }
262 EXPORT_SYMBOL_GPL(unwind_next_frame);
263