v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / arch / s390 / kernel / process.c
1 /*
2  *  arch/s390/kernel/process.c
3  *
4  *  S390 version
5  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7  *               Hartmut Penner (hp@de.ibm.com),
8  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
9  *
10  *  Derived from "arch/i386/kernel/process.c"
11  *    Copyright (C) 1995, Linus Torvalds
12  */
13
14 /*
15  * This file handles the architecture-dependent parts of process handling..
16  */
17
18 #define __KERNEL_SYSCALLS__
19 #include <stdarg.h>
20
21 #include <linux/config.h>
22 #include <linux/errno.h>
23 #include <linux/sched.h>
24 #include <linux/kernel.h>
25 #include <linux/mm.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/slab.h>
32 #include <linux/vmalloc.h>
33 #include <linux/user.h>
34 #include <linux/a.out.h>
35 #include <linux/interrupt.h>
36 #include <linux/delay.h>
37 #include <linux/reboot.h>
38 #include <linux/init.h>
39
40 #include <asm/uaccess.h>
41 #include <asm/pgtable.h>
42 #include <asm/system.h>
43 #include <asm/io.h>
44 #include <asm/processor.h>
45 #include <asm/irq.h>
46
47 spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
48
49 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
50
51 /*
52  * The idle loop on a S390...
53  */
54
55 static psw_t wait_psw;
56
57 int cpu_idle(void *unused)
58 {
59         /* endless idle loop with no priority at all */
60         init_idle();
61         current->nice = 20;
62         current->counter = -100;
63         wait_psw.mask = _WAIT_PSW_MASK;
64         wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
65         while(1) {
66                 if (current->need_resched) {
67                         schedule();
68                         check_pgt_cache();
69                         continue;
70                 }
71
72                 /* load wait psw */
73                 asm volatile (
74                         "lpsw %0"
75                         : : "m" (wait_psw) );
76 idle_wakeup:
77         }
78 }
79
80 /*
81   As all the register will only be made displayable to the root
82   user ( via printk ) or checking if the uid of the user is 0 from
83   the /proc filesystem please god this will be secure enough DJB.
84   The lines are given one at a time so as not to chew stack space in
85   printk on a crash & also for the proc filesystem when you get
86   0 returned you know you've got all the lines
87  */
88
89 static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
90 {
91         int linelen=0;
92         int regno,chaincnt;
93         u32 backchain,prev_backchain,endchain;
94         u32 ksp = 0;
95         char *mode = "???";
96
97         enum
98         {
99                 sp_linefeed,
100                 sp_psw,
101                 sp_ksp,
102                 sp_gprs,
103                 sp_gprs1,
104                 sp_gprs2,
105                 sp_gprs3,
106                 sp_gprs4,
107                 sp_acrs,
108                 sp_acrs1,
109                 sp_acrs2,
110                 sp_acrs3,
111                 sp_acrs4,
112                 sp_kern_backchain,
113                 sp_kern_backchain1
114         };
115
116         if (task)
117                 ksp = task->thread.ksp;
118         if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
119                 ksp = regs->gprs[15];
120
121         if (regs)
122                 mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
123                        "User" : "Kernel";
124
125         switch(line)
126         {
127         case sp_linefeed: 
128                 linelen=sprintf(buff,"\n");
129                 break;
130         case sp_psw:
131                 if(regs)
132                         linelen=sprintf(buff, "%s PSW:    %08lx %08lx\n", mode,
133                                 (unsigned long) regs->psw.mask,
134                                 (unsigned long) regs->psw.addr);
135                 else
136                         linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
137                 break;
138         case sp_ksp:
139                 linelen=sprintf(&buff[linelen],
140                                 "task: %08x ksp: %08x pt_regs: %08x\n",
141                                 (addr_t)task, (addr_t)ksp, (addr_t)regs);
142                 break;
143         case sp_gprs:
144                 if(regs)
145                         linelen=sprintf(buff, "%s GPRS:\n", mode);
146                 break;
147         case sp_gprs1 ... sp_gprs4:
148                 if(regs)
149                 {
150                         regno=(line-sp_gprs1)*4;
151                         linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
152                                         regs->gprs[regno], 
153                                         regs->gprs[regno+1],
154                                         regs->gprs[regno+2],
155                                         regs->gprs[regno+3]);
156                 }
157                 break;
158         case sp_acrs:
159                 if(regs)
160                         linelen=sprintf(buff, "%s ACRS:\n", mode);
161                 break;  
162         case sp_acrs1 ... sp_acrs4:
163                 if(regs)
164                 {
165                         regno=(line-sp_acrs1)*4;
166                         linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
167                                         regs->acrs[regno],
168                                         regs->acrs[regno+1],
169                                         regs->acrs[regno+2],
170                                         regs->acrs[regno+3]);
171                 }
172                 break;
173         case sp_kern_backchain:
174                 if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
175                         break;  
176                 if (ksp)
177                         linelen=sprintf(buff, "Kernel BackChain  CallChain\n");
178                 break;
179         default:
180                 if (ksp)
181                 {
182                         
183                         backchain=ksp&PSW_ADDR_MASK;
184                         endchain=((backchain&(-8192))+8192);
185                         prev_backchain=backchain-1;
186                         line-=sp_kern_backchain1;
187                         for(chaincnt=0;;chaincnt++)
188                         {
189                                 if((backchain==0)||(backchain>=endchain)
190                                    ||(chaincnt>=8)||(prev_backchain>=backchain))
191                                         break;
192                                 if(chaincnt==line)
193                                 {
194                                         linelen+=sprintf(&buff[linelen],"       %08x   [<%08lx>]\n",
195                                                          backchain,
196                                                          *(u32 *)(backchain+56)&PSW_ADDR_MASK);
197                                         break;
198                                 }
199                                 prev_backchain=backchain;
200                                 backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
201                         }
202                 }
203         }
204         return(linelen);
205 }
206
207
208 void show_regs(struct pt_regs *regs)
209 {
210         char buff[80];
211         int line;
212
213         printk("CPU:    %d\n",smp_processor_id());
214         printk("Process %s (pid: %d, stackpage=%08X)\n",
215                 current->comm, current->pid, 4096+(addr_t)current);
216         
217         for (line = 0; sprintf_regs(line, buff, current, regs); line++)
218                 printk(buff);
219 }
220
221 char *task_show_regs(struct task_struct *task, char *buffer)
222 {
223         int line, len;
224
225         for (line = 0; ; line++)
226         {
227                 len = sprintf_regs(line, buffer, task, task->thread.regs);
228                 if (!len) break;
229                 buffer += len;
230         }
231         return buffer;
232 }
233
234
235 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
236 {
237         int clone_arg = flags | CLONE_VM;
238         int retval;
239
240         __asm__ __volatile__(
241                 "     sr    2,2\n"
242                 "     lr    3,%1\n"
243                 "     l     4,%6\n"     /* load kernel stack ptr of parent */
244                 "     svc   %b2\n"                     /* Linux system call*/
245                 "     cl    4,%6\n"    /* compare ksp's: child or parent ? */
246                 "     je    0f\n"                          /* parent - jump*/
247                 "     l     15,%6\n"            /* fix kernel stack pointer*/
248                 "     ahi   15,%7\n"
249                 "     xc    0(96,15),0(15)\n"           /* clear save area */
250                 "     lr    2,%4\n"                        /* load argument*/
251                 "     lr    14,%5\n"                      /* get fn-pointer*/
252                 "     basr  14,14\n"                             /* call fn*/
253                 "     svc   %b3\n"                     /* Linux system call*/
254                 "0:   lr    %0,2"
255                 : "=a" (retval)
256                 : "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
257                   "d" (arg), "d" (fn), "i" (__LC_KERNEL_STACK) , "i" (-STACK_FRAME_OVERHEAD)
258                 : "2", "3", "4" );
259         return retval;
260 }
261
262 /*
263  * Free current thread data structures etc..
264  */
265 void exit_thread(void)
266 {
267 }
268
269 void flush_thread(void)
270 {
271
272         current->used_math = 0;
273         current->flags &= ~PF_USEDFPU;
274 }
275
276 void release_thread(struct task_struct *dead_task)
277 {
278 }
279
280 int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
281         unsigned long unused,
282         struct task_struct * p, struct pt_regs * regs)
283 {
284         struct stack_frame
285           {
286             unsigned long back_chain;
287             unsigned long eos;
288             unsigned long glue1;
289             unsigned long glue2;
290             unsigned long scratch[2];
291             unsigned long gprs[10];    /* gprs 6 -15                       */
292             unsigned long fprs[4];     /* fpr 4 and 6                      */
293             unsigned long empty[4];
294 #if CONFIG_REMOTE_DEBUG
295             struct gdb_pt_regs childregs;
296 #else
297             struct pt_regs childregs;
298 #endif
299           } *frame;
300
301         frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
302         frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
303         p->thread.regs = (struct pt_regs *)&frame->childregs;
304         p->thread.ksp = (unsigned long) frame;
305         memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
306         frame->childregs.gprs[15] = new_stackp;
307         frame->back_chain = frame->eos = 0;
308
309         /* new return point is ret_from_sys_call */
310         frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
311
312         /* fake return stack for resume(), don't go back to schedule */
313         frame->gprs[9]  = (unsigned long) frame;
314         frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
315         /* save fprs, if used in last task */
316         save_fp_regs(&p->thread.fp_regs);
317         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
318         p->thread.fs = USER_DS;
319         /* Don't copy debug registers */
320         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
321         return 0;
322 }
323
324 asmlinkage int sys_fork(struct pt_regs regs)
325 {
326         int ret;
327
328         lock_kernel();
329         ret = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
330         unlock_kernel();
331         return ret;
332 }
333
334 asmlinkage int sys_clone(struct pt_regs regs)
335 {
336         unsigned long clone_flags;
337         unsigned long newsp;
338         int ret;
339
340         lock_kernel();
341         clone_flags = regs.gprs[3];
342         newsp = regs.orig_gpr2;
343         if (!newsp)
344                 newsp = regs.gprs[15];
345         ret = do_fork(clone_flags, newsp, &regs, 0);
346         unlock_kernel();
347         return ret;
348 }
349
350 /*
351  * This is trivial, and on the face of it looks like it
352  * could equally well be done in user mode.
353  *
354  * Not so, for quite unobvious reasons - register pressure.
355  * In user mode vfork() cannot have a stack frame, and if
356  * done by calling the "clone()" system call directly, you
357  * do not have enough call-clobbered registers to hold all
358  * the information you need.
359  */
360 asmlinkage int sys_vfork(struct pt_regs regs)
361 {
362         return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
363                        regs.gprs[15], &regs, 0);
364 }
365
366 /*
367  * sys_execve() executes a new program.
368  */
369 asmlinkage int sys_execve(struct pt_regs regs)
370 {
371         int error;
372         char * filename;
373
374         filename = getname((char *) regs.orig_gpr2);
375         error = PTR_ERR(filename);
376         if (IS_ERR(filename))
377                 goto out;
378         error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
379         if (error == 0)
380         {
381                 current->ptrace &= ~PT_DTRACE;
382                 current->thread.fp_regs.fpc=0;
383                 if(MACHINE_HAS_IEEE)
384                 {
385                         __asm__ __volatile__
386                         ("sr  0,0\n\t"
387                          "sfpc 0,0\n\t"
388                                 :
389                                 :
390                                 :"0");
391                 }
392         }
393         putname(filename);
394 out:
395         return error;
396 }
397
398
399 /*
400  * fill in the FPU structure for a core dump.
401  */
402 int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
403 {
404         save_fp_regs(fpregs);
405         return 1;
406 }
407
408 /*
409  * fill in the user structure for a core dump..
410  */
411 void dump_thread(struct pt_regs * regs, struct user * dump)
412 {
413
414 /* changed the size calculations - should hopefully work better. lbt */
415         dump->magic = CMAGIC;
416         dump->start_code = 0;
417         dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
418         dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
419         dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
420         dump->u_dsize -= dump->u_tsize;
421         dump->u_ssize = 0;
422         if (dump->start_stack < TASK_SIZE)
423                 dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
424         memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
425         dump_fpu (regs, &dump->regs.fp_regs);
426         memcpy(&dump->regs.per_info,&current->thread.per_info,sizeof(per_struct));
427 }
428
429 /*
430  * These bracket the sleeping functions..
431  */
432 extern void scheduling_functions_start_here(void);
433 extern void scheduling_functions_end_here(void);
434 #define first_sched     ((unsigned long) scheduling_functions_start_here)
435 #define last_sched      ((unsigned long) scheduling_functions_end_here)
436
437 unsigned long get_wchan(struct task_struct *p)
438 {
439         unsigned long r14, r15, bc;
440         unsigned long stack_page;
441         int count = 0;
442         if (!p || p == current || p->state == TASK_RUNNING)
443                 return 0;
444         stack_page = (unsigned long) p;
445         r15 = p->thread.ksp;
446         if (!stack_page || r15 < stack_page || r15 >= 8188+stack_page)
447                 return 0;
448         bc = (*(unsigned long *) r15) & 0x7fffffff;
449         do {
450                 if (bc < stack_page || bc >= 8188+stack_page)
451                         return 0;
452                 r14 = (*(unsigned long *) (bc+56)) & 0x7fffffff;
453                 if (r14 < first_sched || r14 >= last_sched)
454                         return r14;
455                 bc = (*(unsigned long *) bc) & 0x7fffffff;
456         } while (count++ < 16);
457         return 0;
458 }
459 #undef last_sched
460 #undef first_sched
461