v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / arch / s390x / 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;
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                         "lpswe %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         u64 backchain,prev_backchain,endchain;
94         u64 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_gprs5,
108                 sp_gprs6,
109                 sp_gprs7,
110                 sp_gprs8,
111                 sp_acrs,
112                 sp_acrs1,
113                 sp_acrs2,
114                 sp_acrs3,
115                 sp_acrs4,
116                 sp_kern_backchain,
117                 sp_kern_backchain1
118         };
119
120         if (task)
121                 ksp = task->thread.ksp;
122         if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
123                 ksp = regs->gprs[15];
124
125         if (regs)
126                 mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
127                        "User" : "Kernel";
128
129         switch(line)
130         {
131         case sp_linefeed: 
132                 linelen=sprintf(buff,"\n");
133                 break;
134         case sp_psw:
135                 if(regs)
136                         linelen=sprintf(buff, "%s PSW:    %016lx %016lx\n", mode,
137                                 (unsigned long) regs->psw.mask,
138                                 (unsigned long) regs->psw.addr);
139                 else
140                         linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
141                 break;
142         case sp_ksp:
143                 linelen=sprintf(&buff[linelen],
144                                 "task: %016lx ksp: %016lx pt_regs: %016lx\n",
145                                 (addr_t)task, (addr_t)ksp, (addr_t)regs);
146                 break;
147         case sp_gprs:
148                 if(regs)
149                         linelen=sprintf(buff, "%s GPRS:\n", mode);
150                 break;
151         case sp_gprs1 ... sp_gprs8:
152                 if(regs)
153                 {
154                         regno=(line-sp_gprs1)*2;
155                         linelen = sprintf(buff,"%016lx  %016lx\n",
156                                           regs->gprs[regno],
157                                           regs->gprs[regno+1]);
158                 }
159                 break;
160         case sp_acrs:
161                 if(regs)
162                         linelen=sprintf(buff, "%s ACRS:\n", mode);
163                 break;  
164         case sp_acrs1 ... sp_acrs4:
165                 if(regs)
166                 {
167                         regno=(line-sp_acrs1)*4;
168                         linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
169                                         regs->acrs[regno],
170                                         regs->acrs[regno+1],
171                                         regs->acrs[regno+2],
172                                         regs->acrs[regno+3]);
173                 }
174                 break;
175         case sp_kern_backchain:
176                 if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
177                         break;
178                 if (ksp)
179                         linelen=sprintf(buff, "Kernel BackChain          CallChain\n");
180                 break;
181         default:
182                 if (ksp)
183                 {
184                         
185                         backchain=ksp&PSW_ADDR_MASK;
186                         endchain=((backchain&(-THREAD_SIZE))+THREAD_SIZE);
187                         prev_backchain=backchain-1;
188                         line-=sp_kern_backchain1;
189                         for(chaincnt=0;;chaincnt++)
190                         {
191                                 if((backchain==0)||(backchain>=endchain)
192                                    ||(chaincnt>=8)||(prev_backchain>=backchain))
193                                         break;
194                                 if(chaincnt==line)
195                                 {
196                                         linelen+=sprintf(&buff[linelen],"       %016lx   [<%016lx>]\n",
197                                                          backchain,
198                                                          *(u64 *)(backchain+112)&PSW_ADDR_MASK);
199                                         break;
200                                 }
201                                 prev_backchain=backchain;
202                                 backchain=(*((u64 *)backchain))&PSW_ADDR_MASK;
203                         }
204                 }
205         }
206         return(linelen);
207 }
208
209 void show_regs(struct pt_regs *regs)
210 {
211         char buff[80];
212         int line;
213
214         printk("CPU:    %d\n",smp_processor_id());
215         printk("Process %s (pid: %d, stackpage=%016lX)\n",
216                 current->comm, current->pid, 4096+(addr_t)current);
217         
218         for (line = 0; sprintf_regs(line, buff, current, regs); line++)
219                 printk(buff);
220 }
221
222 char *task_show_regs(struct task_struct *task, char *buffer)
223 {
224         int line, len;
225
226         for (line = 0; ; line++)
227         {
228                 len = sprintf_regs(line, buffer, task, NULL);
229                 if (!len) break;
230                 buffer += len;
231         }
232         return buffer;
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                 "     slgr  2,2\n"
242                 "     lgr   3,%1\n"
243                 "     lg    4,%6\n"     /* load kernel stack ptr of parent */
244                 "     svc   %b2\n"                     /* Linux system call*/
245                 "     clg   4,%6\n"    /* compare ksp's: child or parent ? */
246                 "     je    0f\n"                          /* parent - jump*/
247                 "     lg    15,%6\n"            /* fix kernel stack pointer*/
248                 "     aghi  15,%7\n"
249                 "     xc    0(160,15),0(15)\n"          /* clear save area */
250                 "     lgr   2,%4\n"                        /* load argument*/
251                 "     basr  14,%5\n"                             /* call fn*/
252                 "     svc   %b3\n"                     /* Linux system call*/
253                 "0:   lgr   %0,2"
254                 : "=a" (retval)
255                 : "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
256                   "d" (arg), "a" (fn), "i" (__LC_KERNEL_STACK) ,
257                   "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[2];     /* fpr 4 and 6                      */
293             unsigned long empty[2];
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 *) (4*PAGE_SIZE + (unsigned long) p) -1;
302         frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
303         p->thread.regs = &frame->childregs;
304         p->thread.ksp = (unsigned long) frame;
305         frame->childregs = *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;
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) | _REGION_TABLE;
318         /* Don't copy debug registers */
319         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
320         return 0;
321 }
322
323 asmlinkage int sys_fork(struct pt_regs regs)
324 {
325         int ret;
326
327         lock_kernel();
328         ret = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
329         unlock_kernel();
330         return ret;
331 }
332
333 asmlinkage int sys_clone(struct pt_regs regs)
334 {
335         unsigned long clone_flags;
336         unsigned long newsp;
337         int ret;
338
339         lock_kernel();
340         clone_flags = regs.gprs[3];
341         newsp = regs.orig_gpr2;
342         if (!newsp)
343                 newsp = regs.gprs[15];
344         ret = do_fork(clone_flags, newsp, &regs, 0);
345         unlock_kernel();
346         return ret;
347 }
348
349 /*
350  * This is trivial, and on the face of it looks like it
351  * could equally well be done in user mode.
352  *
353  * Not so, for quite unobvious reasons - register pressure.
354  * In user mode vfork() cannot have a stack frame, and if
355  * done by calling the "clone()" system call directly, you
356  * do not have enough call-clobbered registers to hold all
357  * the information you need.
358  */
359 asmlinkage int sys_vfork(struct pt_regs regs)
360 {
361         return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
362                        regs.gprs[15], &regs, 0);
363 }
364
365 /*
366  * sys_execve() executes a new program.
367  */
368 asmlinkage int sys_execve(struct pt_regs regs)
369 {
370         int error;
371         char * filename;
372
373         filename = getname((char *) regs.orig_gpr2);
374         error = PTR_ERR(filename);
375         if (IS_ERR(filename))
376                 goto out;
377         error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
378         if (error == 0)
379         {
380                 current->ptrace &= ~PT_DTRACE;
381                 current->thread.fp_regs.fpc=0;
382                 __asm__ __volatile__
383                         ("sr  0,0\n\t"
384                          "sfpc 0,0\n\t"
385                          : : :"0");
386         }
387         putname(filename);
388 out:
389         return error;
390 }
391
392
393 /*
394  * fill in the FPU structure for a core dump.
395  */
396 int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
397 {
398         save_fp_regs(fpregs);
399         return 1;
400 }
401
402 /*
403  * fill in the user structure for a core dump..
404  */
405 void dump_thread(struct pt_regs * regs, struct user * dump)
406 {
407
408 /* changed the size calculations - should hopefully work better. lbt */
409         dump->magic = CMAGIC;
410         dump->start_code = 0;
411         dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
412         dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
413         dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
414         dump->u_dsize -= dump->u_tsize;
415         dump->u_ssize = 0;
416         if (dump->start_stack < TASK_SIZE)
417                 dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
418         memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
419         dump_fpu (regs, &dump->regs.fp_regs);
420         memcpy(&dump->regs.per_info,&current->thread.per_info,sizeof(per_struct));
421 }
422
423 /*
424  * These bracket the sleeping functions..
425  */
426 extern void scheduling_functions_start_here(void);
427 extern void scheduling_functions_end_here(void);
428 #define first_sched     ((unsigned long) scheduling_functions_start_here)
429 #define last_sched      ((unsigned long) scheduling_functions_end_here)
430
431 unsigned long get_wchan(struct task_struct *p)
432 {
433         unsigned long r14, r15, bc;
434         unsigned long stack_page;
435         int count = 0;
436         if (!p || p == current || p->state == TASK_RUNNING)
437                 return 0;
438         stack_page = (unsigned long) p;
439         r15 = p->thread.ksp;
440         if (!stack_page || r15 < stack_page || r15 >= 16380+stack_page)
441                 return 0;
442         bc = *(unsigned long *) r15;
443         do {
444                 if (bc < stack_page || bc >= 16380+stack_page)
445                         return 0;
446                 r14 = *(unsigned long *) (bc+112);
447                 if (r14 < first_sched || r14 >= last_sched)
448                         return r14;
449                 bc = *(unsigned long *) bc;
450         } while (count++ < 16);
451         return 0;
452 }
453 #undef last_sched
454 #undef first_sched
455