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