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