2 * arch/s390/kernel/process.c
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),
10 * Derived from "arch/i386/kernel/process.c"
11 * Copyright (C) 1995, Linus Torvalds
15 * This file handles the architecture-dependent parts of process handling..
18 #define __KERNEL_SYSCALLS__
21 #include <linux/config.h>
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/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>
40 #include <asm/uaccess.h>
41 #include <asm/pgtable.h>
42 #include <asm/system.h>
44 #include <asm/processor.h>
47 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
50 * The idle loop on a S390...
53 int cpu_idle(void *unused)
58 /* endless idle loop with no priority at all */
61 current->counter = -100;
63 if (current->need_resched) {
70 * Wait for external, I/O or machine check interrupt and
71 * switch of machine check bit after the wait has ended.
73 wait_psw.mask = _WAIT_PSW_MASK;
76 "0: la %0,1f-0b(%0)\n"
80 "1: la %0,2f-1b(%0)\n"
86 : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
90 extern void show_registers(struct pt_regs *regs);
91 extern void show_trace(unsigned long *sp);
93 void show_regs(struct pt_regs *regs)
95 struct task_struct *tsk = current;
97 printk("CPU: %d %s\n", tsk->processor, print_tainted());
98 printk("Process %s (pid: %d, task: %08lx, ksp: %08x)\n",
99 current->comm, current->pid, (unsigned long) tsk,
102 show_registers(regs);
103 /* Show stack backtrace if pt_regs is from kernel mode */
104 if (!(regs->psw.mask & PSW_PROBLEM_STATE))
105 show_trace((unsigned long *) regs->gprs[15]);
108 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
110 int clone_arg = flags | CLONE_VM;
113 __asm__ __volatile__(
116 " l 4,%6\n" /* load kernel stack ptr of parent */
117 " svc %b2\n" /* Linux system call*/
118 " cl 4,%6\n" /* compare ksp's: child or parent ? */
119 " je 0f\n" /* parent - jump*/
120 " l 15,%6\n" /* fix kernel stack pointer*/
122 " xc 0(96,15),0(15)\n" /* clear save area */
123 " lr 2,%4\n" /* load argument*/
124 " lr 14,%5\n" /* get fn-pointer*/
125 " basr 14,14\n" /* call fn*/
126 " svc %b3\n" /* Linux system call*/
129 : "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
130 "d" (arg), "d" (fn), "i" (__LC_KERNEL_STACK) , "i" (-STACK_FRAME_OVERHEAD)
136 * Free current thread data structures etc..
138 void exit_thread(void)
142 void flush_thread(void)
145 current->used_math = 0;
146 current->flags &= ~PF_USEDFPU;
149 void release_thread(struct task_struct *dead_task)
153 int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
154 unsigned long unused,
155 struct task_struct * p, struct pt_regs * regs)
159 unsigned long back_chain;
163 unsigned long scratch[2];
164 unsigned long gprs[10]; /* gprs 6 -15 */
165 unsigned long fprs[4]; /* fpr 4 and 6 */
166 unsigned long empty[4];
167 struct pt_regs childregs;
170 frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
171 p->thread.ksp = (unsigned long) frame;
172 memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
173 frame->childregs.gprs[15] = new_stackp;
174 frame->back_chain = frame->eos = 0;
176 /* new return point is ret_from_sys_call */
177 frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
179 /* fake return stack for resume(), don't go back to schedule */
180 frame->gprs[9] = (unsigned long) frame;
181 /* save fprs, if used in last task */
182 save_fp_regs(&p->thread.fp_regs);
183 p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
184 /* Don't copy debug registers */
185 memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
189 asmlinkage int sys_fork(struct pt_regs regs)
191 return do_fork(SIGCHLD, regs.gprs[15], ®s, 0);
194 asmlinkage int sys_clone(struct pt_regs regs)
196 unsigned long clone_flags;
199 clone_flags = regs.gprs[3];
200 newsp = regs.orig_gpr2;
202 newsp = regs.gprs[15];
203 return do_fork(clone_flags, newsp, ®s, 0);
207 * This is trivial, and on the face of it looks like it
208 * could equally well be done in user mode.
210 * Not so, for quite unobvious reasons - register pressure.
211 * In user mode vfork() cannot have a stack frame, and if
212 * done by calling the "clone()" system call directly, you
213 * do not have enough call-clobbered registers to hold all
214 * the information you need.
216 asmlinkage int sys_vfork(struct pt_regs regs)
218 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
219 regs.gprs[15], ®s, 0);
223 * sys_execve() executes a new program.
225 asmlinkage int sys_execve(struct pt_regs regs)
230 filename = getname((char *) regs.orig_gpr2);
231 error = PTR_ERR(filename);
232 if (IS_ERR(filename))
234 error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], ®s);
237 current->ptrace &= ~PT_DTRACE;
238 current->thread.fp_regs.fpc=0;
256 * fill in the FPU structure for a core dump.
258 int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
260 save_fp_regs(fpregs);
265 * fill in the user structure for a core dump..
267 void dump_thread(struct pt_regs * regs, struct user * dump)
270 /* changed the size calculations - should hopefully work better. lbt */
271 dump->magic = CMAGIC;
272 dump->start_code = 0;
273 dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
274 dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
275 dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
276 dump->u_dsize -= dump->u_tsize;
278 if (dump->start_stack < TASK_SIZE)
279 dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
280 memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
281 dump_fpu (regs, &dump->regs.fp_regs);
282 memcpy(&dump->regs.per_info,¤t->thread.per_info,sizeof(per_struct));
286 * These bracket the sleeping functions..
288 extern void scheduling_functions_start_here(void);
289 extern void scheduling_functions_end_here(void);
290 #define first_sched ((unsigned long) scheduling_functions_start_here)
291 #define last_sched ((unsigned long) scheduling_functions_end_here)
293 unsigned long get_wchan(struct task_struct *p)
295 unsigned long r14, r15, bc;
296 unsigned long stack_page;
298 if (!p || p == current || p->state == TASK_RUNNING)
300 stack_page = (unsigned long) p;
302 if (!stack_page || r15 < stack_page || r15 >= 8188+stack_page)
304 bc = (*(unsigned long *) r15) & 0x7fffffff;
306 if (bc < stack_page || bc >= 8188+stack_page)
308 r14 = (*(unsigned long *) (bc+56)) & 0x7fffffff;
309 if (r14 < first_sched || r14 >= last_sched)
311 bc = (*(unsigned long *) bc) & 0x7fffffff;
312 } while (count++ < 16);