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
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>
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)
76 if (!need_resched()) {
78 __asm__("nop"); // was asm sleep
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)
94 while (!need_resched())
96 preempt_enable_no_resched();
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
)
111 __asm__
__volatile__ (
114 : "r" (CPU_RESET_ADDRESS
)
118 EXPORT_SYMBOL(machine_restart
);
120 void machine_halt(void)
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)
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
)
181 long clone_arg
= flags
| CLONE_VM
;
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 */
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) */
207 " callr %3\n\t" /* Call function (fn) */
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. */
216 " mov %0, r2\n\t" /* error rtn code (retval) */
218 : "=r" (retval
) /* %0 */
220 : "i" (__NR_clone
) /* %1 */
221 , "i" (__NR_exit
) /* %2 */
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 */
238 void flush_thread(void)
240 /* Now, this task is no longer a kernel thread. */
241 current
->thread
.flags
&= ~NIOS2_FLAG_KTHREAD
;
244 unsigned long zero
= 0;
250 asm volatile (".chip 68k/68881\n\t"
252 ".chip 68k" : : "a" (&zero
));
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
263 asmlinkage
int nios2_fork(struct pt_regs
*regs
)
265 /* fork almost works, enough to trick you into looking elsewhere :-( */
270 * nios2_execve() executes a new program.
272 asmlinkage
int nios2_execve(struct pt_regs
*regs
)
278 filename
= getname((char *) regs
->r4
);
279 error
= PTR_ERR(filename
);
280 if (IS_ERR(filename
))
282 error
= do_execve(filename
,
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
;
304 clone_flags
= regs
->r4
;
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
;
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
;
334 p
->thread
.kregs
->sp
= (unsigned long) childstack
;
336 p
->thread
.kregs
->sp
= usp
;
338 p
->thread
.ksp
= (unsigned long)childstack
;
342 /* Copy the current fpu state */
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])
351 /* Restore the state in case the fpu was busy */
352 asm volatile ("frestore %0" : : "m" (p
->thread
.fpstate
[0]));
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
367 /* Fill in the fpu structure for a core dump. */
369 int dump_fpu(struct pt_regs
*regs
, struct user_m68kfp_struct
*fpu
)
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);
388 /* First dump the fpu context to avoid protocol violation. */
390 asm volatile ("fsave %0" :: "m" (fpustate
[0]) : "memory");
394 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
395 :: "m" (fpu
->fpcntl
[0])
397 asm volatile ("fmovemx %/fp0-%/fp7,%0"
398 :: "m" (fpu
->fpregs
[0])
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
;
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
)
469 printk(KERN_EMERG
"\nCURRENT PROCESS:\n\n");
470 printk(KERN_EMERG
"COMM=%s PID=%d\n", current
->comm
, current
->pid
);
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
,
494 printk(KERN_EMERG
"\nCODE:");
495 tp
= ((unsigned char *) fp
->ea
) - 0x20;
496 for (sp
= (unsigned long *) tp
, i
= 0; (i
< 0x40); i
+= 4) {
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) {
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) {
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
;
536 if (!p
|| p
== current
|| p
->state
== TASK_RUNNING
)
539 stack_page
= (unsigned long)p
;
540 fp
= ((struct switch_stack
*)p
->thread
.ksp
)->fp
; //;dgt2
542 if (fp
< stack_page
+sizeof(struct task_struct
) ||
543 fp
>= 8184+stack_page
) //;dgt2;tmp
545 pc
= ((unsigned long *)fp
)[1];
546 if (!in_sched_functions(pc
))
548 fp
= *(unsigned long *) fp
;
549 } while (count
++ < 16); //;dgt2;tmp
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
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);