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