File: /usr/src/linux/arch/ppc/kernel/process.c

1     /*
2      * BK Id: SCCS/s.process.c 1.27 08/28/01 22:01:21 paulus
3      */
4     /*
5      *  linux/arch/ppc/kernel/process.c
6      *
7      *  Derived from "arch/i386/kernel/process.c"
8      *    Copyright (C) 1995  Linus Torvalds
9      *
10      *  Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
11      *  Paul Mackerras (paulus@cs.anu.edu.au)
12      *
13      *  PowerPC version 
14      *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
15      *
16      *  This program is free software; you can redistribute it and/or
17      *  modify it under the terms of the GNU General Public License
18      *  as published by the Free Software Foundation; either version
19      *  2 of the License, or (at your option) any later version.
20      *
21      */
22     
23     #include <linux/config.h>
24     #include <linux/errno.h>
25     #include <linux/sched.h>
26     #include <linux/kernel.h>
27     #include <linux/mm.h>
28     #include <linux/smp.h>
29     #include <linux/smp_lock.h>
30     #include <linux/stddef.h>
31     #include <linux/unistd.h>
32     #include <linux/ptrace.h>
33     #include <linux/slab.h>
34     #include <linux/user.h>
35     #include <linux/elf.h>
36     #include <linux/init.h>
37     
38     #include <asm/pgtable.h>
39     #include <asm/uaccess.h>
40     #include <asm/system.h>
41     #include <asm/io.h>
42     #include <asm/processor.h>
43     #include <asm/mmu.h>
44     #include <asm/prom.h>
45     
46     int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
47     extern unsigned long _get_SP(void);
48     
49     struct task_struct *last_task_used_math = NULL;
50     struct task_struct *last_task_used_altivec = NULL;
51     static struct fs_struct init_fs = INIT_FS;
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     /* this is 16-byte aligned because it has a stack in it */
56     union task_union __attribute((aligned(16))) init_task_union = {
57     	INIT_TASK(init_task_union.task)
58     };
59     /* only used to get secondary processor up */
60     struct task_struct *current_set[NR_CPUS] = {&init_task, };
61     
62     #undef SHOW_TASK_SWITCHES
63     #undef CHECK_STACK
64     
65     #if defined(CHECK_STACK)
66     unsigned long
67     kernel_stack_top(struct task_struct *tsk)
68     {
69     	return ((unsigned long)tsk) + sizeof(union task_union);
70     }
71     
72     unsigned long
73     task_top(struct task_struct *tsk)
74     {
75     	return ((unsigned long)tsk) + sizeof(struct task_struct);
76     }
77     
78     /* check to make sure the kernel stack is healthy */
79     int check_stack(struct task_struct *tsk)
80     {
81     	unsigned long stack_top = kernel_stack_top(tsk);
82     	unsigned long tsk_top = task_top(tsk);
83     	int ret = 0;
84     
85     #if 0	
86     	/* check thread magic */
87     	if ( tsk->thread.magic != THREAD_MAGIC )
88     	{
89     		ret |= 1;
90     		printk("thread.magic bad: %08x\n", tsk->thread.magic);
91     	}
92     #endif
93     
94     	if ( !tsk )
95     		printk("check_stack(): tsk bad tsk %p\n",tsk);
96     	
97     	/* check if stored ksp is bad */
98     	if ( (tsk->thread.ksp > stack_top) || (tsk->thread.ksp < tsk_top) )
99     	{
100     		printk("stack out of bounds: %s/%d\n"
101     		       " tsk_top %08lx ksp %08lx stack_top %08lx\n",
102     		       tsk->comm,tsk->pid,
103     		       tsk_top, tsk->thread.ksp, stack_top);
104     		ret |= 2;
105     	}
106     	
107     	/* check if stack ptr RIGHT NOW is bad */
108     	if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
109     	{
110     		printk("current stack ptr out of bounds: %s/%d\n"
111     		       " tsk_top %08lx sp %08lx stack_top %08lx\n",
112     		       current->comm,current->pid,
113     		       tsk_top, _get_SP(), stack_top);
114     		ret |= 4;
115     	}
116     
117     #if 0	
118     	/* check amount of free stack */
119     	for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ )
120     	{
121     		if ( !i )
122     			printk("check_stack(): i = %p\n", i);
123     		if ( *i != 0 )
124     		{
125     			/* only notify if it's less than 900 bytes */
126     			if ( (i - (unsigned long *)task_top(tsk))  < 900 )
127     				printk("%d bytes free on stack\n",
128     				       i - task_top(tsk));
129     			break;
130     		}
131     	}
132     #endif
133     
134     	if (ret)
135     	{
136     		panic("bad kernel stack");
137     	}
138     	return(ret);
139     }
140     #endif /* defined(CHECK_STACK) */
141     
142     #ifdef CONFIG_ALTIVEC
143     int
144     dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
145     {
146     	if (regs->msr & MSR_VEC)
147     		giveup_altivec(current);
148     	memcpy(vrregs, &current->thread.vr[0], sizeof(*vrregs));
149     	return 1;
150     }
151     
152     void 
153     enable_kernel_altivec(void)
154     {
155     #ifdef CONFIG_SMP
156     	if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
157     		giveup_altivec(current);
158     	else
159     		giveup_altivec(NULL);	/* just enable AltiVec for kernel - force */
160     #else
161     	giveup_altivec(last_task_used_altivec);
162     #endif /* __SMP __ */
163     }
164     #endif /* CONFIG_ALTIVEC */
165     
166     void
167     enable_kernel_fp(void)
168     {
169     #ifdef CONFIG_SMP
170     	if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
171     		giveup_fpu(current);
172     	else
173     		giveup_fpu(NULL);	/* just enables FP for kernel */
174     #else
175     	giveup_fpu(last_task_used_math);
176     #endif /* CONFIG_SMP */
177     }
178     
179     int
180     dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
181     {
182     	if (regs->msr & MSR_FP)
183     		giveup_fpu(current);
184     	memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
185     	return 1;
186     }
187     
188     void
189     _switch_to(struct task_struct *prev, struct task_struct *new,
190     	  struct task_struct **last)
191     {
192     	struct thread_struct *new_thread, *old_thread;
193     	unsigned long s;
194     	
195     	__save_flags(s);
196     	__cli();
197     #if CHECK_STACK
198     	check_stack(prev);
199     	check_stack(new);
200     #endif
201     
202     #ifdef CONFIG_SMP
203     	/* avoid complexity of lazy save/restore of fpu
204     	 * by just saving it every time we switch out if
205     	 * this task used the fpu during the last quantum.
206     	 * 
207     	 * If it tries to use the fpu again, it'll trap and
208     	 * reload its fp regs.  So we don't have to do a restore
209     	 * every switch, just a save.
210     	 *  -- Cort
211     	 */
212     	if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) )
213     		giveup_fpu(prev);
214     #ifdef CONFIG_ALTIVEC	
215     	/*
216     	 * If the previous thread used altivec in the last quantum
217     	 * (thus changing altivec regs) then save them.
218     	 * We used to check the VRSAVE register but not all apps
219     	 * set it, so we don't rely on it now (and in fact we need
220     	 * to save & restore VSCR even if VRSAVE == 0).  -- paulus
221     	 *
222     	 * On SMP we always save/restore altivec regs just to avoid the
223     	 * complexity of changing processors.
224     	 *  -- Cort
225     	 */
226     	if ((prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)))
227     		giveup_altivec(prev);
228     #endif /* CONFIG_ALTIVEC */	
229     	current_set[smp_processor_id()] = new;
230     #endif /* CONFIG_SMP */
231     	/* Avoid the trap.  On smp this this never happens since
232     	 * we don't set last_task_used_altivec -- Cort
233     	 */
234     	if (new->thread.regs && last_task_used_altivec == new)
235     		new->thread.regs->msr |= MSR_VEC;
236     	new_thread = &new->thread;
237     	old_thread = &current->thread;
238     	*last = _switch(old_thread, new_thread);
239     	__restore_flags(s);
240     }
241     
242     void show_regs(struct pt_regs * regs)
243     {
244     	int i;
245     
246     	printk("NIP: %08lX XER: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx\n",
247     	       regs->nip, regs->xer, regs->link, regs->gpr[1], regs,regs->trap);
248     	printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
249     	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
250     	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
251     	       regs->msr&MSR_IR ? 1 : 0,
252     	       regs->msr&MSR_DR ? 1 : 0);
253     	if (regs->trap == 0x300 || regs->trap == 0x600)
254     		printk("DAR: %08lX, DSISR: %08lX\n", regs->dar, regs->dsisr);
255     	printk("TASK = %p[%d] '%s' ",
256     	       current, current->pid, current->comm);
257     	printk("Last syscall: %ld ", current->thread.last_syscall);
258     	printk("\nlast math %p last altivec %p", last_task_used_math,
259     	       last_task_used_altivec);
260     
261     #ifdef CONFIG_4xx
262     	printk("\nPLB0: bear= 0x%8.8x acr=   0x%8.8x besr=  0x%8.8x\n",
263     	    mfdcr(DCRN_POB0_BEAR), mfdcr(DCRN_PLB0_ACR),
264     	    mfdcr(DCRN_PLB0_BESR));
265     	printk("PLB0 to OPB: bear= 0x%8.8x besr0= 0x%8.8x besr1= 0x%8.8x\n",
266     	    mfdcr(DCRN_PLB0_BEAR), mfdcr(DCRN_POB0_BESR0),
267     	    mfdcr(DCRN_POB0_BESR1));
268     #endif
269     	
270     #ifdef CONFIG_SMP
271     	printk(" CPU: %d", current->processor);
272     #endif /* CONFIG_SMP */
273     	
274     	printk("\n");
275     	for (i = 0;  i < 32;  i++)
276     	{
277     		long r;
278     		if ((i % 8) == 0)
279     		{
280     			printk("GPR%02d: ", i);
281     		}
282     
283     		if ( __get_user(r, &(regs->gpr[i])) )
284     		    goto out;
285     		printk("%08lX ", r);
286     		if ((i % 8) == 7)
287     		{
288     			printk("\n");
289     		}
290     	}
291     out:
292     	print_backtrace((unsigned long *)regs->gpr[1]);
293     }
294     
295     void exit_thread(void)
296     {
297     	if (last_task_used_math == current)
298     		last_task_used_math = NULL;
299     	if (last_task_used_altivec == current)
300     		last_task_used_altivec = NULL;
301     }
302     
303     void flush_thread(void)
304     {
305     	if (last_task_used_math == current)
306     		last_task_used_math = NULL;
307     	if (last_task_used_altivec == current)
308     		last_task_used_altivec = NULL;
309     }
310     
311     void
312     release_thread(struct task_struct *t)
313     {
314     }
315     
316     /*
317      * Copy a thread..
318      */
319     int
320     copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
321     	    unsigned long unused,
322     	    struct task_struct *p, struct pt_regs *regs)
323     {
324     	struct pt_regs *childregs, *kregs;
325     	extern void ret_from_fork(void);
326     	unsigned long sp = (unsigned long)p + sizeof(union task_union);
327     	unsigned long childframe;
328     
329     	/* Copy registers */
330     	sp -= sizeof(struct pt_regs);
331     	childregs = (struct pt_regs *) sp;
332     	*childregs = *regs;
333     	if ((childregs->msr & MSR_PR) == 0) {
334     		/* for kernel thread, set `current' and stackptr in new task */
335     		childregs->gpr[1] = sp + sizeof(struct pt_regs);
336     		childregs->gpr[2] = (unsigned long) p;
337     	}
338     	childregs->gpr[3] = 0;  /* Result from fork() */
339     	p->thread.regs = childregs;
340     	sp -= STACK_FRAME_OVERHEAD;
341     	childframe = sp;
342     
343     	/*
344     	 * The way this works is that at some point in the future
345     	 * some task will call _switch to switch to the new task.
346     	 * That will pop off the stack frame created below and start
347     	 * the new task running at ret_from_fork.  The new task will
348     	 * do some house keeping and then return from the fork or clone
349     	 * system call, using the stack frame created above.
350     	 */
351     	sp -= sizeof(struct pt_regs);
352     	kregs = (struct pt_regs *) sp;
353     	sp -= STACK_FRAME_OVERHEAD;
354     	p->thread.ksp = sp;
355     	kregs->nip = (unsigned long)ret_from_fork;
356     
357     	/*
358     	 * copy fpu info - assume lazy fpu switch now always
359     	 *  -- Cort
360     	 */
361     	if (regs->msr & MSR_FP) {
362     		giveup_fpu(current);
363     		childregs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
364     	}
365     	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
366     	p->thread.fpscr = current->thread.fpscr;
367     
368     #ifdef CONFIG_ALTIVEC
369     	/*
370     	 * copy altiVec info - assume lazy altiVec switch
371     	 * - kumar
372     	 */
373     	if (regs->msr & MSR_VEC)
374     		giveup_altivec(current);
375     	memcpy(&p->thread.vr, &current->thread.vr, sizeof(p->thread.vr));
376     	p->thread.vscr = current->thread.vscr;
377     	childregs->msr &= ~MSR_VEC;
378     #endif /* CONFIG_ALTIVEC */
379     
380     	p->thread.last_syscall = -1;
381     
382     	return 0;
383     }
384     
385     /*
386      * Set up a thread for executing a new program
387      */
388     void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
389     {
390     	set_fs(USER_DS);
391     	memset(regs->gpr, 0, sizeof(regs->gpr));
392     	memset(&regs->ctr, 0, 5 * sizeof(regs->ctr));
393     	regs->nip = nip;
394     	regs->gpr[1] = sp;
395     	regs->msr = MSR_USER;
396     	if (last_task_used_math == current)
397     		last_task_used_math = 0;
398     	if (last_task_used_altivec == current)
399     		last_task_used_altivec = 0;
400     	current->thread.fpscr = 0;
401     }
402     
403     int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
404     	      struct pt_regs *regs)
405     {
406     	return do_fork(p1, regs->gpr[1], regs, 0);
407     }
408     
409     int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
410     	     struct pt_regs *regs)
411     {
412     	return do_fork(SIGCHLD, regs->gpr[1], regs, 0);
413     }
414     
415     int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
416     	      struct pt_regs *regs)
417     {
418     	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
419     }
420     
421     int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
422     	       unsigned long a3, unsigned long a4, unsigned long a5,
423     	       struct pt_regs *regs)
424     {
425     	int error;
426     	char * filename;
427     
428     	filename = getname((char *) a0);
429     	error = PTR_ERR(filename);
430     	if (IS_ERR(filename))
431     		goto out;
432     	if (regs->msr & MSR_FP)
433     		giveup_fpu(current);
434     #ifdef CONFIG_ALTIVEC
435     	if (regs->msr & MSR_VEC)
436     		giveup_altivec(current);
437     #endif /* CONFIG_ALTIVEC */ 
438     	error = do_execve(filename, (char **) a1, (char **) a2, regs);
439     	if (error == 0)
440     		current->ptrace &= ~PT_DTRACE;
441     	putname(filename);
442     out:
443     	return error;
444     }
445     
446     void
447     print_backtrace(unsigned long *sp)
448     {
449     	int cnt = 0;
450     	unsigned long i;
451     
452     	printk("Call backtrace: ");
453     	while (sp) {
454     		if (__get_user( i, &sp[1] ))
455     			break;
456     		if (cnt++ % 7 == 0)
457     			printk("\n");
458     		printk("%08lX ", i);
459     		if (cnt > 32) break;
460     		if (__get_user(sp, (unsigned long **)sp))
461     			break;
462     	}
463     	printk("\n");
464     }
465     
466     #if 0
467     /*
468      * Low level print for debugging - Cort
469      */
470     int __init ll_printk(const char *fmt, ...)
471     {
472             va_list args;
473     	char buf[256];
474             int i;
475     
476             va_start(args, fmt);
477             i=vsprintf(buf,fmt,args);
478     	ll_puts(buf);
479             va_end(args);
480             return i;
481     }
482     
483     int lines = 24, cols = 80;
484     int orig_x = 0, orig_y = 0;
485     
486     void puthex(unsigned long val)
487     {
488     	unsigned char buf[10];
489     	int i;
490     	for (i = 7;  i >= 0;  i--)
491     	{
492     		buf[i] = "0123456789ABCDEF"[val & 0x0F];
493     		val >>= 4;
494     	}
495     	buf[8] = '\0';
496     	prom_print(buf);
497     }
498     
499     void __init ll_puts(const char *s)
500     {
501     	int x,y;
502     	char *vidmem = (char *)/*(_ISA_MEM_BASE + 0xB8000) */0xD00B8000;
503     	char c;
504     	extern int mem_init_done;
505     
506     	if ( mem_init_done ) /* assume this means we can printk */
507     	{
508     		printk(s);
509     		return;
510     	}
511     
512     #if 0	
513     	if ( have_of )
514     	{
515     		prom_print(s);
516     		return;
517     	}
518     #endif
519     
520     	/*
521     	 * can't ll_puts on chrp without openfirmware yet.
522     	 * vidmem just needs to be setup for it.
523     	 * -- Cort
524     	 */
525     	if ( _machine != _MACH_prep )
526     		return;
527     	x = orig_x;
528     	y = orig_y;
529     
530     	while ( ( c = *s++ ) != '\0' ) {
531     		if ( c == '\n' ) {
532     			x = 0;
533     			if ( ++y >= lines ) {
534     				/*scroll();*/
535     				/*y--;*/
536     				y = 0;
537     			}
538     		} else {
539     			vidmem [ ( x + cols * y ) * 2 ] = c; 
540     			if ( ++x >= cols ) {
541     				x = 0;
542     				if ( ++y >= lines ) {
543     					/*scroll();*/
544     					/*y--;*/
545     					y = 0;
546     				}
547     			}
548     		}
549     	}
550     
551     	orig_x = x;
552     	orig_y = y;
553     }
554     #endif
555     
556     /*
557      * These bracket the sleeping functions..
558      */
559     extern void scheduling_functions_start_here(void);
560     extern void scheduling_functions_end_here(void);
561     #define first_sched    ((unsigned long) scheduling_functions_start_here)
562     #define last_sched     ((unsigned long) scheduling_functions_end_here)
563     
564     unsigned long get_wchan(struct task_struct *p)
565     {
566     	unsigned long ip, sp;
567     	unsigned long stack_page = (unsigned long) p;
568     	int count = 0;
569     	if (!p || p == current || p->state == TASK_RUNNING)
570     		return 0;
571     	sp = p->thread.ksp;
572     	do {
573     		sp = *(unsigned long *)sp;
574     		if (sp < stack_page || sp >= stack_page + 8188)
575     			return 0;
576     		if (count > 0) {
577     			ip = *(unsigned long *)(sp + 4);
578     			if (ip < first_sched || ip >= last_sched)
579     				return ip;
580     		}
581     	} while (count++ < 16);
582     	return 0;
583     }
584