2 * $Id: process.c,v 1.86 1999/06/17 21:53:46 cort Exp $
4 * linux/arch/ppc/kernel/process.c
6 * Derived from "arch/i386/kernel/process.c"
7 * Copyright (C) 1995 Linus Torvalds
9 * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
10 * Paul Mackerras (paulus@cs.anu.edu.au)
13 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
22 #include <linux/errno.h>
23 #include <linux/sched.h>
24 #include <linux/kernel.h>
26 #include <linux/smp.h>
27 #include <linux/smp_lock.h>
28 #include <linux/stddef.h>
29 #include <linux/unistd.h>
30 #include <linux/ptrace.h>
31 #include <linux/malloc.h>
32 #include <linux/user.h>
33 #include <linux/elf.h>
34 #include <linux/elf.h>
35 #include <linux/init.h>
37 #include <asm/pgtable.h>
38 #include <asm/uaccess.h>
39 #include <asm/system.h>
41 #include <asm/processor.h>
45 int dump_fpu(struct pt_regs
*regs
, elf_fpregset_t
*fpregs
);
46 extern unsigned long _get_SP(void);
48 struct task_struct
*last_task_used_math
= NULL
;
49 static struct vm_area_struct init_mmap
= INIT_MMAP
;
50 static struct fs_struct init_fs
= INIT_FS
;
51 static struct file
* init_fd_array
[NR_OPEN
] = { NULL
, };
52 static struct files_struct init_files
= INIT_FILES
;
53 static struct signal_struct init_signals
= INIT_SIGNALS
;
54 struct mm_struct init_mm
= INIT_MM(init_mm
);
55 union task_union init_task_union
= { INIT_TASK(init_task_union
.task
) };
56 /* only used to get secondary processor up */
57 struct task_struct
*current_set
[NR_CPUS
] = {&init_task
, };
59 #undef SHOW_TASK_SWITCHES 1
63 kernel_stack_top(struct task_struct
*tsk
)
65 return ((unsigned long)tsk
) + sizeof(union task_union
);
69 task_top(struct task_struct
*tsk
)
71 return ((unsigned long)tsk
) + sizeof(struct task_struct
);
75 dump_fpu(struct pt_regs
*regs
, elf_fpregset_t
*fpregs
)
77 if (regs
->msr
& MSR_FP
)
79 memcpy(fpregs
, ¤t
->tss
.fpr
[0], sizeof(*fpregs
));
84 enable_kernel_fp(void)
87 if (current
->tss
.regs
&& (current
->tss
.regs
->msr
& MSR_FP
))
90 giveup_fpu(NULL
); /* just enables FP for kernel */
92 giveup_fpu(last_task_used_math
);
96 /* check to make sure the kernel stack is healthy */
97 int check_stack(struct task_struct
*tsk
)
99 unsigned long stack_top
= kernel_stack_top(tsk
);
100 unsigned long tsk_top
= task_top(tsk
);
104 /* check tss magic */
105 if ( tsk
->tss
.magic
!= TSS_MAGIC
)
108 printk("tss.magic bad: %08x\n", tsk
->tss
.magic
);
113 printk("check_stack(): tsk bad tsk %p\n",tsk
);
115 /* check if stored ksp is bad */
116 if ( (tsk
->tss
.ksp
> stack_top
) || (tsk
->tss
.ksp
< tsk_top
) )
118 printk("stack out of bounds: %s/%d\n"
119 " tsk_top %08lx ksp %08lx stack_top %08lx\n",
121 tsk_top
, tsk
->tss
.ksp
, stack_top
);
125 /* check if stack ptr RIGHT NOW is bad */
126 if ( (tsk
== current
) && ((_get_SP() > stack_top
) || (_get_SP() < tsk_top
)) )
128 printk("current stack ptr out of bounds: %s/%d\n"
129 " tsk_top %08lx sp %08lx stack_top %08lx\n",
130 current
->comm
,current
->pid
,
131 tsk_top
, _get_SP(), stack_top
);
136 /* check amount of free stack */
137 for ( i
= (unsigned long *)task_top(tsk
) ; i
< kernel_stack_top(tsk
) ; i
++ )
140 printk("check_stack(): i = %p\n", i
);
143 /* only notify if it's less than 900 bytes */
144 if ( (i
- (unsigned long *)task_top(tsk
)) < 900 )
145 printk("%d bytes free on stack\n",
154 panic("bad kernel stack");
160 _switch_to(struct task_struct
*prev
, struct task_struct
*new,
161 struct task_struct
**last
)
163 struct thread_struct
*new_tss
, *old_tss
;
164 int s
= _disable_interrupts();
170 #ifdef SHOW_TASK_SWITCHES
171 printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
172 prev
->comm
,prev
->pid
,
173 new->comm
,new->pid
,new->tss
.regs
->nip
,new->processor
,
174 new->fs
->root
,prev
->fs
->root
);
177 /* avoid complexity of lazy save/restore of fpu
178 * by just saving it every time we switch out if
179 * this task used the fpu during the last quantum.
181 * If it tries to use the fpu again, it'll trap and
182 * reload its fp regs. So we don't have to do a restore
183 * every switch, just a save.
186 if (prev
->tss
.regs
&& (prev
->tss
.regs
->msr
& MSR_FP
))
189 prev
->last_processor
= prev
->processor
;
190 current_set
[smp_processor_id()] = new;
193 old_tss
= ¤t
->tss
;
194 *last
= _switch(old_tss
, new_tss
, new->mm
->context
);
195 _enable_interrupts(s
);
198 void show_regs(struct pt_regs
* regs
)
202 printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
203 regs
->nip
, regs
->xer
, regs
->link
, regs
,regs
->trap
);
204 printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
205 regs
->msr
, regs
->msr
&MSR_EE
? 1 : 0, regs
->msr
&MSR_PR
? 1 : 0,
206 regs
->msr
& MSR_FP
? 1 : 0,regs
->msr
&MSR_ME
? 1 : 0,
207 regs
->msr
&MSR_IR
? 1 : 0,
208 regs
->msr
&MSR_DR
? 1 : 0);
209 printk("TASK = %p[%d] '%s' mm->pgd %p ",
210 current
, current
->pid
, current
->comm
, current
->mm
->pgd
);
211 printk("Last syscall: %ld ", current
->tss
.last_syscall
);
212 printk("\nlast math %p", last_task_used_math
);
215 printk(" CPU: %d last CPU: %d", current
->processor
,current
->last_processor
);
219 for (i
= 0; i
< 32; i
++)
224 printk("GPR%02d: ", i
);
227 if ( __get_user(r
, &(regs
->gpr
[i
])) )
238 void exit_thread(void)
240 if (last_task_used_math
== current
)
241 last_task_used_math
= NULL
;
244 void flush_thread(void)
246 if (last_task_used_math
== current
)
247 last_task_used_math
= NULL
;
251 release_thread(struct task_struct
*t
)
259 copy_thread(int nr
, unsigned long clone_flags
, unsigned long usp
,
260 struct task_struct
* p
, struct pt_regs
* regs
)
262 struct pt_regs
* childregs
, *kregs
;
264 extern void ret_from_smpfork(void);
266 extern void ret_from_syscall(void);
269 childregs
= ((struct pt_regs
*)
270 ((unsigned long)p
+ sizeof(union task_union
)
271 - STACK_FRAME_OVERHEAD
)) - 2;
273 if ((childregs
->msr
& MSR_PR
) == 0)
274 childregs
->gpr
[2] = (unsigned long) p
; /* `current' in new task */
275 childregs
->gpr
[3] = 0; /* Result from fork() */
276 p
->tss
.regs
= childregs
;
277 p
->tss
.ksp
= (unsigned long) childregs
- STACK_FRAME_OVERHEAD
;
278 p
->tss
.ksp
-= sizeof(struct pt_regs
) + STACK_FRAME_OVERHEAD
;
279 kregs
= (struct pt_regs
*)(p
->tss
.ksp
+ STACK_FRAME_OVERHEAD
);
281 kregs
->nip
= (unsigned long)ret_from_smpfork
;
283 kregs
->nip
= (unsigned long)ret_from_syscall
;
285 kregs
->msr
= MSR_KERNEL
;
286 kregs
->gpr
[1] = (unsigned long)childregs
- STACK_FRAME_OVERHEAD
;
287 kregs
->gpr
[2] = (unsigned long)p
;
289 if (usp
>= (unsigned long) regs
) {
290 /* Stack is in kernel space - must adjust */
291 childregs
->gpr
[1] = (unsigned long)(childregs
+ 1);
293 /* Provided stack is in user space */
294 childregs
->gpr
[1] = usp
;
296 p
->tss
.last_syscall
= -1;
299 * copy fpu info - assume lazy fpu switch now always
302 if (regs
->msr
& MSR_FP
)
305 memcpy(&p
->tss
.fpr
, ¤t
->tss
.fpr
, sizeof(p
->tss
.fpr
));
306 p
->tss
.fpscr
= current
->tss
.fpscr
;
307 childregs
->msr
&= ~MSR_FP
;
311 p
->last_processor
= NO_PROC_ID
;
317 * XXX ld.so expects the auxiliary table to start on
318 * a 16-byte boundary, so we have to find it and
321 static inline void shove_aux_table(unsigned long sp
)
326 unsigned long aux_start
, offset
;
328 if (__get_user(argc
, (int *)sp
))
330 sp
+= sizeof(int) + (argc
+ 1) * sizeof(char *);
331 /* skip over the environment pointers */
333 if (__get_user(p
, (char **)sp
))
335 sp
+= sizeof(char *);
338 /* skip to the end of the auxiliary table */
340 if (__get_user(e
, (unsigned long *)sp
))
342 sp
+= 2 * sizeof(unsigned long);
343 } while (e
!= AT_NULL
);
344 offset
= ((aux_start
+ 15) & ~15) - aux_start
;
347 sp
-= sizeof(unsigned long);
348 if (__get_user(e
, (unsigned long *)sp
)
349 || __put_user(e
, (unsigned long *)(sp
+ offset
)))
351 } while (sp
> aux_start
);
356 * Set up a thread for executing a new program
358 void start_thread(struct pt_regs
*regs
, unsigned long nip
, unsigned long sp
)
363 regs
->msr
= MSR_USER
;
365 if (last_task_used_math
== current
)
366 last_task_used_math
= 0;
367 current
->tss
.fpscr
= 0;
370 asmlinkage
int sys_clone(int p1
, int p2
, int p3
, int p4
, int p5
, int p6
,
371 struct pt_regs
*regs
)
373 unsigned long clone_flags
= p1
;
376 res
= do_fork(clone_flags
, regs
->gpr
[1], regs
);
378 /* When we clone the idle task we keep the same pid but
379 * the return value of 0 for both causes problems.
382 if ((current
->pid
== 0) && (current
== &init_task
))
389 asmlinkage
int sys_fork(int p1
, int p2
, int p3
, int p4
, int p5
, int p6
,
390 struct pt_regs
*regs
)
395 res
= do_fork(SIGCHLD
, regs
->gpr
[1], regs
);
397 /* When we clone the idle task we keep the same pid but
398 * the return value of 0 for both causes problems.
401 if ((current
->pid
== 0) && (current
== &init_task
))
407 asmlinkage
int sys_vfork(int p1
, int p2
, int p3
, int p4
, int p5
, int p6
,
408 struct pt_regs
*regs
)
410 return do_fork(CLONE_VFORK
| CLONE_VM
| SIGCHLD
, regs
->gpr
[1], regs
);
413 asmlinkage
int sys_execve(unsigned long a0
, unsigned long a1
, unsigned long a2
,
414 unsigned long a3
, unsigned long a4
, unsigned long a5
,
415 struct pt_regs
*regs
)
420 filename
= getname((char *) a0
);
421 error
= PTR_ERR(filename
);
422 if (IS_ERR(filename
))
424 if (regs
->msr
& MSR_FP
)
426 error
= do_execve(filename
, (char **) a1
, (char **) a2
, regs
);
435 print_backtrace(unsigned long *sp
)
440 printk("Call backtrace: ");
442 if (__get_user( i
, &sp
[1] ))
448 if (__get_user(sp
, (unsigned long **)sp
))
456 * Low level print for debugging - Cort
458 __initfunc(int ll_printk(const char *fmt
, ...))
465 i
=vsprintf(buf
,fmt
,args
);
471 int lines
= 24, cols
= 80;
472 int orig_x
= 0, orig_y
= 0;
474 void puthex(unsigned long val
)
476 unsigned char buf
[10];
478 for (i
= 7; i
>= 0; i
--)
480 buf
[i
] = "0123456789ABCDEF"[val
& 0x0F];
487 __initfunc(void ll_puts(const char *s
))
490 char *vidmem
= (char *)/*(_ISA_MEM_BASE + 0xB8000) */0xD00B8000;
492 extern int mem_init_done
;
494 if ( mem_init_done
) /* assume this means we can printk */
509 * can't ll_puts on chrp without openfirmware yet.
510 * vidmem just needs to be setup for it.
518 while ( ( c
= *s
++ ) != '\0' ) {
521 if ( ++y
>= lines
) {
527 vidmem
[ ( x
+ cols
* y
) * 2 ] = c
;
530 if ( ++y
>= lines
) {