1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/errno.h>
19#include <linux/sched.h>
20#include <linux/sched/debug.h>
21#include <linux/sched/task.h>
22#include <linux/sched/task_stack.h>
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/smp.h>
26#include <linux/stddef.h>
27#include <linux/unistd.h>
28#include <linux/ptrace.h>
29#include <linux/elf.h>
30#include <linux/hw_breakpoint.h>
31#include <linux/init.h>
32#include <linux/prctl.h>
33#include <linux/init_task.h>
34#include <linux/module.h>
35#include <linux/mqueue.h>
36#include <linux/fs.h>
37#include <linux/slab.h>
38#include <linux/rcupdate.h>
39
40#include <asm/pgtable.h>
41#include <linux/uaccess.h>
42#include <asm/io.h>
43#include <asm/processor.h>
44#include <asm/platform.h>
45#include <asm/mmu.h>
46#include <asm/irq.h>
47#include <linux/atomic.h>
48#include <asm/asm-offsets.h>
49#include <asm/regs.h>
50#include <asm/hw_breakpoint.h>
51
52extern void ret_from_fork(void);
53extern void ret_from_kernel_thread(void);
54
55struct task_struct *current_set[NR_CPUS] = {&init_task, };
56
57void (*pm_power_off)(void) = NULL;
58EXPORT_SYMBOL(pm_power_off);
59
60
61#ifdef CONFIG_STACKPROTECTOR
62#include <linux/stackprotector.h>
63unsigned long __stack_chk_guard __read_mostly;
64EXPORT_SYMBOL(__stack_chk_guard);
65#endif
66
67#if XTENSA_HAVE_COPROCESSORS
68
69void coprocessor_release_all(struct thread_info *ti)
70{
71 unsigned long cpenable;
72 int i;
73
74
75
76 preempt_disable();
77
78
79
80 cpenable = ti->cpenable;
81
82 for (i = 0; i < XCHAL_CP_MAX; i++) {
83 if (coprocessor_owner[i] == ti) {
84 coprocessor_owner[i] = 0;
85 cpenable &= ~(1 << i);
86 }
87 }
88
89 ti->cpenable = cpenable;
90 coprocessor_clear_cpenable();
91
92 preempt_enable();
93}
94
95void coprocessor_flush_all(struct thread_info *ti)
96{
97 unsigned long cpenable;
98 int i;
99
100 preempt_disable();
101
102 cpenable = ti->cpenable;
103
104 for (i = 0; i < XCHAL_CP_MAX; i++) {
105 if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
106 coprocessor_flush(ti, i);
107 cpenable >>= 1;
108 }
109
110 preempt_enable();
111}
112
113#endif
114
115
116
117
118
119void arch_cpu_idle(void)
120{
121 platform_idle();
122}
123
124
125
126
127void exit_thread(struct task_struct *tsk)
128{
129#if XTENSA_HAVE_COPROCESSORS
130 coprocessor_release_all(task_thread_info(tsk));
131#endif
132}
133
134
135
136
137
138void flush_thread(void)
139{
140#if XTENSA_HAVE_COPROCESSORS
141 struct thread_info *ti = current_thread_info();
142 coprocessor_flush_all(ti);
143 coprocessor_release_all(ti);
144#endif
145 flush_ptrace_hw_breakpoint(current);
146}
147
148
149
150
151
152int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
153{
154#if XTENSA_HAVE_COPROCESSORS
155 coprocessor_flush_all(task_thread_info(src));
156#endif
157 *dst = *src;
158 return 0;
159}
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
204 unsigned long thread_fn_arg, struct task_struct *p)
205{
206 struct pt_regs *childregs = task_pt_regs(p);
207
208#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
209 struct thread_info *ti;
210#endif
211
212
213 SPILL_SLOT(childregs, 1) = (unsigned long)childregs;
214 SPILL_SLOT(childregs, 0) = 0;
215
216 p->thread.sp = (unsigned long)childregs;
217
218 if (!(p->flags & PF_KTHREAD)) {
219 struct pt_regs *regs = current_pt_regs();
220 unsigned long usp = usp_thread_fn ?
221 usp_thread_fn : regs->areg[1];
222
223 p->thread.ra = MAKE_RA_FOR_CALL(
224 (unsigned long)ret_from_fork, 0x1);
225
226
227
228
229
230 *childregs = *regs;
231 childregs->areg[1] = usp;
232 childregs->areg[2] = 0;
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247 if (clone_flags & CLONE_VM) {
248
249 int len = childregs->wmask & ~0xf;
250 if (regs->areg[1] == usp && len != 0) {
251 int callinc = (regs->areg[0] >> 30) & 3;
252 int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
253 put_user(regs->areg[caller_ars+1],
254 (unsigned __user*)(usp - 12));
255 }
256 childregs->wmask = 1;
257 childregs->windowstart = 1;
258 childregs->windowbase = 0;
259 } else {
260 int len = childregs->wmask & ~0xf;
261 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
262 ®s->areg[XCHAL_NUM_AREGS - len/4], len);
263 }
264
265
266 if (clone_flags & CLONE_SETTLS)
267 childregs->threadptr = childregs->areg[5];
268 } else {
269 p->thread.ra = MAKE_RA_FOR_CALL(
270 (unsigned long)ret_from_kernel_thread, 1);
271
272
273
274
275 SPILL_SLOT(childregs, 3) = thread_fn_arg;
276 SPILL_SLOT(childregs, 2) = usp_thread_fn;
277
278
279
280
281 }
282
283#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
284 ti = task_thread_info(p);
285 ti->cpenable = 0;
286#endif
287
288 clear_ptrace_hw_breakpoint(p);
289
290 return 0;
291}
292
293
294
295
296
297
298unsigned long get_wchan(struct task_struct *p)
299{
300 unsigned long sp, pc;
301 unsigned long stack_page = (unsigned long) task_stack_page(p);
302 int count = 0;
303
304 if (!p || p == current || p->state == TASK_RUNNING)
305 return 0;
306
307 sp = p->thread.sp;
308 pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
309
310 do {
311 if (sp < stack_page + sizeof(struct task_struct) ||
312 sp >= (stack_page + THREAD_SIZE) ||
313 pc == 0)
314 return 0;
315 if (!in_sched_functions(pc))
316 return pc;
317
318
319
320 pc = MAKE_PC_FROM_RA(*(unsigned long*)sp - 4, sp);
321 sp = *(unsigned long *)sp - 3;
322 } while (count++ < 16);
323 return 0;
324}
325
326
327
328
329
330
331
332
333
334
335void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
336{
337 unsigned long wb, ws, wm;
338 int live, last;
339
340 wb = regs->windowbase;
341 ws = regs->windowstart;
342 wm = regs->wmask;
343 ws = ((ws >> wb) | (ws << (WSBITS - wb))) & ((1 << WSBITS) - 1);
344
345
346
347 memset(elfregs, 0, sizeof(*elfregs));
348
349
350
351
352
353 elfregs->pc = regs->pc;
354 elfregs->ps = (regs->ps & ~(1 << PS_EXCM_BIT));
355 elfregs->lbeg = regs->lbeg;
356 elfregs->lend = regs->lend;
357 elfregs->lcount = regs->lcount;
358 elfregs->sar = regs->sar;
359 elfregs->windowstart = ws;
360
361 live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
362 last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
363 memcpy(elfregs->a, regs->areg, live * 4);
364 memcpy(elfregs->a + last, regs->areg + last, (wm >> 4) * 16);
365}
366
367int dump_fpu(void)
368{
369 return 0;
370}
371