MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / nios2nommu / kernel / process.c
blob75610524e6b136f0377ff9ee2a083087871e591b
1 /*--------------------------------------------------------------------
3 * arch/nios2nommu/kernel/process.c
5 * Derived from M68knommu
7 * Copyright (C) 1995 Hamish Macdonald
8 * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
9 * Copyright (C) 2004 Microtronix Datacom Ltd
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
22 * 68060 fixes by Jesper Skov
23 * Jan/20/2004 dgt NiosII
24 * rdusp() === (pt_regs *) regs->sp
25 * Monday:
26 * asm-nios2nommu\processor.h now bears
27 * inline thread_saved_pc
28 * (struct thread_struct *t)
29 * Friday: it's back here now
31 ---------------------------------------------------------------------*/
35 * This file handles the architecture-dependent parts of process handling..
38 #include <linux/module.h>
39 #include <linux/errno.h>
40 #include <linux/sched.h>
41 #include <linux/kernel.h>
42 #include <linux/mm.h>
43 #include <linux/smp.h>
44 #include <linux/smp_lock.h>
45 #include <linux/stddef.h>
46 #include <linux/unistd.h>
47 #include <linux/ptrace.h>
48 #include <linux/slab.h>
49 #include <linux/user.h>
50 #include <linux/a.out.h>
51 #include <linux/interrupt.h>
52 #include <linux/reboot.h>
54 #include <asm/uaccess.h>
55 #include <asm/system.h>
56 #include <asm/traps.h>
57 //;dgt2;#include <asm/machdep.h>
58 #include <asm/setup.h>
59 #include <asm/pgtable.h>
60 #include <asm/cacheflush.h>
62 asmlinkage void ret_from_fork(void);
65 * The following aren't currently used.
67 void (*pm_idle)(void) = NULL;
68 EXPORT_SYMBOL(pm_idle);
70 void (*pm_power_off)(void) = NULL;
71 EXPORT_SYMBOL(pm_power_off);
73 void default_idle(void)
75 local_irq_disable();
76 if (!need_resched()) {
77 local_irq_enable();
78 __asm__("nop"); // was asm sleep
79 } else
80 local_irq_enable();
83 void (*idle)(void) = default_idle;
86 * The idle thread. There's no useful work to be
87 * done, so just try to conserve power and have a
88 * low exit latency (ie sit in a loop waiting for
89 * somebody to say that they'd like to reschedule)
91 void cpu_idle(void)
93 while (1) {
94 while (!need_resched())
95 idle();
96 preempt_enable_no_resched();
97 schedule();
98 preempt_disable();
103 * The development boards have no way to pull a board
104 * reset. Just jump to the cpu reset address and let
105 * the code in head.S take care of disabling peripherals.
108 void machine_restart(char * __unused)
110 local_irq_disable();
111 __asm__ __volatile__ (
112 "jmp %0\n\t"
114 : "r" (CPU_RESET_ADDRESS)
115 : "r4");
118 EXPORT_SYMBOL(machine_restart);
120 void machine_halt(void)
122 local_irq_disable();
123 for (;;);
126 EXPORT_SYMBOL(machine_halt);
128 void exit_thread(void)
132 void release_thread(struct task_struct *dead_task)
134 /* nothing to do ... */
138 * There is no way to power off the development
139 * boards. So just spin lock for now. If you have
140 * your own board with power down circuits add you
141 * specific code here.
144 void machine_power_off(void)
146 local_irq_disable();
147 for (;;);
150 EXPORT_SYMBOL(machine_power_off);
152 void show_regs(struct pt_regs * regs)
154 printk(KERN_NOTICE "\n");
156 printk(KERN_NOTICE "r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n",
157 regs->r1, regs->r2, regs->r3, regs->r4);
159 printk(KERN_NOTICE "r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n",
160 regs->r5, regs->r6, regs->r7, regs->r8);
162 printk(KERN_NOTICE "r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n",
163 regs->r9, regs->r10, regs->r11, regs->r12);
165 printk(KERN_NOTICE "r13: %08lx r14: %08lx r15: %08lx\n",
166 regs->r13, regs->r14, regs->r15);
168 printk(KERN_NOTICE "ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n",
169 regs->ra, regs->fp, regs->sp, regs->gp);
171 printk(KERN_NOTICE "ea: %08lx estatus: %08lx statusx: %08lx\n",
172 regs->ea, regs->estatus, regs->status_extension);
176 * Create a kernel thread
178 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
180 long retval;
181 long clone_arg = flags | CLONE_VM;
182 mm_segment_t fs;
184 fs = get_fs();
185 set_fs(KERNEL_DS);
187 __asm__ __volatile(
189 " movi r2, %6\n\t" /* TRAP_ID_SYSCALL */
190 " movi r3, %1\n\t" /* __NR_clone */
191 " mov r4, %5\n\t" /* (clone_arg */
192 /* (flags | CLONE_VM)) */
193 " movia r5, -1\n\t" /* usp: -1 */
194 " trap\n\t" /* sys_clone */
195 "\n\t"
196 " cmpeq r4, r3, zero\n\t"/*2nd return valu in r3 */
197 " bne r4, zero, 1f\n\t"/* 0: parent, just return. */
198 /* See copy_thread, called */
199 /* by do_fork, called by */
200 /* nios2_clone, called by */
201 /* sys_clone, called by */
202 /* syscall trap handler. */
204 " mov r4, %4\n\t" /* fn's parameter (arg) */
205 "\n\t"
206 "\n\t"
207 " callr %3\n\t" /* Call function (fn) */
208 "\n\t"
209 " mov r4, r2\n\t" /* fn's rtn code//;dgt2;tmp;*/
210 " movi r2, %6\n\t" /* TRAP_ID_SYSCALL */
211 " movi r3, %2\n\t" /* __NR_exit */
212 " trap\n\t" /* sys_exit() */
214 /* Not reached by child. */
215 "1:\n\t"
216 " mov %0, r2\n\t" /* error rtn code (retval) */
218 : "=r" (retval) /* %0 */
220 : "i" (__NR_clone) /* %1 */
221 , "i" (__NR_exit) /* %2 */
222 , "r" (fn) /* %3 */
223 , "r" (arg) /* %4 */
224 , "r" (clone_arg) /* %5 (flags | CLONE_VM) */
225 , "i" (TRAP_ID_SYSCALL) /* %6 */
227 : "r2" /* Clobbered */
228 , "r3" /* Clobbered */
229 , "r4" /* Clobbered */
230 , "r5" /* Clobbered */
231 , "ra" /* Clobbered //;mex1 */
234 set_fs(fs);
235 return retval;
238 void flush_thread(void)
240 /* Now, this task is no longer a kernel thread. */
241 current->thread.flags &= ~NIOS2_FLAG_KTHREAD;
243 #ifdef CONFIG_FPU
244 unsigned long zero = 0;
245 #endif
246 set_fs(USER_DS);
247 #ifdef CONFIG_FPU
248 if (!FPU_IS_EMU)
249 ...;dgt2;
250 asm volatile (".chip 68k/68881\n\t"
251 "frestore %0@\n\t"
252 ".chip 68k" : : "a" (&zero));
253 #endif
257 * "nios2_fork()".. By the time we get here, the
258 * non-volatile registers have also been saved on the
259 * stack. We do some ugly pointer stuff here.. (see
260 * also copy_thread)
263 asmlinkage int nios2_fork(struct pt_regs *regs)
265 /* fork almost works, enough to trick you into looking elsewhere :-( */
266 return(-EINVAL);
270 * nios2_execve() executes a new program.
272 asmlinkage int nios2_execve(struct pt_regs *regs)
274 int error;
275 char * filename;
277 lock_kernel();
278 filename = getname((char *) regs->r4);
279 error = PTR_ERR(filename);
280 if (IS_ERR(filename))
281 goto out;
282 error = do_execve(filename,
283 (char **) regs->r5,
284 (char **) regs->r6,
285 regs);
286 putname(filename);
287 out:
288 unlock_kernel();
289 return error;
292 asmlinkage int nios2_vfork(struct pt_regs *regs)
294 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL);
297 asmlinkage int nios2_clone(struct pt_regs *regs)
299 /* r4: clone_flags, r5: child_stack (usp) */
301 unsigned long clone_flags;
302 unsigned long newsp;
304 clone_flags = regs->r4;
305 newsp = regs->r5;
306 if (!newsp)
307 newsp = regs->sp;
308 return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
311 int copy_thread(int nr, unsigned long clone_flags,
312 unsigned long usp, unsigned long topstk,
313 struct task_struct * p, struct pt_regs * regs)
315 struct pt_regs * childregs;
316 struct switch_stack * childstack, *stack;
317 unsigned long stack_offset, *retp;
319 stack_offset = THREAD_SIZE - sizeof(struct pt_regs);
320 childregs = (struct pt_regs *) ((unsigned long) p->thread_info + stack_offset);
321 p->thread.kregs = childregs;
323 *childregs = *regs;
324 childregs->r2 = 0; //;dgt2;...redundant?...see "rtnvals" below
326 retp = ((unsigned long *) regs);
327 stack = ((struct switch_stack *) retp) - 1;
329 childstack = ((struct switch_stack *) childregs) - 1;
330 *childstack = *stack;
331 childstack->ra = (unsigned long)ret_from_fork;
333 if (usp == -1)
334 p->thread.kregs->sp = (unsigned long) childstack;
335 else
336 p->thread.kregs->sp = usp;
338 p->thread.ksp = (unsigned long)childstack;
340 #ifdef CONFIG_FPU
341 if (!FPU_IS_EMU) {
342 /* Copy the current fpu state */
343 ...;dgt2;
344 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
346 if (p->thread.fpstate[0])
347 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
348 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
349 : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
350 : "memory");
351 /* Restore the state in case the fpu was busy */
352 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
354 #endif
356 /* Set the return value for the child. */
357 childregs->r2 = 0; //;dgt2;...redundant?...see childregs->r2 above
358 childregs->r3 = 1; //;dgt2;...eg: kernel_thread parent test
360 /* Set the return value for the parent. */
361 regs->r2 = p->pid; // Return child pid to parent
362 regs->r3 = 0; //;dgt2;...eg: kernel_thread parent test
364 return 0;
367 /* Fill in the fpu structure for a core dump. */
369 int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
371 #ifdef CONFIG_FPU
372 char fpustate[216];
374 if (FPU_IS_EMU) {
375 int i;
377 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
378 memcpy(fpu->fpregs, current->thread.fp, 96);
379 /* Convert internal fpu reg representation
380 * into long double format
382 for (i = 0; i < 24; i += 3)
383 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
384 ((fpu->fpregs[i] & 0x0000ffff) << 16);
385 return 1;
388 /* First dump the fpu context to avoid protocol violation. */
389 ...;dgt2;tmp;
390 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
391 if (!fpustate[0])
392 return 0;
394 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
395 :: "m" (fpu->fpcntl[0])
396 : "memory");
397 asm volatile ("fmovemx %/fp0-%/fp7,%0"
398 :: "m" (fpu->fpregs[0])
399 : "memory");
400 #endif
401 return 1;
405 * fill in the user structure for a core dump..
407 void dump_thread(struct pt_regs * regs, struct user * dump)
409 struct switch_stack *sw;
411 /* changed the size calculations - should hopefully work better. lbt */
412 dump->magic = CMAGIC;
413 dump->start_code = 0;
414 dump->start_stack = regs->sp & ~(PAGE_SIZE - 1);
415 dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
416 dump->u_dsize = ((unsigned long) (current->mm->brk +
417 (PAGE_SIZE-1))) >> PAGE_SHIFT;
418 dump->u_dsize -= dump->u_tsize;
419 dump->u_ssize = 0;
421 if (dump->start_stack < TASK_SIZE)
422 dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
424 dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
425 sw = ((struct switch_stack *)regs) - 1;
426 dump->regs.r1 = regs->r1;
427 dump->regs.r2 = regs->r2;
428 dump->regs.r3 = regs->r3;
429 dump->regs.r4 = regs->r4;
430 dump->regs.r5 = regs->r5;
431 dump->regs.r6 = regs->r6;
432 dump->regs.r7 = regs->r7;
433 dump->regs.r8 = regs->r8;
434 dump->regs.r9 = regs->r9;
435 dump->regs.r10 = regs->r10;
436 dump->regs.r11 = regs->r11;
437 dump->regs.r12 = regs->r12;
438 dump->regs.r13 = regs->r13;
439 dump->regs.r14 = regs->r14;
440 dump->regs.r15 = regs->r15;
441 dump->regs.r16 = sw->r16;
442 dump->regs.r17 = sw->r17;
443 dump->regs.r18 = sw->r18;
444 dump->regs.r19 = sw->r19;
445 dump->regs.r20 = sw->r20;
446 dump->regs.r21 = sw->r21;
447 dump->regs.r22 = sw->r22;
448 dump->regs.r23 = sw->r23;
449 dump->regs.ra = sw->ra;
450 dump->regs.fp = sw->fp;
451 dump->regs.gp = sw->gp;
452 dump->regs.sp = regs->sp;
453 dump->regs.orig_r2 = regs->orig_r2;
454 dump->regs.estatus = regs->estatus;
455 dump->regs.ea = regs->ea;
456 /* dump floating point stuff */
457 // dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp);
461 * Generic dumping code. Used for panic and debug.
463 void dump(struct pt_regs *fp)
465 unsigned long *sp;
466 unsigned char *tp;
467 int i;
469 printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
470 printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
472 if (current->mm) {
473 printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
474 (int) current->mm->start_code,
475 (int) current->mm->end_code,
476 (int) current->mm->start_data,
477 (int) current->mm->end_data,
478 (int) current->mm->end_data,
479 (int) current->mm->brk);
480 printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
481 (int) current->mm->start_stack,
482 (int)(((unsigned long) current) + THREAD_SIZE));
485 printk(KERN_EMERG "PC: %08lx\n", fp->ea);
486 printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->estatus, (long) fp);
487 printk(KERN_EMERG "r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
488 fp->r4, fp->r5, fp->r6, fp->r7);
489 printk(KERN_EMERG "r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
490 fp->r8, fp->r9, fp->r10, fp->r11);
491 printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) fp->sp,
492 (unsigned int) fp);
494 printk(KERN_EMERG "\nCODE:");
495 tp = ((unsigned char *) fp->ea) - 0x20;
496 for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
497 if ((i % 0x10) == 0)
498 printk(KERN_EMERG "\n%08x: ", (int) (tp + i));
499 printk(KERN_EMERG "%08x ", (int) *sp++);
501 printk(KERN_EMERG "\n");
503 printk(KERN_EMERG "\nKERNEL STACK:");
504 tp = ((unsigned char *) fp) - 0x40;
505 for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
506 if ((i % 0x10) == 0)
507 printk(KERN_EMERG "\n%08x: ", (int) (tp + i));
508 printk(KERN_EMERG "%08x ", (int) *sp++);
510 printk(KERN_EMERG "\n");
511 printk(KERN_EMERG "\n");
513 printk(KERN_EMERG "\nUSER STACK:");
514 tp = (unsigned char *) (fp->sp - 0x10);
515 for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
516 if ((i % 0x10) == 0)
517 printk(KERN_EMERG "\n%08x: ", (int) (tp + i));
518 printk(KERN_EMERG "%08x ", (int) *sp++);
520 printk(KERN_EMERG "\n\n");
524 * These bracket the sleeping functions..
526 extern void scheduling_functions_start_here(void);
527 extern void scheduling_functions_end_here(void);
528 #define first_sched ((unsigned long) scheduling_functions_start_here)
529 #define last_sched ((unsigned long) scheduling_functions_end_here)
531 unsigned long get_wchan(struct task_struct *p)
533 unsigned long fp, pc;
534 unsigned long stack_page;
535 int count = 0;
536 if (!p || p == current || p->state == TASK_RUNNING)
537 return 0;
539 stack_page = (unsigned long)p;
540 fp = ((struct switch_stack *)p->thread.ksp)->fp; //;dgt2
541 do {
542 if (fp < stack_page+sizeof(struct task_struct) ||
543 fp >= 8184+stack_page) //;dgt2;tmp
544 return 0;
545 pc = ((unsigned long *)fp)[1];
546 if (!in_sched_functions(pc))
547 return pc;
548 fp = *(unsigned long *) fp;
549 } while (count++ < 16); //;dgt2;tmp
550 return 0;
553 /* Return saved PC of a blocked thread. */
554 unsigned long thread_saved_pc(struct task_struct *t)
556 return (t->thread.kregs->ea);
560 * Do necessary setup to start up a newly executed thread.
561 * Will statup in user mode (status_extension = 0).
563 void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
565 memset((void *) regs, 0, sizeof(struct pt_regs));
566 regs->estatus = NIOS2_STATUS_PIE_MSK; // No user mode setting, at least not for now
567 regs->ea = pc;
568 regs->sp = sp;
570 /* check if debug flag is set */
571 if (current->thread.flags & NIOS2_FLAG_DEBUG ) {
572 if ( *(u32*)pc == NIOS2_OP_NOP ) {
573 *(u32*)pc = NIOS2_OP_BREAK;
574 flush_icache_range(pc, pc+4);